r2021 - in trunk/kernel/source: kernel-source-2.6.8-2.6.8/debian kernel-source-2.6.8-2.6.8/debian/patches kernel-source-2.6.8-2.6.8/debian/patches/series kernel-source-2.6.9-2.6.9/debian kernel-source-2.6.9-2.6.9/debian/patches kernel-source-2.6.9-2.6.9/debian/patches/series

Andres Salomon dilinger-guest@haydn.debian.org
Thu, 23 Dec 2004 00:10:51 -0700


Author: dilinger-guest
Date: 2004-12-23 00:10:30 -0700 (Thu, 23 Dec 2004)
New Revision: 2021

Added:
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks-2.dpatch
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks-2.dpatch
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks.patch
Modified:
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-11
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog
   trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-4
Log:
  * Add some additional reiserfs locking and error handling fixes, in
    hopes of lessening reports of reiser corruption (Andres Salomon).



Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2004-12-23 07:10:30 UTC (rev 2021)
@@ -42,6 +42,9 @@
     https://lists.netfilter.org/pipermail/netfilter-devel/2004-December/017677.html
     Thanks to Fabio M. Di Nitto for point this out (Andres Salomon).
 
+  * Add some additional reiserfs locking and error handling fixes, in
+    hopes of lessening reports of reiser corruption (Andres Salomon).
+
  -- dann frazier <dannf@debian.org>  Fri, 03 Dec 2004 00:13:41 -0700
 
 kernel-source-2.6.8 (2.6.8-10) unstable; urgency=high

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks-2.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks-2.dpatch	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks-2.dpatch	2004-12-23 07:10:30 UTC (rev 2021)
@@ -0,0 +1,47 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: ReiserFS: Fix several missing reiserfs_write_unlock calls
+## DP: Patch author: Jeff Mahoney <jeffm@novell.com>
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2004/10/18 23:07:58-07:00 jeffm@novell.com 
+#   [PATCH] ReiserFS: Fix several missing reiserfs_write_unlock calls
+#   
+#   This patch fixes several missing reiserfs_write_unlock() calls on error
+#   paths not introduced by reiserfs-io-error-handling.diff
+#   
+#   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/namei.c
+#   2004/10/18 22:26:49-07:00 jeffm@novell.com +2 -0
+#   ReiserFS: Fix several missing reiserfs_write_unlock calls
+# 
+diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
+--- a/fs/reiserfs/namei.c	2004-12-22 22:33:49 -08:00
++++ b/fs/reiserfs/namei.c	2004-12-22 22:33:49 -08:00
+@@ -341,6 +341,7 @@
+             REISERFS_SB(dir->i_sb)->priv_root &&
+             REISERFS_SB(dir->i_sb)->priv_root->d_inode &&
+ 	    de.de_objectid == le32_to_cpu (INODE_PKEY(REISERFS_SB(dir->i_sb)->priv_root->d_inode)->k_objectid)) {
++	  reiserfs_write_unlock (dir->i_sb);
+ 	  return ERR_PTR (-EACCES);
+ 	}
+ 
+@@ -1091,6 +1092,7 @@
+ 	return -EMLINK;
+     }
+     if (inode->i_nlink == 0) {
++        reiserfs_write_unlock(dir->i_sb);
+         return -ENOENT;
+     }
+ 

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks.dpatch	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/reiserfs-sucks.dpatch	2004-12-23 07:10:30 UTC (rev 2021)
@@ -0,0 +1,2997 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: ReiserFS: Add I/O error handling to journal operations
+## DP: Patch author: Jeff Mahoney <jeffm@novell.com>
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# 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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/bitmap.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/dir.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/file.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/inode.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/journal.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/namei.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/objectid.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/prints.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/resize.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/stree.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/super.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/tail_conversion.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/include/linux/reiserfs_fs.h	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/include/linux/reiserfs_fs_sb.h	2004-12-22 22:53:54 -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 */

Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-11
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-11	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-11	2004-12-23 07:10:30 UTC (rev 2021)
@@ -11,3 +11,5 @@
 + binfmt-huge-vma-dos2.dpatch
 + arch-x86_64-sys32_quotactl-overflow.dpatch
 + ip-conntrack-ftp-leak.dpatch 
++ reiserfs-sucks.patch
++ reiserfs-sucks-2.patch

Modified: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/changelog	2004-12-23 07:10:30 UTC (rev 2021)
@@ -47,6 +47,9 @@
     https://lists.netfilter.org/pipermail/netfilter-devel/2004-December/017677.html
     Thanks to Fabio M. Di Nitto for this (Andres Salomon).
 
+  * Add some additional reiserfs locking and error handling fixes, in
+    hopes of lessening reports of reiser corruption (Andres Salomon).
+
  -- dann frazier <dannf@debian.org>  Fri, 03 Dec 2004 09:26:52 -0700
 
 kernel-source-2.6.9 (2.6.9-3) unstable; urgency=low

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks-2.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks-2.dpatch	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks-2.dpatch	2004-12-23 07:10:30 UTC (rev 2021)
@@ -0,0 +1,47 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: ReiserFS: Fix several missing reiserfs_write_unlock calls
+## DP: Patch author: Jeff Mahoney <jeffm@novell.com>
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2004/10/18 23:07:58-07:00 jeffm@novell.com 
+#   [PATCH] ReiserFS: Fix several missing reiserfs_write_unlock calls
+#   
+#   This patch fixes several missing reiserfs_write_unlock() calls on error
+#   paths not introduced by reiserfs-io-error-handling.diff
+#   
+#   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/namei.c
+#   2004/10/18 22:26:49-07:00 jeffm@novell.com +2 -0
+#   ReiserFS: Fix several missing reiserfs_write_unlock calls
+# 
+diff -Nru a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
+--- a/fs/reiserfs/namei.c	2004-12-22 22:33:49 -08:00
++++ b/fs/reiserfs/namei.c	2004-12-22 22:33:49 -08:00
+@@ -341,6 +341,7 @@
+             REISERFS_SB(dir->i_sb)->priv_root &&
+             REISERFS_SB(dir->i_sb)->priv_root->d_inode &&
+ 	    de.de_objectid == le32_to_cpu (INODE_PKEY(REISERFS_SB(dir->i_sb)->priv_root->d_inode)->k_objectid)) {
++	  reiserfs_write_unlock (dir->i_sb);
+ 	  return ERR_PTR (-EACCES);
+ 	}
+ 
+@@ -1091,6 +1092,7 @@
+ 	return -EMLINK;
+     }
+     if (inode->i_nlink == 0) {
++        reiserfs_write_unlock(dir->i_sb);
+         return -ENOENT;
+     }
+ 

Added: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks.patch	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/reiserfs-sucks.patch	2004-12-23 07:10:30 UTC (rev 2021)
@@ -0,0 +1,2997 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: ReiserFS: Add I/O error handling to journal operations
+## DP: Patch author: Jeff Mahoney <jeffm@novell.com>
+## DP: Upstream status: backported
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# 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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/bitmap.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/dir.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/file.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/inode.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/journal.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/namei.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/objectid.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/prints.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/resize.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/stree.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/super.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/fs/reiserfs/tail_conversion.c	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/include/linux/reiserfs_fs.h	2004-12-22 22:53:54 -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-12-22 22:53:54 -08:00
++++ b/include/linux/reiserfs_fs_sb.h	2004-12-22 22:53:54 -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 */

Modified: trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-4
===================================================================
--- trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-4	2004-12-23 06:26:32 UTC (rev 2020)
+++ trunk/kernel/source/kernel-source-2.6.9-2.6.9/debian/patches/series/2.6.9-4	2004-12-23 07:10:30 UTC (rev 2021)
@@ -13,3 +13,5 @@
 + binfmt-huge-vma-dos2.dpatch
 + arch-x86_64-sys32_quotactl-overflow.dpatch
 + ip-conntrack-ftp-leak.dpatch
++ reiserfs-sucks.patch
++ reiserfs-sucks-2.patch