[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#274167: kernel-image-2.6.8-1-686: reiserfs bug on a firewire harddisk, possible patch found



On Tue, Nov 02, 2004 at 12:42:19PM +0100, Stefan Armbruster wrote:
> Package: kernel-image-2.6.8-1-686
> Version: 2.6.8-4
> Followup-For: Bug #274167
> 
> 
> 
> -- System Information:
> Debian Release: 3.1
>   APT prefers testing
>   APT policy: (500, 'testing')
> Architecture: i386 (i686)
> Kernel: Linux 2.6.8-1-686
> Locale: LANG=de_DE@euro, LC_CTYPE=de_DE@euro
> 
> Versions of packages kernel-image-2.6.8-1-686 depends on:
> ii  coreutils [fileutils]         5.2.1-2    The GNU core utilities
> ii  initrd-tools                  0.1.74     tools to create initrd image for p
> ii  module-init-tools             3.1-pre6-1 tools for managing Linux kernel mo
> 
> -- no debconf information
> 
> I encountered a bug that might be related to #274167. See the following
> snippet of /var/log/kern.log. The bug occured after the following steps:
> * Plugged a 160GB firewire harddisk
> * Mount the first partition of the hd (/dev/sda1, 120G)
> * tried write a large amount of date (~60G) to the firewire hd
> * after the snippet was writted, all processes accessing the hd are
> blocked and cannot be interrupted. Even regular system shutdown did not
> work. I switched off the computer.
> 
> The interesting line of the snippet is 
> 	kernel BUG at fs/reiserfs/prints.c:362!
> 
> Googling for this leads me to a potential patch, see
> http://www.mail-archive.com/reiserfs-list@namesys.com/msg16068.html
> 
> Since I'm no kernel hacker at all I can't say anything regarding the
> patch.

Hi Stefan,

Thanks for this bug report. I had a quick look over your logs
(which I have snipped from my reply for the sake of brevity)
and the patch at the URL above. To be honest I am not
convinced you are seeing the same problem. The bug above
refers to files and filesystems about an order of magnitute
larget than what you have. 

I also note that there are a lot of ieee1394 warnings and
errors in your logs preceeding the reiserfs panic. Which
suggests to me that there may be some problem reading the
drive. This may be hardware or software (kernel) related,
I am not sure. However, I do notice the attached patch to
reiser which prevents it from panicing when it
sees I/O errors. If this is your problem then it isn't going
to help you much in terms of accessing the disk, however it
should stop your system from locking up.

The patch is from the 2.6 bitkeeper tree, and was applied
post 2.6.9. It should apply cleanly to 2.6.9, and possibley 2.6.8,
though I haven't verified either.

If you could test it out that would be most useful. However,
I should throw in a word of caution. Obviously if your filesystem
malfunctions, then your data may not be safe. Please back up
any data before trying patches to the file system code.
Granted that may not be possible, but just so you know.

-- 
Horms
#ChangeSet1.1988.74.100
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/10/18 23:07:45-07:00 jeffm@novell.com 
#   [PATCH] ReiserFS: Add I/O error handling to journal operations
#   
#   This patch allows ReiserFS to handle I/O errors in the journal (or journal
#   flush) where it would have previously panicked.  The new behavior is to
#   mark the filesystem read-only, disallow new transactions to be started, and
#   to allow existing transactions to complete (though not to commit).  The
#   resultant filesystem can be safely umounted, and checked via normal
#   mechanisms.  As it is a journaling filesystem, the filesystem itself will
#   be in a similar state to the power being cut to the machine, once umounted.
#   
#   Signed-off-by: Jeff Mahoney <jeffm@novell.com>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
# 
# fs/reiserfs/bitmap.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +13 -0
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/dir.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +5 -2
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/file.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +103 -24
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/inode.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +149 -47
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/journal.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +260 -95
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/namei.c
#   2004/10/18 22:28:07-07:00 jeffm@novell.com +108 -47
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/objectid.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +2 -0
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/prints.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +43 -0
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/resize.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +18 -8
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/stree.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +46 -11
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/super.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +99 -37
#   ReiserFS: Add I/O error handling to journal operations
# 
# fs/reiserfs/tail_conversion.c
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +3 -0
#   ReiserFS: Add I/O error handling to journal operations
# 
# include/linux/reiserfs_fs.h
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +9 -6
#   ReiserFS: Add I/O error handling to journal operations
# 
# include/linux/reiserfs_fs_sb.h
#   2004/10/18 22:26:49-07:00 jeffm@novell.com +26 -0
#   ReiserFS: Add I/O error handling to journal operations
# 
diff -Nru a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
--- a/fs/reiserfs/bitmap.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/bitmap.c	2004-11-03 18:29:31 -08:00
@@ -137,6 +137,8 @@
     int end, next;
     int org = *beg;
 
+    BUG_ON (!th->t_trans_id);
+
     RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)",bmap_n, SB_BMAP_NR (s) - 1);
     PROC_INFO_INC( s, scan_bitmap.bmap );
 /* this is unclear and lacks comments, explain how journal bitmaps
@@ -290,6 +292,8 @@
     int end_bm, end_off;
     int off_max = s->s_blocksize << 3;
 
+    BUG_ON (!th->t_trans_id);
+
     PROC_INFO_INC( s, scan_bitmap.call ); 
     if ( SB_FREE_BLOCKS(s) <= 0)
 	return 0; // No point in looking for more free blocks
@@ -348,6 +352,8 @@
     struct reiserfs_bitmap_info *apbi;
     int nr, offset;
 
+    BUG_ON (!th->t_trans_id);
+
     PROC_INFO_INC( s, free_block );
 
     rs = SB_DISK_SUPER_BLOCK (s);
@@ -389,6 +395,8 @@
 {
     struct super_block * s = th->t_super;
 
+    BUG_ON (!th->t_trans_id);
+
     RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
     RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
     /* mark it before we clear it, just in case */
@@ -401,6 +409,7 @@
 			  struct inode *inode, b_blocknr_t block) {
     RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
     RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
+    BUG_ON (!th->t_trans_id);
     _reiserfs_free_block(th, inode, block, 1) ;
 }
 
@@ -410,6 +419,7 @@
     unsigned long save = ei->i_prealloc_block ;
     int dirty = 0;
     struct inode *inode = &ei->vfs_inode;
+    BUG_ON (!th->t_trans_id);
 #ifdef CONFIG_REISERFS_CHECK
     if (ei->i_prealloc_count < 0)
 	reiserfs_warning (th->t_super, "zam-4001:%s: inode has negative prealloc blocks count.", __FUNCTION__ );
@@ -431,6 +441,7 @@
 				struct inode *inode)
 {
     struct reiserfs_inode_info *ei = REISERFS_I(inode);
+    BUG_ON (!th->t_trans_id);
     if (ei->i_prealloc_count)
 	__discard_prealloc(th, ei);
 }
@@ -438,6 +449,8 @@
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
 {
     struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
+
+    BUG_ON (!th->t_trans_id);
 
     while (!list_empty(plist)) {
 	struct reiserfs_inode_info *ei;
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/dir.c	2004-11-03 18:29:31 -08:00
@@ -26,10 +26,13 @@
 
 int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
   struct inode *inode = dentry->d_inode;
+  int err;
   reiserfs_write_lock(inode->i_sb);
-  reiserfs_commit_for_inode(inode) ;
+  err = reiserfs_commit_for_inode(inode) ;
   reiserfs_write_unlock(inode->i_sb) ;
-  return 0 ;
+  if (err < 0)
+      return err;
+  return 0;
 }
 
 
diff -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c
--- a/fs/reiserfs/file.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/file.c	2004-11-03 18:29:31 -08:00
@@ -35,6 +35,8 @@
 {
 
     struct reiserfs_transaction_handle th ;
+    int err;
+    int jbegin_failure = 0;
 
     if (!S_ISREG (inode->i_mode))
 	BUG ();
@@ -49,26 +51,58 @@
     
     reiserfs_write_lock(inode->i_sb);
     down (&inode->i_sem); 
-    journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
+    /* freeing preallocation only involves relogging blocks that
+     * are already in the current transaction.  preallocation gets
+     * freed at the end of each transaction, so it is impossible for
+     * us to log any additional blocks
+     */
+    err = journal_begin(&th, inode->i_sb, 1);
+    if (err) {
+	/* uh oh, we can't allow the inode to go away while there
+	 * is still preallocation blocks pending.  Try to join the
+	 * aborted transaction
+	 */
+	jbegin_failure = err;
+	err = journal_join_abort(&th, inode->i_sb, 1);
+
+	if (err) {
+	    /* hmpf, our choices here aren't good.  We can pin the inode
+	     * which will disallow unmount from every happening, we can
+	     * do nothing, which will corrupt random memory on unmount,
+	     * or we can forcibly remove the file from the preallocation
+	     * list, which will leak blocks on disk.  Lets pin the inode
+	     * and let the admin know what is going on.
+	     */
+	    igrab(inode);
+	    reiserfs_warning(inode->i_sb, "pinning inode %lu because the "
+	                     "preallocation can't be freed");
+	    goto out;
+	}
+    }
     reiserfs_update_inode_transaction(inode) ;
 
 #ifdef REISERFS_PREALLOCATE
     reiserfs_discard_prealloc (&th, inode);
 #endif
-    journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
+    err = journal_end(&th, inode->i_sb, 1);
 
-    if (atomic_read(&inode->i_count) <= 1 &&
+    /* copy back the error code from journal_begin */
+    if (!err)
+        err = jbegin_failure;
+
+    if (!err && atomic_read(&inode->i_count) <= 1 &&
 	(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) &&
         tail_has_to_be_packed (inode)) {
 	/* if regular file is released by last holder and it has been
 	   appended (we append by unformatted node only) or its direct
 	   item(s) had to be converted, then it may have to be
 	   indirect2direct converted */
-	reiserfs_truncate_file(inode, 0) ;
+	err = reiserfs_truncate_file(inode, 0) ;
     }
+out:
     up (&inode->i_sem); 
     reiserfs_write_unlock(inode->i_sb);
-    return 0;
+    return err;
 }
 
 static void reiserfs_vfs_truncate_file(struct inode *inode) {
@@ -99,6 +133,8 @@
   reiserfs_write_unlock(p_s_inode->i_sb);
   if (barrier_done != 1)
       blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
+  if (barrier_done < 0)
+    return barrier_done;
   return ( n_err < 0 ) ? -EIO : 0;
 }
 
@@ -146,7 +182,6 @@
 				 // of the fact that we already prepared
 				 // current block for journal
     int will_prealloc = 0;
-
     RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?");
 
     /* only preallocate if this is a small write */
@@ -166,7 +201,9 @@
     /* If we came here, it means we absolutely need to open a transaction,
        since we need to allocate some blocks */
     reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
-    journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough
+    res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough
+    if (res)
+        goto error_exit;
     reiserfs_update_inode_transaction(inode) ;
 
     /* Look for the in-tree position of our write, need path for block allocator */
@@ -194,7 +231,9 @@
 	    /* We flush the transaction in case of no space. This way some
 	       blocks might become free */
 	    SB_JOURNAL(inode->i_sb)->j_must_wait = 1;
-	    restart_transaction(th, inode, &path);
+	    res = restart_transaction(th, inode, &path);
+            if (res)
+                goto error_exit;
 
 	    /* We might have scheduled, so search again */
 	    res = search_for_position_by_key(inode->i_sb, &key, &path);
@@ -322,8 +361,14 @@
 		}
 		/* Now we want to check if transaction is too full, and if it is
 		   we restart it. This will also free the path. */
-		if (journal_transaction_should_end(th, th->t_blocks_allocated))
-		    restart_transaction(th, inode, &path);
+		if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
+		    res = restart_transaction(th, inode, &path);
+                    if (res) {
+                        pathrelse (&path);
+                        kfree(zeros);
+                        goto error_exit;
+                    }
+                }
 
 		/* Well, need to recalculate path and stuff */
 		set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + (to_paste << inode->i_blkbits));
@@ -349,6 +394,7 @@
     // we are going to overwrite, so there is nothing to scan through for holes.
     for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
 retry:
+
 	if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
 	    /* We run out of data in this indirect item, let's look for another
 	       one. */
@@ -526,8 +572,14 @@
 	reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), 1);
 
 error_exit:
-    reiserfs_update_sd(th, inode); // update any changes we made to blk count
-    journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
+    if (th->t_trans_id) {
+        int err;
+        // update any changes we made to blk count
+        reiserfs_update_sd(th, inode);
+        err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
+        if (err)
+            res = err;
+    }
     reiserfs_write_unlock(inode->i_sb);
     kfree(allocated_blocks);
 
@@ -602,13 +654,16 @@
     struct super_block *s = inode->i_sb;
     int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
     struct reiserfs_transaction_handle th;
-    th.t_trans_id = 0;
+    int ret = 0;
 
+    th.t_trans_id = 0;
     blocksize = 1 << inode->i_blkbits;
 
     if (logit) {
 	reiserfs_write_lock(s);
-	journal_begin(&th, s, bh_per_page + 1);
+	ret = journal_begin(&th, s, bh_per_page + 1);
+	if (ret)
+	    goto drop_write_lock;
 	reiserfs_update_inode_transaction(inode);
     }
     for(bh = head = page_buffers(page), block_start = 0;
@@ -640,7 +695,8 @@
 	}
     }
     if (logit) {
-	journal_end(&th, s, bh_per_page + 1);
+	ret = journal_end(&th, s, bh_per_page + 1);
+drop_write_lock:
 	reiserfs_write_unlock(s);
     }
     /*
@@ -651,7 +707,7 @@
      */
     if (!partial)
 	SetPageUptodate(page);
-    return 0;
+    return ret;
 }
 
 
@@ -717,7 +773,9 @@
 	reiserfs_write_lock(inode->i_sb);
 	if (!sd_update)
 	    reiserfs_update_sd(th, inode);
-	journal_end(th, th->t_super, th->t_blocks_allocated);
+	status = journal_end(th, th->t_super, th->t_blocks_allocated);
+        if (status)
+            retval = status;
 	reiserfs_write_unlock(inode->i_sb);
     }
     th->t_trans_id = 0;
@@ -1100,6 +1158,7 @@
     size_t already_written = 0; // Number of bytes already written to the file.
     loff_t pos; // Current position in the file.
     ssize_t res; // return value of various functions that we call.
+    int err = 0;
     struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
 				/* To simplify coding at this time, we store
 				   locked pages in array for now */
@@ -1114,24 +1173,40 @@
 	       If we will crash while doing direct io, finish_unfinished will
 	       cut the garbage from the file end. */
 	    reiserfs_write_lock(inode->i_sb);
-	    journal_begin(&th, inode->i_sb,  JOURNAL_PER_BALANCE_CNT );
+	    err = journal_begin(&th, inode->i_sb,  JOURNAL_PER_BALANCE_CNT );
+            if (err) {
+		reiserfs_write_unlock (inode->i_sb);
+		return err;
+	    }
 	    reiserfs_update_inode_transaction(inode);
 	    add_save_link (&th, inode, 1 /* Truncate */);
-	    journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
-	    reiserfs_write_unlock(inode->i_sb);
 	    after_file_end = 1;
+	    err = journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
+            reiserfs_write_unlock(inode->i_sb);
+	    if (err)
+		return err;
 	}
 	result = generic_file_write(file, buf, count, ppos);
 
 	if ( after_file_end ) { /* Now update i_size and remove the savelink */
 	    struct reiserfs_transaction_handle th;
 	    reiserfs_write_lock(inode->i_sb);
-	    journal_begin(&th, inode->i_sb, 1);
+	    err = journal_begin(&th, inode->i_sb, 1);
+            if (err) {
+                reiserfs_write_unlock (inode->i_sb);
+                return err;
+            }
 	    reiserfs_update_inode_transaction(inode);
 	    reiserfs_update_sd(&th, inode);
-	    journal_end(&th, inode->i_sb, 1);
-	    remove_save_link (inode, 1/* truncate */);
+	    err = journal_end(&th, inode->i_sb, 1);
+            if (err) {
+                reiserfs_write_unlock (inode->i_sb);
+                return err;
+            }
+	    err = remove_save_link (inode, 1/* truncate */);
 	    reiserfs_write_unlock(inode->i_sb);
+            if (err)
+                return err;
 	}
 
 	return result;
@@ -1280,8 +1355,12 @@
     /* this is only true on error */
     if (th.t_trans_id) {
         reiserfs_write_lock(inode->i_sb);
-	journal_end(&th, th.t_super, th.t_blocks_allocated);
+        err = journal_end(&th, th.t_super, th.t_blocks_allocated);
         reiserfs_write_unlock(inode->i_sb);
+        if (err) {
+            res = err;
+            goto out;
+        }
     }
 
     if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/inode.c	2004-11-03 18:29:31 -08:00
@@ -47,21 +47,32 @@
 
 	reiserfs_delete_xattrs (inode);
 
-	journal_begin(&th, inode->i_sb, jbegin_count) ;
+	if (journal_begin(&th, inode->i_sb, jbegin_count)) {
+	    up (&inode->i_sem);
+	    goto out;
+	}
 	reiserfs_update_inode_transaction(inode) ;
 
-	reiserfs_delete_object (&th, inode);
+	if (reiserfs_delete_object (&th, inode)) {
+	    up (&inode->i_sem);
+	    goto out;
+	}
 
-	journal_end(&th, inode->i_sb, jbegin_count) ;
+	if (journal_end(&th, inode->i_sb, jbegin_count)) {
+	    up (&inode->i_sem);
+	    goto out;
+	}
 
         up (&inode->i_sem);
 
         /* all items of file are deleted, so we can remove "save" link */
-	remove_save_link (inode, 0/* not truncate */);
+	remove_save_link (inode, 0/* not truncate */); /* we can't do anything
+                                                        * about an error here */
     } else {
 	/* no object items are in the tree */
 	;
     }
+out:
     clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */
     inode->i_blocks = 0;
     reiserfs_write_unlock(inode->i_sb);
@@ -201,20 +212,28 @@
     return 0;
 }
 
-/*static*/ void restart_transaction(struct reiserfs_transaction_handle *th,
+/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th,
 				struct inode *inode, struct path *path) {
   struct super_block *s = th->t_super ;
   int len = th->t_blocks_allocated ;
+  int err;
+
+  BUG_ON (!th->t_trans_id);
+  BUG_ON (!th->t_refcount);
 
   /* we cannot restart while nested */
   if (th->t_refcount > 1) {
-      return  ;
+      return 0  ;
   }
   pathrelse(path) ;
   reiserfs_update_sd(th, inode) ;
-  journal_end(th, s, len) ;
-  journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
-  reiserfs_update_inode_transaction(inode) ;
+  err = journal_end(th, s, len) ;
+  if (!err) {
+      err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
+      if (!err)
+        reiserfs_update_inode_transaction(inode) ;
+  }
+  return err;
 }
 
 // it is called by get_block when create == 0. Returns block number
@@ -443,9 +462,11 @@
 
     ret = reiserfs_get_block(inode, iblock, bh_result,
                              create | GET_BLOCK_NO_DANGLE) ;
+    if (ret)
+        goto out;
 
     /* don't allow direct io onto tail pages */
-    if (ret == 0 && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
+    if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
         /* make sure future calls to the direct io funcs for this offset
         ** in the file fail by unmapping the buffer
         */
@@ -455,11 +476,15 @@
     /* Possible unpacked tail. Flush the data before pages have
        disappeared */
     if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
+        int err;
         lock_kernel();
-        reiserfs_commit_for_inode(inode);
+        err = reiserfs_commit_for_inode(inode);
         REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
         unlock_kernel();
+        if (err < 0)
+            ret = err;
     }
+out:
     return ret ;
 }
 
@@ -539,6 +564,7 @@
 			   b_blocknr_t *allocated_block_nr, 
 			   struct path * path,
 			   int flags) {
+    BUG_ON (!th->t_trans_id);
   
 #ifdef REISERFS_PREALLOCATE
     if (!(flags & GET_BLOCK_NO_ISEM)) {
@@ -551,7 +577,7 @@
 int reiserfs_get_block (struct inode * inode, sector_t block,
 			struct buffer_head * bh_result, int create)
 {
-    int repeat, retval;
+    int repeat, retval = 0;
     b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is (unsigned) 32 bit int
     INITIALIZE_PATH(path);
     int pos_in_item;
@@ -655,7 +681,9 @@
 	    ** research if we succeed on the second try
 	    */
 	    SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1;
-	    restart_transaction(th, inode, &path) ;
+	    retval = restart_transaction(th, inode, &path) ;
+            if (retval)
+                goto failure;
 	    repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
 
 	    if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
@@ -696,8 +724,9 @@
 	}
 	set_block_dev_mapped(bh_result, unfm_ptr, inode);
 	pathrelse (&path);
+        retval = 0;
 	if (!dangle && th)
-	    reiserfs_end_persistent_transaction(th);
+	    retval = reiserfs_end_persistent_transaction(th);
 
 	reiserfs_write_unlock(inode->i_sb);
 	 
@@ -705,7 +734,7 @@
 	** there is no need to make sure the inode is updated with this 
 	** transaction
 	*/
-	return 0;
+	return retval;
     }
 
     if (!th) {
@@ -766,9 +795,12 @@
 		 * ugly, but we can only end the transaction if
 		 * we aren't nested
 		 */
+		BUG_ON (!th->t_refcount);
 		if (th->t_refcount == 1) {
-		    reiserfs_end_persistent_transaction(th);
+		    retval = reiserfs_end_persistent_transaction(th);
 		    th = NULL;
+		    if (retval)
+			goto failure;
 		}
 
 		retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
@@ -898,7 +930,9 @@
 	** ending their transaction will be able to continue.
 	*/
 	if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
-	  restart_transaction(th, inode, &path) ;
+	  retval = restart_transaction(th, inode, &path) ;
+	  if (retval)
+	    goto failure;
 	}
 	/* inserting indirect pointers for a hole can take a 
 	** long time.  reschedule if needed
@@ -929,10 +963,15 @@
     retval = 0;
 
  failure:
-    if (th && !dangle) {
-      reiserfs_update_sd(th, inode) ;
-      reiserfs_end_persistent_transaction(th);
+    if (th && (!dangle || (retval && !th->t_trans_id))) {
+        int err;
+        if (th->t_trans_id)
+            reiserfs_update_sd(th, inode);
+        err = reiserfs_end_persistent_transaction(th);
+        if (err)
+            retval = err;
     }
+
     reiserfs_write_unlock(inode->i_sb);
     reiserfs_check_path(&path) ;
     return retval;
@@ -1215,6 +1254,8 @@
     struct item_head *ih, tmp_ih ;
     int retval;
 
+    BUG_ON (!th->t_trans_id);
+
     make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant
     
     for(;;) {
@@ -1508,12 +1549,8 @@
     struct reiserfs_transaction_handle th ;
     int jbegin_count = 1 ;
 
-    if (inode->i_sb->s_flags & MS_RDONLY) {
-        reiserfs_warning (inode->i_sb,
-			  "clm-6005: writing inode %lu on readonly FS",
-			  inode->i_ino) ;
+    if (inode->i_sb->s_flags & MS_RDONLY)
         return -EROFS;
-    }
     /* memory pressure can sometimes initiate write_inode calls with sync == 1,
     ** these cases are just when the system needs ram, not when the 
     ** inode needs to reach disk for safety, and they can safely be
@@ -1521,9 +1558,10 @@
     */
     if (do_sync && !(current->flags & PF_MEMALLOC)) {
 	reiserfs_write_lock(inode->i_sb);
-	journal_begin(&th, inode->i_sb, jbegin_count) ;
-	reiserfs_update_sd (&th, inode);
-	journal_end_sync(&th, inode->i_sb, jbegin_count) ;
+	if (!journal_begin(&th, inode->i_sb, jbegin_count)) {
+            reiserfs_update_sd (&th, inode);
+            journal_end_sync(&th, inode->i_sb, jbegin_count) ;
+        }
 	reiserfs_write_unlock(inode->i_sb);
     }
     return 0;
@@ -1551,6 +1589,8 @@
     char * body = empty_dir;
     struct cpu_key key;
     int retval;
+
+    BUG_ON (!th->t_trans_id);
     
     _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id),
 		   le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/);
@@ -1602,6 +1642,8 @@
     struct cpu_key key;
     int retval;
 
+    BUG_ON (!th->t_trans_id);
+
     _make_cpu_key (&key, KEY_FORMAT_3_5, 
 		   le32_to_cpu (ih->ih_key.k_dir_id), 
 		   le32_to_cpu (ih->ih_key.k_objectid),
@@ -1652,6 +1694,8 @@
     struct stat_data sd;
     int retval;
     int err;
+
+    BUG_ON (!th->t_trans_id);
   
     if (!dir || !dir->i_nlink) {
 	err = -EPERM;
@@ -1926,7 +1970,7 @@
 **
 ** some code taken from block_truncate_page
 */
-void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
+int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
     struct reiserfs_transaction_handle th ;
     /* we want the offset for the first byte after the end of the file */
     unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ;
@@ -1962,18 +2006,28 @@
     /* it is enough to reserve space in transaction for 2 balancings:
        one for "save" link adding and another for the first
        cut_from_item. 1 is for update_sd */
-    journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+    error = journal_begin (&th, p_s_inode->i_sb,
+                           JOURNAL_PER_BALANCE_CNT * 2 + 1);
+    if (error)
+        goto out;
     reiserfs_update_inode_transaction(p_s_inode) ;
     if (update_timestamps)
 	    /* we are doing real truncate: if the system crashes before the last
 	       transaction of truncating gets committed - on reboot the file
 	       either appears truncated properly or not truncated at all */
 	add_save_link (&th, p_s_inode, 1);
-    reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
-    journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+    error = reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
+    if (error)
+        goto out;
+    error = journal_end (&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
+    if (error)
+        goto out;
 
-    if (update_timestamps)
-	remove_save_link (p_s_inode, 1/* truncate */);
+    if (update_timestamps) {
+	error = remove_save_link (p_s_inode, 1/* truncate */);
+        if (error)
+            goto out;
+    }
 
     if (page) {
         length = offset & (blocksize - 1) ;
@@ -1995,6 +2049,14 @@
     }
 
     reiserfs_write_unlock(p_s_inode->i_sb);
+    return 0;
+out:
+    if (page) {
+        unlock_page (page);
+        page_cache_release (page);
+    }
+    reiserfs_write_unlock(p_s_inode->i_sb);
+    return error;
 }
 
 static int map_block_for_writepage(struct inode *inode, 
@@ -2064,7 +2126,9 @@
 
 	if (!trans_running) {
 	    /* vs-3050 is gone, no need to drop the path */
-	    journal_begin(&th, inode->i_sb, jbegin_count) ;
+	    retval = journal_begin(&th, inode->i_sb, jbegin_count) ;
+            if (retval)
+                goto out;
 	    reiserfs_update_inode_transaction(inode) ;
 	    trans_running = 1;
 	    if (fs_changed(fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) {
@@ -2104,7 +2168,9 @@
 out:
     pathrelse(&path) ;
     if (trans_running) {
-	journal_end(&th, inode->i_sb, jbegin_count) ;
+        int err = journal_end(&th, inode->i_sb, jbegin_count) ;
+        if (err)
+            retval = err;
 	trans_running = 0;
     }
     reiserfs_write_unlock(inode->i_sb);
@@ -2210,7 +2276,11 @@
     if (checked) {
 	ClearPageChecked(page);
 	reiserfs_write_lock(s);
-	journal_begin(&th, s, bh_per_page + 1);
+	error = journal_begin(&th, s, bh_per_page + 1);
+	if (error) {
+	    reiserfs_write_unlock(s);
+	    goto fail;
+	}
 	reiserfs_update_inode_transaction(inode);
     }
     /* now go through and lock any dirty buffers on the page */
@@ -2245,8 +2315,10 @@
     } while((bh = bh->b_this_page) != head);
 
     if (checked) {
-	journal_end(&th, s, bh_per_page + 1);
+	error = journal_end(&th, s, bh_per_page + 1);
 	reiserfs_write_unlock(s);
+	if (error)
+	    goto fail;
     }
     BUG_ON(PageWriteback(page));
     set_page_writeback(page);
@@ -2352,7 +2424,9 @@
     fix_tail_page_for_writing(page) ;
     if (reiserfs_transaction_running(inode->i_sb)) {
 	struct reiserfs_transaction_handle *th;
-        th = (struct reiserfs_transaction_handle *)current->journal_info;
+	th = (struct reiserfs_transaction_handle *)current->journal_info;
+        BUG_ON (!th->t_refcount);
+        BUG_ON (!th->t_trans_id);
 	old_ref = th->t_refcount;
 	th->t_refcount++;
     }
@@ -2374,9 +2448,12 @@
 	    if (old_ref)
 	    	th->t_refcount--;
 	    else {
+                int err;
 		reiserfs_write_lock(inode->i_sb);
-		reiserfs_end_persistent_transaction(th);
+		err = reiserfs_end_persistent_transaction(th);
 		reiserfs_write_unlock(inode->i_sb);
+                if (err)
+                    ret = err;
 	    }
 	}
     }
@@ -2417,20 +2494,28 @@
 	     (have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) )
 	    REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ;
 
-	journal_begin(&myth, inode->i_sb, 1) ;
+	ret = journal_begin(&myth, inode->i_sb, 1) ;
+	if (ret) {
+	    reiserfs_write_unlock(inode->i_sb);
+	    goto journal_error;
+	}
 	reiserfs_update_inode_transaction(inode) ;
 	inode->i_size = pos ;
 	reiserfs_update_sd(&myth, inode) ;
 	update_sd = 1;
-	journal_end(&myth, inode->i_sb, 1) ;
+	ret = journal_end(&myth, inode->i_sb, 1) ;
 	reiserfs_write_unlock(inode->i_sb);
+	if (ret)
+	    goto journal_error;
     }
     if (th) {
 	reiserfs_write_lock(inode->i_sb);
 	if (!update_sd)
 	    reiserfs_update_sd(th, inode) ;
-        reiserfs_end_persistent_transaction(th);
+	ret = reiserfs_end_persistent_transaction(th);
 	reiserfs_write_unlock(inode->i_sb);
+	if (ret)
+	    goto out;
     }
  
     /* we test for O_SYNC here so we can commit the transaction
@@ -2438,10 +2523,22 @@
     */
     if (f && (f->f_flags & O_SYNC)) {
 	reiserfs_write_lock(inode->i_sb);
- 	reiserfs_commit_for_inode(inode) ;
+ 	ret = reiserfs_commit_for_inode(inode) ;
 	reiserfs_write_unlock(inode->i_sb);
     }
+out:
     return ret ;
+
+journal_error:
+    if (th) {
+	reiserfs_write_lock(inode->i_sb);
+	if (!update_sd)
+	    reiserfs_update_sd(th, inode) ;
+        ret = reiserfs_end_persistent_transaction(th);
+	reiserfs_write_unlock(inode->i_sb);
+    }
+
+    return ret;
 }
 
 void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
@@ -2667,11 +2764,16 @@
         if (attr->ia_size > inode->i_size) {
 	    error = generic_cont_expand(inode, attr->ia_size) ;
 	    if (REISERFS_I(inode)->i_prealloc_count > 0) {
+		int err;
 		struct reiserfs_transaction_handle th ;
 		/* we're changing at most 2 bitmaps, inode + super */
-		journal_begin(&th, inode->i_sb, 4) ;
-		reiserfs_discard_prealloc (&th, inode);
-		journal_end(&th, inode->i_sb, 4) ;
+		err = journal_begin(&th, inode->i_sb, 4) ;
+		if (!err) {
+		    reiserfs_discard_prealloc (&th, inode);
+		    err = journal_end(&th, inode->i_sb, 4) ;
+		}
+		if (err)
+		    error = err;
 	    }
 	    if (error)
 	        goto out;
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/journal.c	2004-11-03 18:29:31 -08:00
@@ -93,12 +93,6 @@
 #define COMMIT_NOW  2		/* end and commit this transaction */
 #define WAIT        4		/* wait for the log blocks to hit the disk*/
 
-/* state bits for the journal */
-#define WRITERS_BLOCKED 1      /* set when new writers not allowed */
-#define WRITERS_QUEUED 2       /* set when log is full due to too many
-				* writers
-				*/
-
 static int do_journal_end(struct reiserfs_transaction_handle *,struct super_block *,unsigned long nblocks,int flags) ;
 static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
 static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall)  ;
@@ -109,6 +103,18 @@
 static int dirty_one_transaction(struct super_block *s,
                                  struct reiserfs_journal_list *jl);
 static void flush_async_commits(void *p);
+static void queue_log_writer(struct super_block *s);
+
+/* values for join in do_journal_begin_r */
+enum {
+    JBEGIN_REG = 0, /* regular journal begin */
+    JBEGIN_JOIN = 1, /* join the running transaction if at all possible */
+    JBEGIN_ABORT = 2, /* called from cleanup code, ignores aborted flag */
+};
+
+static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
+                             struct super_block * p_s_sb,
+			     unsigned long nblocks,int join);
 
 static void init_journal_hash(struct super_block *p_s_sb) {
   struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
@@ -771,7 +777,7 @@
 {
     struct buffer_head *bh;
     struct reiserfs_jh *jh;
-    int ret = 0;
+    int ret = j->j_errno;
     struct buffer_chunk chunk;
     struct list_head tmp;
     INIT_LIST_HEAD(&tmp);
@@ -795,11 +801,11 @@
 	    cond_resched();
 	    spin_lock(lock);
 	    goto loop_next;
-	}
+        }
 	if (buffer_dirty(bh)) {
 	    list_del_init(&jh->list);
 	    list_add(&jh->list, &tmp);
-	    add_to_chunk(&chunk, bh, lock, write_ordered_chunk);
+            add_to_chunk(&chunk, bh, lock, write_ordered_chunk);
 	} else {
 	    reiserfs_free_jh(bh);
 	    unlock_buffer(bh);
@@ -824,8 +830,9 @@
 	    wait_on_buffer(bh);
 	    spin_lock(lock);
 	}
-	if (!buffer_uptodate(bh))
+	if (!buffer_uptodate(bh)) {
 	    ret = -EIO;
+        }
 	put_bh(bh);
 	cond_resched_lock(lock);
     }
@@ -917,6 +924,7 @@
   unsigned long trans_id = jl->j_trans_id;
   struct reiserfs_journal *journal = SB_JOURNAL (s);
   int barrier = 0;
+  int retval = 0;
 
   reiserfs_check_lock_depth(s, "flush_commit_list") ;
 
@@ -927,10 +935,8 @@
   /* before we can put our commit blocks on disk, we have to make sure everyone older than
   ** us is on disk too
   */
-  if (jl->j_len <= 0)
-    BUG();
-  if (trans_id == journal->j_trans_id)
-    BUG();
+  BUG_ON (jl->j_len <= 0);
+  BUG_ON (trans_id == journal->j_trans_id);
 
   get_journal_list(jl);
   if (flushall) {
@@ -946,8 +952,7 @@
     up(&jl->j_commit_lock);
     goto put_jl;
   }
-  if (jl->j_trans_id == 0)
-    BUG();
+  BUG_ON (jl->j_trans_id == 0);
 
   /* this commit is done, exit */
   if (atomic_read(&(jl->j_commit_left)) <= 0) {
@@ -964,8 +969,7 @@
                             journal, jl, &jl->j_bh_list);
       lock_kernel();
   }
-  if (!list_empty(&jl->j_bh_list))
-      BUG();
+  BUG_ON (!list_empty(&jl->j_bh_list));
   /*
    * for the description block and all the log blocks, submit any buffers
    * that haven't already reached the disk
@@ -975,7 +979,7 @@
     bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start+i) %
          SB_ONDISK_JOURNAL_SIZE(s);
     tbh = journal_find_get_block(s, bn) ;
-    if (buffer_dirty(tbh))
+    if (buffer_dirty(tbh)) /* redundant, ll_rw_block() checks */
 	ll_rw_block(WRITE, 1, &tbh) ;
     put_bh(tbh) ;
   }
@@ -1003,18 +1007,20 @@
     // since we're using ll_rw_blk above, it might have skipped over
     // a locked buffer.  Double check here
     //
-    if (buffer_dirty(tbh))
+    if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
       sync_dirty_buffer(tbh);
-    if (!buffer_uptodate(tbh)) {
-      reiserfs_panic(s, "journal-601, buffer write failed\n") ;
+    if (unlikely (!buffer_uptodate(tbh))) {
+#ifdef CONFIG_REISERFS_CHECK
+      reiserfs_warning(s, "journal-601, buffer write failed") ;
+#endif
+      retval = -EIO;
     }
     put_bh(tbh) ; /* once for journal_find_get_block */
     put_bh(tbh) ;    /* once due to original getblk in do_journal_end */
     atomic_dec(&(jl->j_commit_left)) ;
   }
 
-  if (atomic_read(&(jl->j_commit_left)) != 1)
-    BUG();
+  BUG_ON (atomic_read(&(jl->j_commit_left)) != 1);
 
   if (!barrier) {
       if (buffer_dirty(jl->j_commit_bh))
@@ -1025,8 +1031,15 @@
       wait_on_buffer(jl->j_commit_bh);
 
   check_barrier_completion(s, jl->j_commit_bh);
-  if (!buffer_uptodate(jl->j_commit_bh)) {
-    reiserfs_panic(s, "journal-615: buffer write failed\n") ;
+
+  /* If there was a write error in the journal - we can't commit this
+   * transaction - it will be invalid and, if successful, will just end
+   * up propogating the write error out to the filesystem. */
+  if (unlikely (!buffer_uptodate(jl->j_commit_bh))) {
+#ifdef CONFIG_REISERFS_CHECK
+    reiserfs_warning(s, "journal-615: buffer write failed") ;
+#endif
+    retval = -EIO;
   }
   bforget(jl->j_commit_bh) ;
   if (journal->j_last_commit_id != 0 &&
@@ -1040,8 +1053,11 @@
   /* now, every commit block is on the disk.  It is safe to allow blocks freed during this transaction to be reallocated */
   cleanup_freed_for_journal_list(s, jl) ;
 
+  retval = retval ? retval : journal->j_errno;
+
   /* mark the metadata dirty */
-  dirty_one_transaction(s, jl);
+  if (!retval)
+    dirty_one_transaction(s, jl);
   atomic_dec(&(jl->j_commit_left)) ;
 
   if (flushall) {
@@ -1050,7 +1066,10 @@
   up(&jl->j_commit_lock);
 put_jl:
   put_journal_list(s, jl);
-  return 0 ;
+
+  if (retval)
+    reiserfs_abort (s, retval, "Journal write error in %s", __FUNCTION__);
+  return retval;
 }
 
 /*
@@ -1113,11 +1132,18 @@
 static int _update_journal_header_block(struct super_block *p_s_sb, unsigned long offset, unsigned long trans_id) {
   struct reiserfs_journal_header *jh ;
   struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
+
+  if (reiserfs_is_journal_aborted (journal))
+    return -EIO;
+
   if (trans_id >= journal->j_last_flush_trans_id) {
     if (buffer_locked((journal->j_header_bh)))  {
       wait_on_buffer((journal->j_header_bh)) ;
-      if (!buffer_uptodate(journal->j_header_bh)) {
-        reiserfs_panic(p_s_sb, "journal-699: buffer write failed\n") ;
+      if (unlikely (!buffer_uptodate(journal->j_header_bh))) {
+#ifdef CONFIG_REISERFS_CHECK
+        reiserfs_warning (p_s_sb, "journal-699: buffer write failed") ;
+#endif
+        return -EIO;
       }
     }
     journal->j_last_flush_trans_id = trans_id ;
@@ -1154,10 +1180,7 @@
 static int update_journal_header_block(struct super_block *p_s_sb, 
                                        unsigned long offset, 
 				       unsigned long trans_id) {
-    if (_update_journal_header_block(p_s_sb, offset, trans_id)) {
-	reiserfs_panic(p_s_sb, "journal-712: buffer write failed\n") ;
-    }
-    return 0 ;
+    return _update_journal_header_block(p_s_sb, offset, trans_id);
 }
 /* 
 ** flush any and all journal lists older than you are 
@@ -1176,8 +1199,12 @@
      */
 restart:
     entry = journal->j_journal_list.next;
+    /* Did we wrap? */
+    if (entry == &journal->j_journal_list)
+        return 0;
     other_jl = JOURNAL_LIST_ENTRY(entry);
     if (other_jl->j_trans_id < trans_id) {
+        BUG_ON (other_jl->j_refcount <= 0);
 	/* do not flush all */
 	flush_journal_list(p_s_sb, other_jl, 0) ;
 
@@ -1215,17 +1242,15 @@
   struct buffer_head *saved_bh ; 
   unsigned long j_len_saved = jl->j_len ;
   struct reiserfs_journal *journal = SB_JOURNAL (s);
+  int err = 0;
 
-  if (j_len_saved <= 0) {
-    BUG();
-  }
+  BUG_ON (j_len_saved <= 0);
 
   if (atomic_read(&journal->j_wcount) != 0) {
     reiserfs_warning(s, "clm-2048: flush_journal_list called with wcount %d",
                       atomic_read(&journal->j_wcount)) ;
   }
-  if (jl->j_trans_id == 0)
-    BUG();
+  BUG_ON (jl->j_trans_id == 0);
 
   /* if flushall == 0, the lock is already held */
   if (flushall) {
@@ -1251,7 +1276,7 @@
   */
   flush_commit_list(s, jl, 1) ;
 
-  if (!(jl->j_state & LIST_DIRTY))
+  if (!(jl->j_state & LIST_DIRTY) && !reiserfs_is_journal_aborted (journal))
       BUG();
 
   /* are we done now? */
@@ -1275,6 +1300,11 @@
     if (cn->blocknr == 0) {
       goto free_cnode ;
     }
+
+    /* This transaction failed commit. Don't write out to the disk */
+    if (!(jl->j_state & LIST_DIRTY))
+        goto free_cnode;
+
     pjl = find_newer_jl_for_cn(cn) ;
     /* the order is important here.  We check pjl to make sure we
     ** don't clear BH_JDirty_wait if we aren't the one writing this
@@ -1289,8 +1319,7 @@
       get_bh(saved_bh) ;
 
       if (buffer_journal_dirty(saved_bh)) {
-	if (!can_dirty(cn))
-	  BUG();
+        BUG_ON (!can_dirty (cn));
         was_jwait = 1 ;
         was_dirty = 1 ;
       } else if (can_dirty(cn)) {
@@ -1330,8 +1359,7 @@
       get_bh(saved_bh) ;
       set_bit(BLOCK_NEEDS_FLUSH, &cn->state) ;
       lock_buffer(saved_bh);
-      if (cn->blocknr != saved_bh->b_blocknr)
-        BUG();
+      BUG_ON (cn->blocknr != saved_bh->b_blocknr);
       if (buffer_dirty(saved_bh))
         submit_logged_buffer(saved_bh) ;
       else
@@ -1363,14 +1391,16 @@
 	if (!cn->bh) {
 	  reiserfs_panic(s, "journal-1012: cn->bh is NULL\n") ;
 	}
-	if (!buffer_uptodate(cn->bh)) {
-	  reiserfs_panic(s, "journal-949: buffer write failed\n") ;
-	}
+	if (unlikely (!buffer_uptodate(cn->bh))) {
+#ifdef CONFIG_REISERFS_CHECK
+	  reiserfs_warning(s, "journal-949: buffer write failed\n") ;
+#endif
+          err = -EIO;
+  	}
 	/* note, we must clear the JDirty_wait bit after the up to date
 	** check, otherwise we race against our flushpage routine
 	*/
-        if (!test_clear_buffer_journal_dirty (cn->bh))
-	    BUG();
+        BUG_ON (!test_clear_buffer_journal_dirty (cn->bh));
 
         /* undo the inc from journal_mark_dirty */
 	put_bh(cn->bh) ;
@@ -1380,7 +1410,11 @@
     }
   }
 
+  if (err)
+    reiserfs_abort (s, -EIO, "Write error while pushing transaction to disk in %s", __FUNCTION__);
 flush_older_and_return:
+
+
   /* before we can update the journal header block, we _must_ flush all 
   ** real blocks from all older transactions to disk.  This is because
   ** once the header block is updated, this transaction will not be
@@ -1390,6 +1424,7 @@
     flush_older_journal_lists(s, jl);
   } 
   
+  err = journal->j_errno;
   /* before we can remove everything from the hash tables for this 
   ** transaction, we must make sure it can never be replayed
   **
@@ -1398,11 +1433,13 @@
   ** we only need to update the journal header block for the last list
   ** being flushed
   */
-  if (flushall) {
-    update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
+  if (!err && flushall) {
+    err = update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
+    if (err)
+        reiserfs_abort (s, -EIO, "Write error while updating journal header in %s", __FUNCTION__);
   }
   remove_all_from_journal_list(s, jl, 0) ;
-  list_del(&jl->j_list);
+  list_del_init(&jl->j_list);
   journal->j_num_lists--;
   del_from_work_list(s, jl);
 
@@ -1427,7 +1464,7 @@
   put_journal_list(s, jl);
   if (flushall)
     up(&journal->j_flush_sem);
-  return 0 ;
+  return err ;
 } 
 
 static int write_one_transaction(struct super_block *s,
@@ -1497,8 +1534,7 @@
 	pjl = find_newer_jl_for_cn(cn) ;
         if (!pjl && cn->blocknr && cn->bh && buffer_journal_dirty(cn->bh))
 	{
-	    if (!can_dirty(cn))
-	        BUG();
+	    BUG_ON (!can_dirty(cn));
 	    /* if the buffer is prepared, it will either be logged
 	     * or restored.  If restored, we need to make sure
 	     * it actually gets marked dirty
@@ -1543,7 +1579,7 @@
           (!num_trans && written < num_blocks)) {
 
 	if (jl->j_len == 0 || (jl->j_state & LIST_TOUCHED) ||
-	    atomic_read(&jl->j_commit_left))
+	    atomic_read(&jl->j_commit_left) || !(jl->j_state & LIST_DIRTY))
 	{
 	    del_from_work_list(s, jl);
 	    break;
@@ -1693,18 +1729,33 @@
 */
 static int do_journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, int error) {
   struct reiserfs_transaction_handle myth ;
+  int flushed = 0;
+  struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
 
   /* we only want to flush out transactions if we were called with error == 0
   */
   if (!error && !(p_s_sb->s_flags & MS_RDONLY)) {
     /* end the current trans */
+    BUG_ON (!th->t_trans_id);
     do_journal_end(th, p_s_sb,10, FLUSH_ALL) ;
 
     /* make sure something gets logged to force our way into the flush code */
-    journal_join(&myth, p_s_sb, 1) ;
-    reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
-    journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
-    do_journal_end(&myth, p_s_sb,1, FLUSH_ALL) ;
+    if (!journal_join(&myth, p_s_sb, 1)) {
+        reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
+        journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
+        do_journal_end(&myth, p_s_sb,1, FLUSH_ALL) ;
+        flushed = 1;
+    }
+  }
+
+  /* this also catches errors during the do_journal_end above */
+  if (!error && reiserfs_is_journal_aborted(journal)) {
+      memset(&myth, 0, sizeof(myth));
+      if (!journal_join_abort(&myth, p_s_sb, 1)) {
+	  reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
+	  journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
+          do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL) ;
+      }
   }
 
   reiserfs_mounted_fs_count-- ;
@@ -2314,6 +2365,7 @@
     INIT_LIST_HEAD (&journal->j_prealloc_list);
     INIT_LIST_HEAD(&journal->j_working_list);
     INIT_LIST_HEAD(&journal->j_journal_list);
+    journal->j_persistent_trans = 0;
     if (reiserfs_allocate_list_bitmaps(p_s_sb,
 				       journal->j_list_bitmap,
  				       SB_BMAP_NR(p_s_sb)))
@@ -2492,6 +2544,7 @@
   struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
   time_t now = get_seconds() ;
   /* cannot restart while nested */
+  BUG_ON (!th->t_trans_id);
   if (th->t_refcount > 1)
     return 0 ;
   if ( journal->j_must_wait > 0 ||
@@ -2509,8 +2562,9 @@
 */
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) {
     struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
+    BUG_ON (!th->t_trans_id);
     journal->j_must_wait = 1 ;
-    set_bit(WRITERS_BLOCKED, &journal->j_state) ;
+    set_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
     return ;
 }
 
@@ -2519,7 +2573,7 @@
 */
 void reiserfs_allow_writes(struct super_block *s) {
     struct reiserfs_journal *journal = SB_JOURNAL (s);
-    clear_bit(WRITERS_BLOCKED, &journal->j_state) ;
+    clear_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
     wake_up(&journal->j_join_wait) ;
 }
 
@@ -2529,13 +2583,13 @@
 void reiserfs_wait_on_write_block(struct super_block *s) {
     struct reiserfs_journal *journal = SB_JOURNAL (s);
     wait_event(journal->j_join_wait,
-               !test_bit(WRITERS_BLOCKED, &journal->j_state)) ;
+               !test_bit(J_WRITERS_BLOCKED, &journal->j_state)) ;
 }
 
 static void queue_log_writer(struct super_block *s) {
     wait_queue_t wait;
     struct reiserfs_journal *journal = SB_JOURNAL (s);
-    set_bit(WRITERS_QUEUED, &journal->j_state);
+    set_bit(J_WRITERS_QUEUED, &journal->j_state);
 
     /*
      * we don't want to use wait_event here because
@@ -2544,7 +2598,7 @@
     init_waitqueue_entry(&wait, current);
     add_wait_queue(&journal->j_join_wait, &wait);
     set_current_state(TASK_UNINTERRUPTIBLE);
-    if (test_bit(WRITERS_QUEUED, &journal->j_state))
+    if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
         schedule();
     current->state = TASK_RUNNING;
     remove_wait_queue(&journal->j_join_wait, &wait);
@@ -2552,7 +2606,7 @@
 
 static void wake_queued_writers(struct super_block *s) {
     struct reiserfs_journal *journal = SB_JOURNAL (s);
-    if (test_and_clear_bit(WRITERS_QUEUED, &journal->j_state))
+    if (test_and_clear_bit(J_WRITERS_QUEUED, &journal->j_state))
         wake_up(&journal->j_join_wait);
 }
 
@@ -2590,10 +2644,9 @@
   struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
   struct reiserfs_transaction_handle myth;
   int sched_count = 0;
+  int retval;
 
   reiserfs_check_lock_depth(p_s_sb, "journal_begin") ;
-  RFALSE( p_s_sb->s_flags & MS_RDONLY, 
-	  "clm-2078: calling journal_begin on readonly FS") ;
 
   PROC_INFO_INC( p_s_sb, journal.journal_being );
   /* set here for journal_join */
@@ -2602,9 +2655,14 @@
 
 relock:
   lock_journal(p_s_sb) ;
+  if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted (journal)) {
+    unlock_journal (p_s_sb);
+    retval = journal->j_errno;
+    goto out_fail;
+  }
   journal->j_bcount++;
 
-  if (test_bit(WRITERS_BLOCKED, &journal->j_state)) {
+  if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
     unlock_journal(p_s_sb) ;
     reiserfs_wait_on_write_block(p_s_sb) ;
     PROC_INFO_INC( p_s_sb, journal.journal_relock_writers );
@@ -2647,15 +2705,20 @@
         }
 	goto relock;
     }
-    journal_join(&myth, p_s_sb, 1) ;
+    retval = journal_join(&myth, p_s_sb, 1) ;
+    if (retval)
+        goto out_fail;
 
     /* someone might have ended the transaction while we joined */
     if (old_trans_id != journal->j_trans_id) {
-        do_journal_end(&myth, p_s_sb, 1, 0) ;
+        retval = do_journal_end(&myth, p_s_sb, 1, 0) ;
     } else {
-        do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW) ;
+        retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW) ;
     }
 
+    if (retval)
+        goto out_fail;
+
     PROC_INFO_INC( p_s_sb, journal.journal_relock_wcount );
     goto relock ;
   }
@@ -2669,7 +2732,16 @@
   th->t_blocks_allocated = nblocks ;
   th->t_trans_id = journal->j_trans_id ;
   unlock_journal(p_s_sb) ;
+  INIT_LIST_HEAD (&th->t_list);
   return 0 ;
+
+out_fail:
+  memset (th, 0, sizeof (*th));
+  /* Re-set th->t_super, so we can properly keep track of how many
+   * persistent transactions there are. We need to do this so if this
+   * call is part of a failed restart_transaction, we can free it later */
+  th->t_super = p_s_sb;
+  return retval;
 }
 
 struct reiserfs_transaction_handle *
@@ -2696,16 +2768,23 @@
 	reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
         return NULL;
     }
+
+    SB_JOURNAL(s)->j_persistent_trans++;
     return th ;
 }
 
 int
 reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th) {
     struct super_block *s = th->t_super;
-    int ret;
-    ret = journal_end(th, th->t_super, th->t_blocks_allocated);
-    if (th->t_refcount == 0)
+    int ret = 0;
+    if (th->t_trans_id)
+        ret = journal_end(th, th->t_super, th->t_blocks_allocated);
+    else
+        ret = -EIO;
+    if (th->t_refcount == 0) {
+        SB_JOURNAL(s)->j_persistent_trans--;
 	reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
+    }
     return ret;
 }
 
@@ -2719,7 +2798,20 @@
   if (cur_th && cur_th->t_refcount > 1) {
       BUG() ;
   }
-  return do_journal_begin_r(th, p_s_sb, nblocks, 1) ;
+  return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN) ;
+}
+
+int journal_join_abort(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
+  struct reiserfs_transaction_handle *cur_th = current->journal_info;
+
+  /* this keeps do_journal_end from NULLing out the current->journal_info
+  ** pointer
+  */
+  th->t_handle_save = cur_th ;
+  if (cur_th && cur_th->t_refcount > 1) {
+      BUG() ;
+  }
+  return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT) ;
 }
 
 int journal_begin(struct reiserfs_transaction_handle *th, struct super_block  * p_s_sb, unsigned long nblocks) {
@@ -2730,6 +2822,7 @@
     if (cur_th) {
 	/* we are nesting into the current transaction */
 	if (cur_th->t_super == p_s_sb) {
+              BUG_ON (!cur_th->t_refcount);
 	      cur_th->t_refcount++ ;
 	      memcpy(th, cur_th, sizeof(*th));
 	      if (th->t_refcount <= 1)
@@ -2747,9 +2840,18 @@
     } else {
 	current->journal_info = th;
     }
-    ret = do_journal_begin_r(th, p_s_sb, nblocks, 0) ;
+    ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG) ;
     if (current->journal_info != th)
         BUG() ;
+
+    /* I guess this boils down to being the reciprocal of clm-2100 above.
+     * If do_journal_begin_r fails, we need to put it back, since journal_end
+     * won't be called to do it. */
+    if (ret)
+        current->journal_info = th->t_handle_save;
+    else
+        BUG_ON (!th->t_refcount);
+
     return ret ;
 }
 
@@ -2767,12 +2869,14 @@
   struct reiserfs_journal_cnode *cn = NULL;
   int count_already_incd = 0 ;
   int prepared = 0 ;
+  BUG_ON (!th->t_trans_id);
 
   PROC_INFO_INC( p_s_sb, journal.mark_dirty );
   if (th->t_trans_id != journal->j_trans_id) {
     reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n", 
                    th->t_trans_id, journal->j_trans_id);
   }
+
   p_s_sb->s_dirt = 1;
 
   prepared = test_clear_buffer_journal_prepared (bh);
@@ -2860,6 +2964,11 @@
     reiserfs_warning (p_s_sb, "REISER-NESTING: th NULL, refcount %d",
                       th->t_refcount);
 
+  if (!th->t_trans_id) {
+    WARN_ON (1);
+    return -EIO;
+  }
+
   th->t_refcount--;
   if (th->t_refcount > 0) {
     struct reiserfs_transaction_handle *cur_th = current->journal_info ;
@@ -2976,6 +3085,7 @@
 int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
   struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
 
+  BUG_ON (!th->t_trans_id);
   /* you can sync while nested, very, very bad */
   if (th->t_refcount > 1) {
     BUG() ;
@@ -3008,7 +3118,7 @@
    * this is a little racey, but there's no harm in missing
    * the filemap_fdata_write
    */
-  if (!atomic_read(&journal->j_async_throttle)) {
+  if (!atomic_read(&journal->j_async_throttle) && !reiserfs_is_journal_aborted (journal)) {
       atomic_inc(&journal->j_async_throttle);
       filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
       atomic_dec(&journal->j_async_throttle);
@@ -3040,14 +3150,15 @@
         journal->j_len > 0 &&
         (now - journal->j_trans_start_time) > journal->j_max_trans_age)
     {
-	journal_join(&th, p_s_sb, 1) ;
-	reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
-	journal_mark_dirty(&th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
-
-	/* we're only being called from kreiserfsd, it makes no sense to do
-	** an async commit so that kreiserfsd can do it later
-	*/
-	do_journal_end(&th, p_s_sb,1, COMMIT_NOW | WAIT) ;
+	if (!journal_join(&th, p_s_sb, 1)) {
+            reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
+            journal_mark_dirty(&th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
+
+            /* we're only being called from kreiserfsd, it makes no sense to do
+            ** an async commit so that kreiserfsd can do it later
+            */
+            do_journal_end(&th, p_s_sb,1, COMMIT_NOW | WAIT) ;
+        }
     }
     return p_s_sb->s_dirt;
 }
@@ -3073,6 +3184,8 @@
   struct reiserfs_journal_list *jl;
   struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
 
+  BUG_ON (!th->t_trans_id);
+
   if (th->t_trans_id != journal->j_trans_id) {
     reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n", 
                    th->t_trans_id, journal->j_trans_id);
@@ -3178,6 +3291,7 @@
   struct buffer_head *bh = NULL ;
   struct reiserfs_list_bitmap *jb = NULL ;
   int cleaned = 0 ;
+  BUG_ON (!th->t_trans_id);
 
   cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
   if (cn && cn->bh) {
@@ -3269,18 +3383,21 @@
 	    goto flush_commit_only;
 	}
 
-	journal_begin(&th, sb, 1) ;
+	ret = journal_begin(&th, sb, 1) ;
+	if (ret)
+	    return ret;
 
 	/* someone might have ended this transaction while we joined */
 	if (journal->j_trans_id != id) {
 	    reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb), 1) ;
 	    journal_mark_dirty(&th, sb, SB_BUFFER_WITH_SB(sb)) ;
-	    journal_end(&th, sb, 1) ;
+	    ret = journal_end(&th, sb, 1) ;
 	    goto flush_commit_only;
 	}
 
-	journal_end_sync(&th, sb, 1) ;
-	ret = 1;
+	ret = journal_end_sync(&th, sb, 1) ;
+	if (!ret)
+	    ret = 1;
 
     } else {
 	/* this gets tricky, we have to make sure the journal list in
@@ -3297,6 +3414,8 @@
 	    if (atomic_read(&jl->j_commit_left) > 1)
 	        ret = 1;
 	    flush_commit_list(sb, jl, 1) ;
+	    if (journal->j_errno)
+		ret = journal->j_errno;
 	}
     }
     /* otherwise the list is gone, and long since committed */
@@ -3390,6 +3509,9 @@
 ** If no_async, won't return until all commit blocks are on disk.
 **
 ** keep reading, there are comments as you go along
+**
+** If the journal is aborted, we just clean up. Things like flushing
+** journal lists, etc just won't happen.
 */
 static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_block  * p_s_sb, unsigned long nblocks, 
 		          int flags) {
@@ -3411,8 +3533,8 @@
   unsigned long commit_trans_id;
   int trans_half;
 
-  if (th->t_refcount > 1)
-    BUG() ;
+  BUG_ON (th->t_refcount > 1);
+  BUG_ON (!th->t_trans_id);
 
   current->journal_info = th->t_handle_save;
   reiserfs_check_lock_depth(p_s_sb, "journal end");
@@ -3707,7 +3829,7 @@
   atomic_set(&(journal->j_jlock), 0) ;
   unlock_journal(p_s_sb) ;
   /* wake up any body waiting to join. */
-  clear_bit(WRITERS_QUEUED, &journal->j_state);
+  clear_bit(J_WRITERS_QUEUED, &journal->j_state);
   wake_up(&(journal->j_join_wait)) ;
 
   if (!flush && wait_on_commit &&
@@ -3716,6 +3838,49 @@
   }
 out:
   reiserfs_check_lock_depth(p_s_sb, "journal end2");
-  th->t_trans_id = 0;
-  return 0 ;
+
+  memset (th, 0, sizeof (*th));
+  /* Re-set th->t_super, so we can properly keep track of how many
+   * persistent transactions there are. We need to do this so if this
+   * call is part of a failed restart_transaction, we can free it later */
+  th->t_super = p_s_sb;
+
+  return journal->j_errno;
+}
+
+void
+__reiserfs_journal_abort_hard (struct super_block *sb)
+{
+    struct reiserfs_journal *journal = SB_JOURNAL (sb);
+    if (test_bit (J_ABORTED, &journal->j_state))
+        return;
+
+    printk (KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n",
+                      reiserfs_bdevname (sb));
+
+    sb->s_flags |= MS_RDONLY;
+    set_bit (J_ABORTED, &journal->j_state);
+
+#ifdef CONFIG_REISERFS_CHECK
+    dump_stack();
+#endif
+}
+
+void
+__reiserfs_journal_abort_soft (struct super_block *sb, int errno)
+{
+    struct reiserfs_journal *journal = SB_JOURNAL (sb);
+    if (test_bit (J_ABORTED, &journal->j_state))
+        return;
+
+    if (!journal->j_errno)
+        journal->j_errno = errno;
+
+    __reiserfs_journal_abort_hard (sb);
+}
+
+void
+reiserfs_journal_abort (struct super_block *sb, int errno)
+{
+    return __reiserfs_journal_abort_soft (sb, errno);
 }
diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
--- a/fs/reiserfs/namei.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/namei.c	2004-11-03 18:29:31 -08:00
@@ -430,6 +430,7 @@
     int buflen, paste_size;
     int retval;
 
+    BUG_ON (!th->t_trans_id);
 
     /* cannot allow items to be added into a busy deleted directory */
     if (!namelen)
@@ -606,16 +607,21 @@
     if (locked)
         reiserfs_write_lock_xattrs (dir->i_sb);
 
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
-    retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
-
-    if (locked)
-        reiserfs_write_unlock_xattrs (dir->i_sb);
-
+    retval = journal_begin(&th, dir->i_sb, jbegin_count);
     if (retval) {
+        drop_new_inode (inode);
         goto out_failed;
     }
+
+    retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval)
+        goto out_failed;
 	
+    if (locked) {
+        reiserfs_write_unlock_xattrs (dir->i_sb);
+        locked = 0;
+    }
+
     inode->i_op = &reiserfs_file_inode_operations;
     inode->i_fop = &reiserfs_file_operations;
     inode->i_mapping->a_ops = &reiserfs_address_space_operations ;
@@ -623,9 +629,12 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
+        int err;
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	err = journal_end(&th, dir->i_sb, jbegin_count) ;
+        if (err)
+            retval = err;
 	iput (inode);
 	goto out_failed;
     }
@@ -633,9 +642,11 @@
     reiserfs_update_inode_transaction(dir) ;
 
     d_instantiate(dentry, inode);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
 
 out_failed:
+    if (locked)
+        reiserfs_write_unlock_xattrs (dir->i_sb);
     reiserfs_write_unlock(dir->i_sb);
     return retval;
 }
@@ -666,17 +677,23 @@
     if (locked)
         reiserfs_write_lock_xattrs (dir->i_sb);
 
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
+    if (retval) {
+        drop_new_inode (inode);
+        goto out_failed;
+    }
 
     retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
-
-    if (locked)
-        reiserfs_write_unlock_xattrs (dir->i_sb);
-
     if (retval) {
         goto out_failed;
     }
 
+    if (locked) {
+        reiserfs_write_unlock_xattrs (dir->i_sb);
+        locked = 0;
+    }
+
+
     inode->i_op = &reiserfs_special_inode_operations;
     init_special_inode(inode, inode->i_mode, rdev) ;
 
@@ -689,17 +706,22 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				 inode, 1/*visible*/);
     if (retval) {
+        int err;
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	err = journal_end(&th, dir->i_sb, jbegin_count) ;
+        if (err)
+	    retval = err;
 	iput (inode);
 	goto out_failed;
     }
 
     d_instantiate(dentry, inode);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
 
 out_failed:
+    if (locked)
+        reiserfs_write_unlock_xattrs (dir->i_sb);
     reiserfs_write_unlock(dir->i_sb);
     return retval;
 }
@@ -730,7 +752,13 @@
     reiserfs_write_lock(dir->i_sb);
     if (locked)
         reiserfs_write_lock_xattrs (dir->i_sb);
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+
+    retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
+    if (retval) {
+        drop_new_inode (inode);
+        goto out_failed;
+    }
+
 
     /* inc the link count now, so another writer doesn't overflow it while
     ** we sleep later on.
@@ -741,13 +769,16 @@
 				old_format_only (dir->i_sb) ? 
 				EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
 				dentry, inode);
-    if (locked)
-        reiserfs_write_unlock_xattrs (dir->i_sb);
-
     if (retval) {
 	dir->i_nlink-- ;
 	goto out_failed;
     }
+
+    if (locked) {
+	reiserfs_write_unlock_xattrs (dir->i_sb);
+	locked = 0;
+    }
+
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
 
@@ -758,10 +789,13 @@
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len, 
 				inode, 1/*visible*/);
     if (retval) {
+	int err;
 	inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	err = journal_end(&th, dir->i_sb, jbegin_count) ;
+	if (err)
+	    retval = err;
 	iput (inode);
 	goto out_failed;
     }
@@ -770,8 +804,10 @@
     reiserfs_update_sd (&th, dir);
 
     d_instantiate(dentry, inode);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
 out_failed:
+    if (locked)
+        reiserfs_write_unlock_xattrs (dir->i_sb);
     reiserfs_write_unlock(dir->i_sb);
     return retval;
 }
@@ -791,7 +827,7 @@
 
 static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
 {
-    int retval;
+    int retval, err;
     struct inode * inode;
     struct reiserfs_transaction_handle th ;
     int jbegin_count; 
@@ -803,7 +839,9 @@
     jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
 
     reiserfs_write_lock(dir->i_sb);
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
+    if (retval)
+        goto out_rmdir;
 
     de.de_gen_number_bit_string = NULL;
     if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
@@ -852,24 +890,25 @@
     /* prevent empty directory from getting lost */
     add_save_link (&th, inode, 0/* not truncate */);
 
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_check_path(&path) ;
+out_rmdir:
     reiserfs_write_unlock(dir->i_sb);
-    return 0;
+    return retval;
 	
  end_rmdir:
     /* we must release path, because we did not call
        reiserfs_cut_from_item, or reiserfs_cut_from_item does not
        release path if operation was not complete */
     pathrelse (&path);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    err = journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_write_unlock(dir->i_sb);
-    return retval;	
+    return err ? err : retval;
 }
 
 static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
 {
-    int retval;
+    int retval, err;
     struct inode * inode;
     struct reiserfs_dir_entry de;
     INITIALIZE_PATH (path);
@@ -884,7 +923,9 @@
     jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2;
 
     reiserfs_write_lock(dir->i_sb);
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
+    if (retval)
+        goto out_unlink;
 	
     de.de_gen_number_bit_string = NULL;
     if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
@@ -938,15 +979,18 @@
        /* prevent file from getting lost */
        add_save_link (&th, inode, 0/* not truncate */);
 
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_check_path(&path) ;
     reiserfs_write_unlock(dir->i_sb);
-    return 0;
+    return retval;
 
  end_unlink:
     pathrelse (&path);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    err = journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_check_path(&path) ;
+    if (err)
+        retval = err;
+out_unlink:
     reiserfs_write_unlock(dir->i_sb);
     return retval;
 }
@@ -989,7 +1033,12 @@
 
     /* We would inherit the default ACL here, but symlinks don't get ACLs */
 
-    journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
+    if (retval) {
+        drop_new_inode (inode);
+        reiserfs_kfree (name, item_len, parent_dir->i_sb);
+        goto out_failed;
+    }
 
     retval = reiserfs_new_inode (&th, parent_dir, mode, name, strlen (symname), 
                                  dentry, inode);
@@ -1011,15 +1060,18 @@
     retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name, 
                                  dentry->d_name.len, inode, 1/*visible*/);
     if (retval) {
+	int err;
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
+	err = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
+	if (err)
+	    retval = err;
 	iput (inode);
 	goto out_failed;
     }
 
     d_instantiate(dentry, inode);
-    journal_end(&th, parent_dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
 out_failed:
     reiserfs_write_unlock(parent_dir->i_sb);
     return retval;
@@ -1045,7 +1097,12 @@
     /* inc before scheduling so reiserfs_unlink knows we are here */
     inode->i_nlink++;
 
-    journal_begin(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
+    if (retval) {
+        inode->i_nlink--;
+        reiserfs_write_unlock (dir->i_sb);
+        return retval;
+    }
 
     /* create new entry */
     retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
@@ -1055,10 +1112,11 @@
     reiserfs_update_inode_transaction(dir) ;
 
     if (retval) {
+	int err;
 	inode->i_nlink--;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
+	err = journal_end(&th, dir->i_sb, jbegin_count) ;
 	reiserfs_write_unlock(dir->i_sb);
-	return retval;
+	return err ? err : retval;
     }
 
     inode->i_ctime = CURRENT_TIME;
@@ -1066,9 +1124,9 @@
 
     atomic_inc(&inode->i_count) ;
     d_instantiate(dentry, inode);
-    journal_end(&th, dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, dir->i_sb, jbegin_count) ;
     reiserfs_write_unlock(dir->i_sb);
-    return 0;
+    return retval;
 }
 
 
@@ -1195,7 +1253,12 @@
 	}
     }
 
-    journal_begin(&th, old_dir->i_sb, jbegin_count) ;
+    retval = journal_begin(&th, old_dir->i_sb, jbegin_count) ;
+    if (retval) {
+        reiserfs_write_unlock (old_dir->i_sb);
+        return retval;
+    }
+
 
     /* add new entry (or find the existing one) */
     retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len, 
@@ -1206,9 +1269,9 @@
 			    "vs-7050: new entry is found, new inode == 0\n");
 	}
     } else if (retval) {
-	journal_end(&th, old_dir->i_sb, jbegin_count) ;
+	int err = journal_end(&th, old_dir->i_sb, jbegin_count) ;
 	reiserfs_write_unlock(old_dir->i_sb);
-	return retval;
+	return err ? err : retval;
     }
 
     reiserfs_update_inode_transaction(old_dir) ;
@@ -1357,9 +1420,9 @@
 	reiserfs_update_sd (&th, new_dentry_inode);
     }
 
-    journal_end(&th, old_dir->i_sb, jbegin_count) ;
+    retval = journal_end(&th, old_dir->i_sb, jbegin_count) ;
     reiserfs_write_unlock(old_dir->i_sb);
-    return 0;
+    return retval;
 }
 
 /*
@@ -1414,5 +1477,3 @@
     .permission     = reiserfs_permission,
 
 };
-
-
diff -Nru a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
--- a/fs/reiserfs/objectid.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/objectid.c	2004-11-03 18:29:31 -08:00
@@ -55,6 +55,7 @@
     __u32 * map = objectid_map (s, rs);
     __u32 unused_objectid;
 
+    BUG_ON (!th->t_trans_id);
 
     check_objectid_map (s, map);
 
@@ -99,6 +100,7 @@
     __u32 * map = objectid_map (s, rs);
     int i = 0;
 
+    BUG_ON (!th->t_trans_id);
     //return;
     check_objectid_map (s, map);
 
diff -Nru a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
--- a/fs/reiserfs/prints.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/prints.c	2004-11-03 18:29:31 -08:00
@@ -366,6 +366,49 @@
 	 reiserfs_bdevname (sb), error_buf);
 }
 
+static void
+do_handle_error (struct super_block *sb, int errno)
+{
+    if (reiserfs_error_panic (sb)) {
+        panic ("REISERFS: panic (device %s): Panic forced after error\n",
+               reiserfs_bdevname (sb));
+    }
+
+    if (reiserfs_error_ro (sb)) {
+        printk (KERN_CRIT "REISERFS: error (device %s): Re-mounting fs "
+                "readonly\n", reiserfs_bdevname (sb));
+        reiserfs_journal_abort (sb, errno);
+    }
+}
+
+void
+reiserfs_error (struct super_block * sb, int errno, const char *fmt, ...)
+{
+    do_reiserfs_warning (fmt);
+    printk (KERN_CRIT "REISERFS: error (device %s): %s\n",
+            reiserfs_bdevname (sb), error_buf);
+    do_handle_error (sb, errno);
+}
+
+void
+reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...)
+{
+    do_reiserfs_warning (fmt);
+
+    if (reiserfs_error_panic (sb)) {
+        panic (KERN_CRIT "REISERFS: panic (device %s): %s\n",
+               reiserfs_bdevname (sb), error_buf);
+    }
+
+    if (sb->s_flags & MS_RDONLY)
+        return;
+
+    printk (KERN_CRIT "REISERFS: abort (device %s): %s\n",
+            reiserfs_bdevname (sb), error_buf);
+
+    sb->s_flags |= MS_RDONLY;
+    reiserfs_journal_abort (sb, errno);
+}
 
 void print_virtual_node (struct virtual_node * vn)
 {
diff -Nru a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
--- a/fs/reiserfs/resize.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/resize.c	2004-11-03 18:29:31 -08:00
@@ -19,8 +19,10 @@
 
 int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
 {
+        int err = 0;
 	struct reiserfs_super_block * sb;
         struct reiserfs_bitmap_info *bitmap;
+	struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
 	struct buffer_head * bh;
 	struct reiserfs_transaction_handle th;
 	unsigned int bmap_nr_new, bmap_nr;
@@ -107,12 +109,19 @@
 	     * block pointers */
 	    bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
 	    if (!bitmap) {
+		/* Journal bitmaps are still supersized, but the memory isn't
+		 * leaked, so I guess it's ok */
 		printk("reiserfs_resize: unable to allocate memory.\n");
 		return -ENOMEM;
 	    }
 	    memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
 	    for (i = 0; i < bmap_nr; i++)
-		bitmap[i] = SB_AP_BITMAP(s)[i];
+		bitmap[i] = old_bitmap[i];
+
+	    /* This doesn't go through the journal, but it doesn't have to.
+	     * The changes are still atomic: We're synced up when the journal
+	     * transaction begins, and the new bitmaps don't matter if the
+	     * transaction fails. */
 	    for (i = bmap_nr; i < bmap_nr_new; i++) {
 		bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
 		memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
@@ -126,12 +135,16 @@
 		bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
 	    }	
 	    /* free old bitmap blocks array */
-	    vfree(SB_AP_BITMAP(s));
 	    SB_AP_BITMAP(s) = bitmap;
+	    vfree (old_bitmap);
 	}
 	
-	/* begin transaction */
-	journal_begin(&th, s, 10);
+	/* begin transaction, if there was an error, it's fine. Yes, we have
+	 * incorrect bitmaps now, but none of it is ever going to touch the
+	 * disk anyway. */
+	err = journal_begin(&th, s, 10);
+	if (err)
+	    return err;
 
 	/* correct last bitmap blocks in old and new disk layout */
 	reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
@@ -165,8 +178,5 @@
 	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
 	
 	SB_JOURNAL(s)->j_must_wait = 1;
-	journal_end(&th, s, 10);
-
-	return 0;
+	return journal_end(&th, s, 10);
 }
-
diff -Nru a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
--- a/fs/reiserfs/stree.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/stree.c	2004-11-03 18:29:31 -08:00
@@ -1036,6 +1036,8 @@
     struct item_head    * p_le_ih = PATH_PITEM_HEAD(p_s_path);
     struct buffer_head  * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
 
+    BUG_ON (!th->t_trans_id);
+
     /* Stat_data item. */
     if ( is_statdata_le_ih (p_le_ih) ) {
 
@@ -1222,6 +1224,9 @@
     struct path         * p_s_path,
     int                   n_size
     ) {
+
+    BUG_ON (!th->t_trans_id);
+
     memset (p_s_tb,'\0',sizeof(struct tree_balance));
     p_s_tb->transaction_handle = th ;
     p_s_tb->tb_sb = p_s_sb;
@@ -1290,6 +1295,8 @@
     int			n_iter = 0;
 #endif
 
+    BUG_ON (!th->t_trans_id);
+
     init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path, 0/*size is unknown*/);
 
     while ( 1 ) {
@@ -1419,6 +1426,8 @@
     struct cpu_key cpu_key;
     int retval;
     int quota_cut_bytes = 0;
+
+    BUG_ON (!th->t_trans_id);
     
     le_key2cpu_key (&cpu_key, key);
     
@@ -1474,12 +1483,16 @@
 }
 
 
-void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
+int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
 {
+    int err;
     inode->i_size = 0;
+    BUG_ON (!th->t_trans_id);
 
     /* for directory this deletes item containing "." and ".." */
-    reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
+    err = reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
+    if (err)
+        return err;
     
 #if defined( USE_INODE_GENERATION_COUNTER )
     if( !old_format_only ( th -> t_super ) )
@@ -1493,6 +1506,8 @@
 /* USE_INODE_GENERATION_COUNTER */
 #endif
     reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
+
+    return err;
 }
 
 static void
@@ -1542,6 +1557,7 @@
     struct super_block * p_s_sb = p_s_inode->i_sb;
     int n_block_size = p_s_sb->s_blocksize;
     int cut_bytes;
+    BUG_ON (!th->t_trans_id);
 
     if (n_new_file_size != p_s_inode->i_size)
 	BUG ();
@@ -1574,6 +1590,7 @@
     struct cpu_key tail_key;
     int tail_len;
     int removed;
+    BUG_ON (!th->t_trans_id);
 
     make_cpu_key (&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4);// !!!!
     tail_key.key_length = 4;
@@ -1623,6 +1640,8 @@
     int retval2 = -1;
     int quota_cut_bytes;
     loff_t tail_pos = 0;
+
+    BUG_ON (!th->t_trans_id);
     
     init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
 
@@ -1775,6 +1794,7 @@
 
 static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
 {
+    BUG_ON (!th->t_trans_id);
     if (inode->i_nlink)
 	reiserfs_warning (inode->i_sb,
 			  "vs-5655: truncate_directory: link count != 0");
@@ -1792,7 +1812,7 @@
 
 /* Truncate file to the new size. Note, this must be called with a transaction
    already started */
-void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 
+int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
 			   struct  inode * p_s_inode, /* ->i_size contains new
                                                          size */
 			   struct page *page, /* up to date for last block */
@@ -1808,14 +1828,16 @@
 	n_new_file_size;/* New file size. */
     int                   n_deleted;      /* Number of deleted or truncated bytes. */
     int retval;
+    int err = 0;
 
+    BUG_ON (!th->t_trans_id);
     if ( ! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode)) )
-	return;
+	return 0;
 
     if (S_ISDIR(p_s_inode->i_mode)) {
 	// deletion of directory - no need to update timestamps
 	truncate_directory (th, p_s_inode);
-	return;
+	return 0;
     }
 
     /* Get new file size. */
@@ -1828,13 +1850,15 @@
     if (retval == IO_ERROR) {
 	reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: "
 			  "i/o failure occurred trying to truncate %K", &s_item_key);
-	return;
+        err = -EIO;
+        goto out;
     }
     if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
-	pathrelse (&s_search_path);
 	reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: "
 			  "wrong result %d of search for %K", retval, &s_item_key);
-	return;
+
+        err = -EIO;
+        goto out;
     }
 
     s_search_path.pos_in_item --;
@@ -1872,7 +1896,7 @@
 	if (n_deleted < 0) {
 	    reiserfs_warning (p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");
 	    reiserfs_check_path(&s_search_path) ;
-	    return;
+	    return 0;
 	}
 
 	RFALSE( n_deleted > n_file_size,
@@ -1902,8 +1926,13 @@
 	  } 
 	  reiserfs_update_sd(th, p_s_inode) ;
 
-	  journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
-	  journal_begin(th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 6) ;
+	  err = journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
+	  if (err)
+	    goto out;
+	  err = journal_begin (th, p_s_inode->i_sb,
+                               JOURNAL_PER_BALANCE_CNT * 6);
+	  if (err)
+	    goto out;
 	  reiserfs_update_inode_transaction(p_s_inode) ;
 	}
     } while ( n_file_size > ROUND_UP (n_new_file_size) &&
@@ -1920,7 +1949,9 @@
     }
     reiserfs_update_sd (th, p_s_inode);
 
+out:
     pathrelse(&s_search_path) ;
+    return err;
 }
 
 
@@ -1963,6 +1994,8 @@
     int                 retval;
     int			fs_gen;
 
+    BUG_ON (!th->t_trans_id);
+
     fs_gen = get_generation(inode->i_sb) ;
 
 #ifdef REISERQUOTA_DEBUG
@@ -2034,6 +2067,8 @@
     int                 retval;
     int fs_gen = 0 ;
     int quota_bytes = 0 ;
+
+    BUG_ON (!th->t_trans_id);
 
     if (inode) {      /* Do we count quotas for item? */
 	fs_gen = get_generation(inode->i_sb);
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/super.c	2004-11-03 18:29:31 -08:00
@@ -24,6 +24,7 @@
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/namespace.h>
 
 struct file_system_type reiserfs_fs_type;
 
@@ -66,11 +67,14 @@
     if (!(s->s_flags & MS_RDONLY)) {
         struct reiserfs_transaction_handle th;
 	reiserfs_write_lock(s);
-	journal_begin(&th, s, 1);
-	journal_end_sync(&th, s, 1);
-	reiserfs_flush_old_commits(s);
-	s->s_dirt = 0;
+	if (!journal_begin(&th, s, 1))
+            if (!journal_end_sync(&th, s, 1))
+                reiserfs_flush_old_commits(s);
+	s->s_dirt = 0; /* Even if it's not true.
+                        * We'll loop forever in sync_supers otherwise */
 	reiserfs_write_unlock(s);
+    } else {
+        s->s_dirt = 0;
     }
 }
 
@@ -84,11 +88,15 @@
   struct reiserfs_transaction_handle th ;
   reiserfs_write_lock(s);
   if (!(s->s_flags & MS_RDONLY)) {
-    journal_begin(&th, s, 1) ;
-    reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
-    journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
-    reiserfs_block_writes(&th) ;
-    journal_end_sync(&th, s, 1) ;
+    int err = journal_begin(&th, s, 1) ;
+    if (err) {
+        reiserfs_block_writes(&th) ;
+    } else {
+        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+        reiserfs_block_writes(&th) ;
+        journal_end_sync(&th, s, 1) ;
+    }
   }
   s->s_dirt = 0;
   reiserfs_write_unlock(s);
@@ -108,29 +116,32 @@
    protecting unlink is bigger that a key lf "save link" which
    protects truncate), so there left no items to make truncate
    completion on */
-static void remove_save_link_only (struct super_block * s, struct key * key, int oid_free)
+static int remove_save_link_only (struct super_block * s, struct key * key, int oid_free)
 {
     struct reiserfs_transaction_handle th;
+    int err;
 
      /* we are going to do one balancing */
-     journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
+     err = journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
+     if (err)
+        return err;
  
      reiserfs_delete_solid_item (&th, NULL, key);
      if (oid_free)
         /* removals are protected by direct items */
         reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
 
-     journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
+     return journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
 }
  
  
 /* look for uncompleted unlinks and truncates and complete them */
-static void finish_unfinished (struct super_block * s)
+static int finish_unfinished (struct super_block * s)
 {
     INITIALIZE_PATH (path);
     struct cpu_key max_cpu_key, obj_key;
     struct key save_link_key;
-    int retval;
+    int retval = 0;
     struct item_head * ih;
     struct buffer_head * bh;
     int item_pos;
@@ -147,7 +158,7 @@
  
     done = 0;
     REISERFS_SB(s)->s_is_unlinked_ok = 1;
-    while (1) {
+    while (!retval) {
         retval = search_item (s, &max_cpu_key, &path);
         if (retval != ITEM_NOT_FOUND) {
             reiserfs_warning (s, "vs-2140: finish_unfinished: search_by_key returned %d",
@@ -189,7 +200,7 @@
 	       "save" link and release objectid */
             reiserfs_warning (s, "vs-2180: finish_unfinished: iget failed for %K",
                               &obj_key);
-            remove_save_link_only (s, &save_link_key, 1);
+            retval = remove_save_link_only (s, &save_link_key, 1);
             continue;
         }
 
@@ -197,7 +208,7 @@
 	    /* file is not unlinked */
             reiserfs_warning (s, "vs-2185: finish_unfinished: file %K is not unlinked",
                               &obj_key);
-            remove_save_link_only (s, &save_link_key, 0);
+            retval = remove_save_link_only (s, &save_link_key, 0);
             continue;
 	}
 
@@ -207,7 +218,7 @@
 	       then boot into old kernel, remove the file and create dir with
 	       the same key. */
 	    reiserfs_warning(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY (inode));
-	    remove_save_link_only (s, &save_link_key, 0);
+	    retval = remove_save_link_only (s, &save_link_key, 0);
 	    truncate = 0;
 	    iput (inode); 
 	    continue;
@@ -220,12 +231,13 @@
             reiserfs_info (s, "Truncating %k to %Ld ..",
                               INODE_PKEY (inode), inode->i_size);
             reiserfs_truncate_file (inode, 0/*don't update modification time*/);
-            remove_save_link (inode, truncate);
+            retval = remove_save_link (inode, truncate);
         } else {
             REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask;
             /* not completed unlink (rmdir) found */
             reiserfs_info (s, "Removing %k..", INODE_PKEY (inode));
             /* removal gets completed in iput */
+            retval = 0;
         }
  
         iput (inode);
@@ -238,6 +250,7 @@
     if (done)
         reiserfs_info (s, "There were %d uncompleted unlinks/truncates. "
                           "Completed\n", done);
+    return retval;
 }
  
 /* to protect file being unlinked from getting lost we "safe" link files
@@ -253,6 +266,8 @@
     struct item_head ih;
     __u32 link;
 
+    BUG_ON (!th->t_trans_id);
+
     /* file can only get one "save link" of each kind */
     RFALSE( truncate && 
 	    ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ),
@@ -317,14 +332,16 @@
 
 
 /* this opens transaction unlike add_save_link */
-void remove_save_link (struct inode * inode, int truncate)
+int remove_save_link (struct inode * inode, int truncate)
 {
     struct reiserfs_transaction_handle th;
     struct key key;
- 
+    int err;
  
     /* we are going to do one balancing only */
-    journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    err = journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    if (err)
+        return err;
  
     /* setup key of "save" link */
     key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
@@ -352,7 +369,7 @@
     } else
 	REISERFS_I(inode) -> i_flags &= ~i_link_saved_truncate_mask;
  
-    journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+    return journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
 }
 
 
@@ -360,6 +377,7 @@
 {
   int i;
   struct reiserfs_transaction_handle th ;
+  th.t_trans_id = 0;
 
   if (REISERFS_SB(s)->xattr_root) {
     d_invalidate (REISERFS_SB(s)->xattr_root);
@@ -373,10 +391,11 @@
 
   /* change file system state to current state if it was mounted with read-write permissions */
   if (!(s->s_flags & MS_RDONLY)) {
-    journal_begin(&th, s, 10) ;
-    reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-    set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
-    journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+    if (!journal_begin(&th, s, 10)) {
+        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
+        set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
+        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
+    }
   }
 
   /* note, journal_release checks for readonly mount, and can decide not
@@ -461,6 +480,7 @@
 static void reiserfs_dirty_inode (struct inode * inode) {
     struct reiserfs_transaction_handle th ;
 
+    int err = 0;
     if (inode->i_sb->s_flags & MS_RDONLY) {
         reiserfs_warning(inode->i_sb, "clm-6006: writing inode %lu on readonly FS",
 	                  inode->i_ino) ;
@@ -471,7 +491,11 @@
     /* this is really only used for atime updates, so they don't have
     ** to be included in O_SYNC or fsync
     */
-    journal_begin(&th, inode->i_sb, 1) ;
+    err = journal_begin(&th, inode->i_sb, 1) ;
+    if (err) {
+        reiserfs_write_unlock (inode->i_sb);
+        return;
+    }
     reiserfs_update_sd (&th, inode);
     journal_end(&th, inode->i_sb, 1) ;
     reiserfs_write_unlock(inode->i_sb);
@@ -575,6 +599,18 @@
     {NULL, 0, 0}
 };
 
+static const arg_desc_t error_actions[] = {
+    {"panic", 1 << REISERFS_ERROR_PANIC,
+              (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
+    {"ro-remount", 1 << REISERFS_ERROR_RO,
+              (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
+#ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
+    {"continue", 1 << REISERFS_ERROR_CONTINUE,
+              (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
+#endif
+    {NULL, 0, 0},
+};
+
 int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
 					      There might be broken applications that are
 					      confused by this. Use nolargeio mount option
@@ -725,6 +761,7 @@
 	{"commit",	.arg_required = 'c', .values = NULL},
 	{"usrquota",},
 	{"grpquota",},
+	{"errors", 	.arg_required = 'e', .values = error_actions},
 	{NULL,}
     };
 	
@@ -862,6 +899,7 @@
   unsigned long safe_mask = 0;
   unsigned int commit_max_age = (unsigned int)-1;
   struct reiserfs_journal *journal = SB_JOURNAL(s);
+  int err;
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
@@ -882,6 +920,9 @@
   safe_mask |= 1 << REISERFS_POSIXACL;
   safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
   safe_mask |= 1 << REISERFS_BARRIER_NONE;
+  safe_mask |= 1 << REISERFS_ERROR_RO;
+  safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
+  safe_mask |= 1 << REISERFS_ERROR_PANIC;
 
   /* Update the bitmask, taking care to keep
    * the bits we're not allowed to change here */
@@ -915,7 +956,10 @@
       return 0;
     }
 
-    journal_begin(&th, s, 10) ;
+    err = journal_begin(&th, s, 10) ;
+    if (err)
+        return err;
+
     /* Mounting a rw partition read-only. */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
     set_sb_umount_state( rs, REISERFS_SB(s)->s_mount_state );
@@ -927,11 +971,16 @@
 	return 0; /* We are read-write already */
     }
 
+    if (reiserfs_is_journal_aborted (journal))
+	return journal->j_errno;
+
     handle_data_mode(s, mount_options);
     handle_barrier_mode(s, mount_options);
     REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
-    journal_begin(&th, s, 10) ;
+    err = journal_begin(&th, s, 10) ;
+    if (err)
+	return err;
     
     /* Mount a partition which is read-only, read-write */
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
@@ -944,7 +993,9 @@
   }
   /* this will force a full flush of all journal lists */
   SB_JOURNAL(s)->j_must_wait = 1 ;
-  journal_end(&th, s, 10) ;
+  err = journal_end(&th, s, 10) ;
+  if (err)
+    return err;
   s->s_dirt = 0;
 
   if (!( *mount_flags & MS_RDONLY ) ) {
@@ -1372,8 +1423,9 @@
     }
     s->s_fs_info = sbi;
     memset (sbi, 0, sizeof (struct reiserfs_sb_info));
-    /* Set default values for options: non-aggressive tails */
-    REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
+    /* Set default values for options: non-aggressive tails, RO on errors */
+    REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
+    REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO);
     /* no preallocation minimum, be smart in
        reiserfs_file_write instead */
     REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
@@ -1501,7 +1553,12 @@
     
     if (!(s->s_flags & MS_RDONLY)) {
 
-	journal_begin(&th, s, 1) ;
+	errval = journal_begin(&th, s, 1) ;
+        if (errval) {
+	    dput (s->s_root);
+	    s->s_root = NULL;
+	    goto error;
+        }
 	reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
 
         set_sb_umount_state( rs, REISERFS_ERROR_FS );
@@ -1531,9 +1588,14 @@
 	}
 
 	journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
-	journal_end(&th, s, 1) ;
+	errval = journal_end(&th, s, 1) ;
+	if (errval) {
+	    dput (s->s_root);
+	    s->s_root = NULL;
+	    goto error;
+	}
 
-	if (reiserfs_xattr_init (s, s->s_flags)) {
+	if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
 	    dput (s->s_root);
 	    s->s_root = NULL;
 	    goto error;
@@ -1546,7 +1608,7 @@
 	    reiserfs_info (s, "using 3.5.x disk format\n") ;
 	}
 
-	if (reiserfs_xattr_init (s, s->s_flags)) {
+	if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
 	    dput (s->s_root);
 	    s->s_root = NULL;
 	    goto error;
diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c	2004-11-03 18:29:31 -08:00
+++ b/fs/reiserfs/tail_conversion.c	2004-11-03 18:29:31 -08:00
@@ -34,6 +34,7 @@
 				       that will be inserted in the
 				       tree. */
 
+    BUG_ON (!th->t_trans_id);
 
     REISERFS_SB(sb)->s_direct2indirect ++;
 
@@ -183,6 +184,8 @@
     int tail_len, round_tail_len;
     loff_t pos, pos1; /* position of first byte of the tail */
     struct cpu_key key;
+
+    BUG_ON (!th->t_trans_id);
 
     REISERFS_SB(p_s_sb)->s_indirect2direct ++;
 
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	2004-11-03 18:29:31 -08:00
+++ b/include/linux/reiserfs_fs.h	2004-11-03 18:29:31 -08:00
@@ -1751,6 +1751,7 @@
   void *t_handle_save ;		/* save existing current->journal_info */
   unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
 				   should be displaced from others */
+  struct list_head t_list;
 } ;
 
 /* used to keep track of ordered and tail writes, attached to the buffer
@@ -1810,12 +1811,14 @@
 int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
 int reiserfs_in_journal(struct super_block *p_s_sb, int bmap_nr, int bit_nr, int searchall, b_blocknr_t *next) ;
 int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-
+int journal_join_abort(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
+void reiserfs_journal_abort (struct super_block *sb, int errno);
+void reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...);
 int reiserfs_allocate_list_bitmaps(struct super_block *s, struct reiserfs_list_bitmap *, int) ;
 
 void add_save_link (struct reiserfs_transaction_handle * th,
 					struct inode * inode, int truncate);
-void remove_save_link (struct inode * inode, int truncate);
+int remove_save_link (struct inode * inode, int truncate);
 
 /* objectid.c */
 __u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
@@ -1911,8 +1914,8 @@
 
 void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
 				 struct inode *inode, struct key * key);
-void reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
-void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, 
+int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
+int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
 			   struct  inode * p_s_inode, struct page *, 
 			   int update_timestamps);
 
@@ -1926,7 +1929,7 @@
 void padd_item (char * item, int total_length, int length);
 
 /* inode.c */
-void restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
+int restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
 void reiserfs_read_locked_inode(struct inode * inode, struct reiserfs_iget_args *args) ;
 int reiserfs_find_actor(struct inode * inode, void *p) ;
 int reiserfs_init_locked_inode(struct inode * inode, void *p) ;
@@ -1941,7 +1944,7 @@
 						int connectable );
 
 int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
-void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
+int reiserfs_truncate_file(struct inode *, int update_timestamps) ;
 void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
 		   int type, int key_length);
 void make_le_item_head (struct item_head * ih, const struct cpu_key * key, 
diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
--- a/include/linux/reiserfs_fs_sb.h	2004-11-03 18:29:31 -08:00
+++ b/include/linux/reiserfs_fs_sb.h	2004-11-03 18:29:31 -08:00
@@ -242,14 +242,24 @@
   struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for all the real buffer heads in all 
   										the transactions */
   struct list_head j_prealloc_list;     /* list of inodes which have preallocated blocks */
+  int j_persistent_trans;
   unsigned long j_max_trans_size ;
   unsigned long j_max_batch_size ;
 
+  int j_errno;
+
   /* when flushing ordered buffers, throttle new ordered writers */
   struct work_struct j_work;
   atomic_t j_async_throttle;
 };
 
+enum journal_state_bits {
+    J_WRITERS_BLOCKED = 1,   /* set when new writers not allowed */
+    J_WRITERS_QUEUED,        /* set when log is full due to too many writers */
+    J_ABORTED,               /* set when log is aborted */
+};
+
+
 #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick.  magic string to find desc blocks in the journal */
 
 typedef __u32 (*hashf_t) (const signed char *, int);
@@ -399,6 +409,7 @@
     struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
     struct rw_semaphore xattr_dir_sem;
 
+    int j_errno;
 };
 
 /* Definitions of reiserfs on-disk properties: */
@@ -447,6 +458,11 @@
     REISERFS_BARRIER_NONE,
     REISERFS_BARRIER_FLUSH,
 
+    /* Actions on error */
+    REISERFS_ERROR_PANIC,
+    REISERFS_ERROR_RO,
+    REISERFS_ERROR_CONTINUE,
+
     REISERFS_TEST1,
     REISERFS_TEST2,
     REISERFS_TEST3,
@@ -478,6 +494,10 @@
 #define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
 #define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
 
+#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
+#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
+#define reiserfs_error_continue(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_CONTINUE))
+
 void reiserfs_file_buffer (struct buffer_head * bh, int list);
 extern struct file_system_type reiserfs_fs_type;
 int reiserfs_resize(struct super_block *, unsigned long) ;
@@ -500,6 +520,12 @@
 static inline char *reiserfs_bdevname(struct super_block *s)
 {
         return (s == NULL) ? "Null superblock" : s -> s_id;
+}
+
+#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
+static inline int __reiserfs_is_journal_aborted (struct reiserfs_journal *journal)
+{
+    return test_bit (J_ABORTED, &journal->j_state);
 }
 
 #endif	/* _LINUX_REISER_FS_SB */

Reply to: