<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Chris Mason &lt;mason@suse.com&gt;

reiserfs support for nested transactions.  This originally came from Peter
Braam for 2.4.x and was ported forward by Jeff Mahoney.


---

 25-akpm/fs/reiserfs/inode.c            |    4 +
 25-akpm/fs/reiserfs/journal.c          |   78 +++++++++++++++++++++++++++++++--
 25-akpm/fs/reiserfs/namei.c            |    1 
 25-akpm/include/linux/reiserfs_fs_sb.h |   12 +++--
 4 files changed, 86 insertions(+), 9 deletions(-)

diff -puN fs/reiserfs/inode.c~reiserfs-nesting-02 fs/reiserfs/inode.c
--- 25/fs/reiserfs/inode.c~reiserfs-nesting-02	Wed Mar 24 15:14:28 2004
+++ 25-akpm/fs/reiserfs/inode.c	Wed Mar 24 15:14:28 2004
@@ -206,6 +206,10 @@ static int file_capable (struct inode * 
   struct super_block *s = th-&gt;t_super ;
   int len = th-&gt;t_blocks_allocated ;
 
+  /* we cannot restart while nested */
+  if (th-&gt;t_refcount &gt; 1) {
+      return  ;
+  }
   pathrelse(path) ;
   reiserfs_update_sd(th, inode) ;
   journal_end(th, s, len) ;
diff -puN fs/reiserfs/journal.c~reiserfs-nesting-02 fs/reiserfs/journal.c
--- 25/fs/reiserfs/journal.c~reiserfs-nesting-02	Wed Mar 24 15:14:28 2004
+++ 25-akpm/fs/reiserfs/journal.c	Wed Mar 24 15:14:28 2004
@@ -2157,6 +2157,9 @@ int journal_transaction_should_end(struc
   time_t now = get_seconds() ;
   if (reiserfs_dont_log(th-&gt;t_super)) 
     return 0 ;
+  /* cannot restart while nested */
+  if (th-&gt;t_refcount &gt; 1)
+    return 0 ;
   if ( SB_JOURNAL(th-&gt;t_super)-&gt;j_must_wait &gt; 0 ||
        (SB_JOURNAL(th-&gt;t_super)-&gt;j_len_alloc + new_alloc) &gt;= SB_JOURNAL_MAX_BATCH(th-&gt;t_super) || 
        atomic_read(&amp;(SB_JOURNAL(th-&gt;t_super)-&gt;j_jlock)) ||
@@ -2212,6 +2215,9 @@ static int do_journal_begin_r(struct rei
     return 0 ;
   }
   PROC_INFO_INC( p_s_sb, journal.journal_being );
+  /* set here for journal_join */
+  th-&gt;t_refcount = 1;
+  th-&gt;t_super = p_s_sb ;
 
 relock:
   lock_journal(p_s_sb) ;
@@ -2268,9 +2274,7 @@ relock:
   SB_JOURNAL(p_s_sb)-&gt;j_len_alloc += nblocks ;
   th-&gt;t_blocks_logged = 0 ;
   th-&gt;t_blocks_allocated = nblocks ;
-  th-&gt;t_super = p_s_sb ;
   th-&gt;t_trans_id = SB_JOURNAL(p_s_sb)-&gt;j_trans_id ;
-  th-&gt;t_caller = "Unknown" ;
   unlock_journal(p_s_sb) ;
   p_s_sb-&gt;s_dirt = 1; 
   return 0 ;
@@ -2278,11 +2282,47 @@ relock:
 
 
 static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
+  struct reiserfs_transaction_handle *cur_th = current-&gt;journal_info;
+
+  /* this keeps do_journal_end from NULLing out the current-&gt;journal_info
+  ** pointer
+  */
+  th-&gt;t_handle_save = cur_th ;
+  if (cur_th &amp;&amp; cur_th-&gt;t_refcount &gt; 1) {
+      BUG() ;
+  }
   return do_journal_begin_r(th, p_s_sb, nblocks, 1) ;
 }
 
 int journal_begin(struct reiserfs_transaction_handle *th, struct super_block  * p_s_sb, unsigned long nblocks) {
-  return do_journal_begin_r(th, p_s_sb, nblocks, 0) ;
+    struct reiserfs_transaction_handle *cur_th = current-&gt;journal_info ;
+    int ret ;
+
+    th-&gt;t_handle_save = NULL ;
+    if (cur_th) {
+	/* we are nesting into the current transaction */
+	if (cur_th-&gt;t_super == p_s_sb) {
+	      cur_th-&gt;t_refcount++ ;
+	      memcpy(th, cur_th, sizeof(*th));
+	      if (th-&gt;t_refcount &lt;= 1)
+		      printk("BAD: refcount &lt;= 1, but journal_info != 0\n");
+	      return 0;
+	} else {
+	    /* we've ended up with a handle from a different filesystem.
+	    ** save it and restore on journal_end.  This should never
+	    ** really happen...
+	    */
+	    reiserfs_warning("clm-2100: nesting info a different FS\n") ;
+	    th-&gt;t_handle_save = current-&gt;journal_info ;
+	    current-&gt;journal_info = th;
+	}
+    } else {
+	current-&gt;journal_info = th;
+    }
+    ret = do_journal_begin_r(th, p_s_sb, nblocks, 0) ;
+    if (current-&gt;journal_info != th)
+        BUG() ;
+    return ret ;
 }
 
 /* not used at all */
@@ -2422,7 +2462,26 @@ int journal_mark_dirty_nolog(struct reis
 }
 
 int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
-  return do_journal_end(th, p_s_sb, nblocks, 0) ;
+  if (!current-&gt;journal_info &amp;&amp; th-&gt;t_refcount &gt; 1)
+    printk("REISER-NESTING: th NULL, refcount %d\n", th-&gt;t_refcount);
+  if (th-&gt;t_refcount &gt; 1) {
+    struct reiserfs_transaction_handle *cur_th = current-&gt;journal_info ;
+
+    /* we aren't allowed to close a nested transaction on a different
+    ** filesystem from the one in the task struct
+    */
+    if (cur_th-&gt;t_super != th-&gt;t_super)
+      BUG() ;
+
+    th-&gt;t_refcount--;
+    if (th != cur_th) {
+      memcpy(current-&gt;journal_info, th, sizeof(*th));
+      th-&gt;t_trans_id = 0;
+    }
+    return 0;
+  } else {
+    return do_journal_end(th, p_s_sb, nblocks, 0) ;
+  }
 }
 
 /* removes from the current transaction, relsing and descrementing any counters.  
@@ -2520,6 +2579,10 @@ static int can_dirty(struct reiserfs_jou
 */
 int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
 
+  /* you can sync while nested, very, very bad */
+  if (th-&gt;t_refcount &gt; 1) {
+    BUG() ;
+  }
   if (SB_JOURNAL(p_s_sb)-&gt;j_len == 0) {
     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)) ;
@@ -2901,6 +2964,10 @@ static int do_journal_end(struct reiserf
   struct reiserfs_super_block *rs ; 
   int trans_half ;
 
+  if (th-&gt;t_refcount &gt; 1)
+    BUG() ;
+
+  current-&gt;journal_info = th-&gt;t_handle_save;
   if (reiserfs_dont_log(th-&gt;t_super)) {
     return 0 ;
   }
@@ -2938,8 +3005,11 @@ static int do_journal_end(struct reiserf
   }
 
 #ifdef REISERFS_PREALLOCATE
+  /* quota ops might need to nest, setup the journal_info pointer for them */
+  current-&gt;journal_info = th ;
   reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into
 				      * the transaction */
+  current-&gt;journal_info = th-&gt;t_handle_save ;
 #endif
   
   rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
diff -puN fs/reiserfs/namei.c~reiserfs-nesting-02 fs/reiserfs/namei.c
--- 25/fs/reiserfs/namei.c~reiserfs-nesting-02	Wed Mar 24 15:14:28 2004
+++ 25-akpm/fs/reiserfs/namei.c	Wed Mar 24 15:14:28 2004
@@ -575,7 +575,6 @@ static int reiserfs_create (struct inode
 
     reiserfs_write_lock(dir-&gt;i_sb);
     journal_begin(&amp;th, dir-&gt;i_sb, jbegin_count) ;
-    th.t_caller = "create" ;
     retval = reiserfs_new_inode (&amp;th, dir, mode, 0, 0/*i_size*/, dentry, inode);
     if (retval) {
         goto out_failed;
diff -puN include/linux/reiserfs_fs_sb.h~reiserfs-nesting-02 include/linux/reiserfs_fs_sb.h
--- 25/include/linux/reiserfs_fs_sb.h~reiserfs-nesting-02	Wed Mar 24 15:14:28 2004
+++ 25-akpm/include/linux/reiserfs_fs_sb.h	Wed Mar 24 15:14:28 2004
@@ -157,13 +157,17 @@ struct reiserfs_list_bitmap {
 ** transaction handle which is passed around for all journal calls
 */
 struct reiserfs_transaction_handle {
-				/* ifdef it. -Hans */
-  char *t_caller ;              /* debugging use */
+  struct super_block *t_super ; /* super for this FS when journal_begin was
+				   called. saves calls to reiserfs_get_super
+				   also used by nested transactions to make
+				   sure they are nesting on the right FS
+				   _must_ be first in the handle
+				*/
+  int t_refcount;
   int t_blocks_logged ;         /* number of blocks this writer has logged */
   int t_blocks_allocated ;      /* number of blocks this writer allocated */
   unsigned long t_trans_id ;    /* sanity check, equals the current trans id */
-  struct super_block *t_super ; /* super for this FS when journal_begin was 
-                                   called. saves calls to reiserfs_get_super */
+  void *t_handle_save ;		/* save existing current-&gt;journal_info */
   int displace_new_blocks:1;	/* if new block allocation occurres, that block
 				   should be displaced from others */
 

_
</pre></body></html>