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