Commit 7a10b433 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] reiserfs: support for nested transactions

From: Chris Mason <mason@suse.com>

reiserfs support for nested transactions.  This originally came from Peter
Braam for 2.4.x and was ported forward by Jeff Mahoney.
parent 545b0840
...@@ -206,6 +206,10 @@ static int file_capable (struct inode * inode, long block) ...@@ -206,6 +206,10 @@ static int file_capable (struct inode * inode, long block)
struct super_block *s = th->t_super ; struct super_block *s = th->t_super ;
int len = th->t_blocks_allocated ; int len = th->t_blocks_allocated ;
/* we cannot restart while nested */
if (th->t_refcount > 1) {
return ;
}
pathrelse(path) ; pathrelse(path) ;
reiserfs_update_sd(th, inode) ; reiserfs_update_sd(th, inode) ;
journal_end(th, s, len) ; journal_end(th, s, len) ;
......
...@@ -2157,6 +2157,9 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th, int n ...@@ -2157,6 +2157,9 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th, int n
time_t now = get_seconds() ; time_t now = get_seconds() ;
if (reiserfs_dont_log(th->t_super)) if (reiserfs_dont_log(th->t_super))
return 0 ; return 0 ;
/* cannot restart while nested */
if (th->t_refcount > 1)
return 0 ;
if ( SB_JOURNAL(th->t_super)->j_must_wait > 0 || if ( SB_JOURNAL(th->t_super)->j_must_wait > 0 ||
(SB_JOURNAL(th->t_super)->j_len_alloc + new_alloc) >= SB_JOURNAL_MAX_BATCH(th->t_super) || (SB_JOURNAL(th->t_super)->j_len_alloc + new_alloc) >= SB_JOURNAL_MAX_BATCH(th->t_super) ||
atomic_read(&(SB_JOURNAL(th->t_super)->j_jlock)) || atomic_read(&(SB_JOURNAL(th->t_super)->j_jlock)) ||
...@@ -2212,6 +2215,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup ...@@ -2212,6 +2215,9 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
return 0 ; return 0 ;
} }
PROC_INFO_INC( p_s_sb, journal.journal_being ); PROC_INFO_INC( p_s_sb, journal.journal_being );
/* set here for journal_join */
th->t_refcount = 1;
th->t_super = p_s_sb ;
relock: relock:
lock_journal(p_s_sb) ; lock_journal(p_s_sb) ;
...@@ -2268,9 +2274,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup ...@@ -2268,9 +2274,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
SB_JOURNAL(p_s_sb)->j_len_alloc += nblocks ; SB_JOURNAL(p_s_sb)->j_len_alloc += nblocks ;
th->t_blocks_logged = 0 ; th->t_blocks_logged = 0 ;
th->t_blocks_allocated = nblocks ; th->t_blocks_allocated = nblocks ;
th->t_super = p_s_sb ;
th->t_trans_id = SB_JOURNAL(p_s_sb)->j_trans_id ; th->t_trans_id = SB_JOURNAL(p_s_sb)->j_trans_id ;
th->t_caller = "Unknown" ;
unlock_journal(p_s_sb) ; unlock_journal(p_s_sb) ;
p_s_sb->s_dirt = 1; p_s_sb->s_dirt = 1;
return 0 ; return 0 ;
...@@ -2278,11 +2282,47 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup ...@@ -2278,11 +2282,47 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup
static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { 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->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, 1) ; 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) { 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->journal_info ;
int ret ;
th->t_handle_save = NULL ;
if (cur_th) {
/* we are nesting into the current transaction */
if (cur_th->t_super == p_s_sb) {
cur_th->t_refcount++ ;
memcpy(th, cur_th, sizeof(*th));
if (th->t_refcount <= 1)
printk("BAD: refcount <= 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->t_handle_save = current->journal_info ;
current->journal_info = th;
}
} else {
current->journal_info = th;
}
ret = do_journal_begin_r(th, p_s_sb, nblocks, 0) ;
if (current->journal_info != th)
BUG() ;
return ret ;
} }
/* not used at all */ /* not used at all */
...@@ -2422,7 +2462,26 @@ int journal_mark_dirty_nolog(struct reiserfs_transaction_handle *th, struct supe ...@@ -2422,7 +2462,26 @@ int journal_mark_dirty_nolog(struct reiserfs_transaction_handle *th, struct supe
} }
int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { 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->journal_info && th->t_refcount > 1)
printk("REISER-NESTING: th NULL, refcount %d\n", th->t_refcount);
if (th->t_refcount > 1) {
struct reiserfs_transaction_handle *cur_th = current->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->t_super != th->t_super)
BUG() ;
th->t_refcount--;
if (th != cur_th) {
memcpy(current->journal_info, th, sizeof(*th));
th->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. /* removes from the current transaction, relsing and descrementing any counters.
...@@ -2520,6 +2579,10 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) { ...@@ -2520,6 +2579,10 @@ static int can_dirty(struct reiserfs_journal_cnode *cn) {
*/ */
int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) { 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->t_refcount > 1) {
BUG() ;
}
if (SB_JOURNAL(p_s_sb)->j_len == 0) { if (SB_JOURNAL(p_s_sb)->j_len == 0) {
reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(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)) ; journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
...@@ -2901,6 +2964,10 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b ...@@ -2901,6 +2964,10 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
struct reiserfs_super_block *rs ; struct reiserfs_super_block *rs ;
int trans_half ; int trans_half ;
if (th->t_refcount > 1)
BUG() ;
current->journal_info = th->t_handle_save;
if (reiserfs_dont_log(th->t_super)) { if (reiserfs_dont_log(th->t_super)) {
return 0 ; return 0 ;
} }
...@@ -2938,8 +3005,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b ...@@ -2938,8 +3005,11 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_b
} }
#ifdef REISERFS_PREALLOCATE #ifdef REISERFS_PREALLOCATE
/* quota ops might need to nest, setup the journal_info pointer for them */
current->journal_info = th ;
reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into
* the transaction */ * the transaction */
current->journal_info = th->t_handle_save ;
#endif #endif
rs = SB_DISK_SUPER_BLOCK(p_s_sb) ; rs = SB_DISK_SUPER_BLOCK(p_s_sb) ;
......
...@@ -575,7 +575,6 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode, ...@@ -575,7 +575,6 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
reiserfs_write_lock(dir->i_sb); reiserfs_write_lock(dir->i_sb);
journal_begin(&th, dir->i_sb, jbegin_count) ; journal_begin(&th, dir->i_sb, jbegin_count) ;
th.t_caller = "create" ;
retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode); retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
if (retval) { if (retval) {
goto out_failed; goto out_failed;
......
...@@ -157,13 +157,17 @@ struct reiserfs_list_bitmap { ...@@ -157,13 +157,17 @@ struct reiserfs_list_bitmap {
** transaction handle which is passed around for all journal calls ** transaction handle which is passed around for all journal calls
*/ */
struct reiserfs_transaction_handle { struct reiserfs_transaction_handle {
/* ifdef it. -Hans */ struct super_block *t_super ; /* super for this FS when journal_begin was
char *t_caller ; /* debugging use */ 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_logged ; /* number of blocks this writer has logged */
int t_blocks_allocated ; /* number of blocks this writer allocated */ int t_blocks_allocated ; /* number of blocks this writer allocated */
unsigned long t_trans_id ; /* sanity check, equals the current trans id */ 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 void *t_handle_save ; /* save existing current->journal_info */
called. saves calls to reiserfs_get_super */
int displace_new_blocks:1; /* if new block allocation occurres, that block int displace_new_blocks:1; /* if new block allocation occurres, that block
should be displaced from others */ should be displaced from others */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment