+Index: linux-2.6.7/include/linux/jbd.h
+===================================================================
+--- linux-2.6.7.orig/include/linux/jbd.h 2004-08-26 17:12:16.000000000 +0400
++++ linux-2.6.7/include/linux/jbd.h 2005-01-19 17:08:33.144512008 +0300
+@@ -826,6 +826,12 @@
+ struct jbd_revoke_table_s *j_revoke_table[2];
+
+ /*
++ * array of bhs for journal_commit_transaction
++ */
++ struct buffer_head **j_wbuf;
++ int j_wbufsize;
++
++ /*
+ * An opaque pointer to fs-private information. ext3 puts its
+ * superblock pointer here
+ */
+Index: linux-2.6.7/include/linux/journal-head.h
+===================================================================
+--- linux-2.6.7.orig/include/linux/journal-head.h 2003-06-24 18:05:26.000000000 +0400
++++ linux-2.6.7/include/linux/journal-head.h 2005-01-19 14:09:59.000000000 +0300
+@@ -80,6 +80,11 @@
+ * [j_list_lock]
+ */
+ struct journal_head *b_cpnext, *b_cpprev;
++
++ /*
++ * counter to track users of the buffer in current transaction
++ */
++ int b_tcount;
+ };
+
+ #endif /* JOURNAL_HEAD_H_INCLUDED */
+Index: linux-2.6.7/fs/jbd/commit.c
+===================================================================
+--- linux-2.6.7.orig/fs/jbd/commit.c 2004-08-26 17:12:40.000000000 +0400
++++ linux-2.6.7/fs/jbd/commit.c 2005-01-19 17:28:32.965111552 +0300
+@@ -103,7 +103,7 @@
+ {
+ transaction_t *commit_transaction;
+ struct journal_head *jh, *new_jh, *descriptor;
+- struct buffer_head *wbuf[64];
++ struct buffer_head **wbuf = journal->j_wbuf;
+ int bufs;
+ int flags;
+ int err;
+@@ -271,7 +283,7 @@
+ BUFFER_TRACE(bh, "start journal writeout");
+ get_bh(bh);
+ wbuf[bufs++] = bh;
+- if (bufs == ARRAY_SIZE(wbuf)) {
++ if (bufs == journal->j_wbufsize) {
+ jbd_debug(2, "submit %d writes\n",
+ bufs);
+ spin_unlock(&journal->j_list_lock);
+@@ -488,7 +500,7 @@
+ /* If there's no more to do, or if the descriptor is full,
+ let the IO rip! */
+
+- if (bufs == ARRAY_SIZE(wbuf) ||
++ if (bufs == journal->j_wbufsize ||
+ commit_transaction->t_buffers == NULL ||
+ space_left < sizeof(journal_block_tag_t) + 16) {
+
+Index: linux-2.6.7/fs/jbd/journal.c
+===================================================================
+--- linux-2.6.7.orig/fs/jbd/journal.c 2005-01-19 12:07:59.000000000 +0300
++++ linux-2.6.7/fs/jbd/journal.c 2005-01-19 17:11:08.589880720 +0300
+@@ -687,6 +687,7 @@
+ {
+ journal_t *journal = journal_init_common();
+ struct buffer_head *bh;
++ int n;
+
+ if (!journal)
+ return NULL;
+@@ -702,6 +703,17 @@
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+
++ /* journal descriptor can store upto n blocks -bzzz */
++ n = journal->j_blocksize / sizeof(journal_block_tag_t);
++ journal->j_wbufsize = n;
++ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
++ if (!journal->j_wbuf) {
++ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
++ __FUNCTION__);
++ kfree(journal);
++ journal = NULL;
++ }
++
+ return journal;
+ }
+
+@@ -717,7 +729,7 @@
+ {
+ struct buffer_head *bh;
+ journal_t *journal = journal_init_common();
+- int err;
++ int err, n;
+ unsigned long blocknr;
+
+ if (!journal)
+@@ -734,6 +746,17 @@
+ journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
+ journal->j_blocksize = inode->i_sb->s_blocksize;
+
++ /* journal descriptor can store upto n blocks -bzzz */
++ n = journal->j_blocksize / sizeof(journal_block_tag_t);
++ journal->j_wbufsize = n;
++ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
++ if (!journal->j_wbuf) {
++ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
++ __FUNCTION__);
++ kfree(journal);
++ return NULL;
++ }
++
+ err = journal_bmap(journal, 0, &blocknr);
+ /* If that failed, give up */
+ if (err) {
+@@ -1107,6 +1130,10 @@
+ iput(journal->j_inode);
+ if (journal->j_revoke)
+ journal_destroy_revoke(journal);
++ if (journal->j_wbuf) {
++ kfree(journal->j_wbuf);
++ journal->j_wbuf = NULL;
++ }
+ kfree(journal);
+ }
+
+Index: linux-2.6.7/fs/jbd/transaction.c
+===================================================================
+--- linux-2.6.7.orig/fs/jbd/transaction.c 2004-08-26 17:12:40.000000000 +0400
++++ linux-2.6.7/fs/jbd/transaction.c 2005-01-19 17:23:30.058160408 +0300
+@@ -611,6 +611,10 @@
+ handle->h_buffer_credits--;
+ if (credits)
+ (*credits)++;
++
++ /* the block's becoming member of the trasaction -bzzz */
++ jh->b_tcount = 0;
++
+ goto done;
+ }
+
+@@ -694,6 +698,9 @@
+ if (credits)
+ (*credits)++;
+
++ /* the block's becoming member of the trasaction -bzzz */
++ jh->b_tcount = 0;
++
+ /*
+ * Finally, if the buffer is not journaled right now, we need to make
+ * sure it doesn't get written to disk before the caller actually
+@@ -723,6 +730,11 @@
+ memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
+ kunmap_atomic(source, KM_USER0);
+ }
++
++ /* track all references to the block to be able to recognize the
++ * situation when the buffer is not part of transaction -bzzz */
++ jh->b_tcount++;
++
+ jbd_unlock_bh_state(bh);
+
+ /*
+@@ -822,11 +834,20 @@
+ jh->b_transaction = transaction;
+ JBUFFER_TRACE(jh, "file as BJ_Reserved");
+ __journal_file_buffer(jh, transaction, BJ_Reserved);
++ jh->b_tcount = 0;
+ } else if (jh->b_transaction == journal->j_committing_transaction) {
+ JBUFFER_TRACE(jh, "set next transaction");
+ jh->b_next_transaction = transaction;
++ jh->b_tcount = 0;
+ }
+ spin_unlock(&journal->j_list_lock);
++
++ /*
++ * track all reference to the block to be able to recognize
++ * the situation when the buffer is not part of transaction -bzzz
++ */
++ jh->b_tcount++;
++
+ jbd_unlock_bh_state(bh);
+
+ /*
+@@ -1178,8 +1199,40 @@
+ void
+ journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits)
+ {
++ journal_t *journal = handle->h_transaction->t_journal;
++ struct journal_head *jh = bh2jh(bh);
++
+ BUFFER_TRACE(bh, "entry");
+- handle->h_buffer_credits += credits;
++
++ /* return credit back to the handle if it was really spent */
++ if (credits)
++ handle->h_buffer_credits++;
++
++ jbd_lock_bh_state(bh);
++ J_ASSERT(jh->b_tcount > 0);
++
++ jh->b_tcount--;
++ if (jh->b_tcount == 0) {
++ /* we can drop it from the transaction -bzzz */
++ J_ASSERT(jh->b_transaction == handle->h_transaction ||
++ jh->b_next_transaction == handle->h_transaction);
++ if (jh->b_transaction == handle->h_transaction) {
++ spin_lock(&journal->j_list_lock);
++ __journal_unfile_buffer(jh);
++ spin_unlock(&journal->j_list_lock);
++ } else if(jh->b_next_transaction) {
++ jh->b_next_transaction = NULL;
++ }
++
++ /*
++ * this was last reference to the block from the current
++ * transaction and we'd like to return credit to the
++ * whole transaction -bzzz
++ */
++ if (!credits)
++ handle->h_buffer_credits++;
++ }
++ jbd_unlock_bh_state(bh);
+ }
+
+ /**
+@@ -1204,6 +1257,7 @@
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ struct journal_head *jh;
++ int drop_reserve = 0;
+
+ BUFFER_TRACE(bh, "entry");
+
+@@ -1227,6 +1281,7 @@
+ J_ASSERT_JH(jh, !jh->b_committed_data);
+
+ __journal_unfile_buffer(jh);
++ drop_reserve = 1;
+
+ /*
+ * We are no longer going to journal this buffer.
+@@ -1249,7 +1304,7 @@
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ __bforget(bh);
+- return;
++ goto drop;
+ }
+ }
+ } else if (jh->b_transaction) {
+@@ -1264,6 +1319,7 @@
+ if (jh->b_next_transaction) {
+ J_ASSERT(jh->b_next_transaction == transaction);
+ jh->b_next_transaction = NULL;
++ drop_reserve = 1;
+ }
+ }
+
+@@ -1271,6 +1327,15 @@
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ __brelse(bh);
++
++drop:
++ if (drop_reserve) {
++ /* no need to reserve log space for this block -bzzz */
++ spin_lock(&transaction->t_handle_lock);
++ transaction->t_outstanding_credits--;
++ spin_unlock(&transaction->t_handle_lock);
++ }
++
+ return;
+ }
+