The logic in there can leak transactions if a race happens. And I think it can cause j_running_transaction and j_committing_transaction to point at the same thing. Fix that up. fs/jbd/transaction.c | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diff -puN fs/jbd/transaction.c~jbd-560-transaction-leak-fix fs/jbd/transaction.c --- 25/fs/jbd/transaction.c~jbd-560-transaction-leak-fix 2003-05-26 21:20:48.000000000 -0700 +++ 25-akpm/fs/jbd/transaction.c 2003-05-26 21:24:14.000000000 -0700 @@ -87,20 +87,24 @@ static int start_this_handle(journal_t * int needed; int nblocks = handle->h_buffer_credits; transaction_t *new_transaction = NULL; + int ret; if (nblocks > journal->j_max_transaction_buffers) { printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", current->comm, nblocks, journal->j_max_transaction_buffers); - return -ENOSPC; + ret = -ENOSPC; + goto out; } alloc_transaction: if (!journal->j_running_transaction) { new_transaction = jbd_kmalloc(sizeof(*new_transaction), GFP_NOFS); - if (!new_transaction) - return -ENOMEM; + if (!new_transaction) { + ret = -ENOMEM; + goto out; + } memset(new_transaction, 0, sizeof(*new_transaction)); } @@ -116,7 +120,8 @@ repeat: if (is_journal_aborted(journal) || (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { spin_unlock(&journal->j_state_lock); - return -EROFS; + ret = -EROFS; + goto out; } /* Wait on the journal's transaction barrier if necessary */ @@ -134,6 +139,7 @@ repeat_locked: goto alloc_transaction; } get_transaction(journal, new_transaction); + new_transaction = NULL; } /* @@@ Error? */ @@ -230,6 +236,9 @@ repeat_locked: __log_space_left(journal)); spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); +out: + if (new_transaction) + kfree(new_transaction); return 0; } _