Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f5a7a6b0d9b6af7d46124ed3f6b3995225cb62d0
Commit:     f5a7a6b0d9b6af7d46124ed3f6b3995225cb62d0
Parent:     36df53f4a3e445175fc1e9d7f433599482ec6d7f
Author:     Jan Kara <[EMAIL PROTECTED]>
AuthorDate: Mon Jan 28 23:58:27 2008 -0500
Committer:  Theodore Ts'o <[EMAIL PROTECTED]>
CommitDate: Mon Jan 28 23:58:27 2008 -0500

    jbd2: Fix assertion failure in fs/jbd2/checkpoint.c
    
    Before we start committing a transaction, we call
    __journal_clean_checkpoint_list() to cleanup transaction's written-back
    buffers.
    
    If this call happens to remove all of them (and there were already some
    buffers), __journal_remove_checkpoint() will decide to free the transaction
    because it isn't (yet) a committing transaction and soon we fail some
    assertion - the transaction really isn't ready to be freed :).
    
    We change the check in __journal_remove_checkpoint() to free only a
    transaction in T_FINISHED state.  The locking there is subtle though (as
    everywhere in JBD ;().  We use j_list_lock to protect the check and a
    subsequent call to __journal_drop_transaction() and do the same in the end
    of journal_commit_transaction() which is the only place where a transaction
    can get to T_FINISHED state.
    
    Probably I'm too paranoid here and such locking is not really necessary -
    checkpoint lists are processed only from log_do_checkpoint() where a
    transaction must be already committed to be processed or from
    __journal_clean_checkpoint_list() where kjournald itself calls it and thus
    transaction cannot change state either.  Better be safe if something
    changes in future...
    
    Signed-off-by: Jan Kara <[EMAIL PROTECTED]>
    Cc: <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
---
 fs/jbd2/checkpoint.c |   12 ++++++------
 fs/jbd2/commit.c     |    8 ++++----
 include/linux/jbd2.h |    2 ++
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 3fccde7..7e958c8 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -602,15 +602,15 @@ int __jbd2_journal_remove_checkpoint(struct journal_head 
*jh)
 
        /*
         * There is one special case to worry about: if we have just pulled the
-        * buffer off a committing transaction's forget list, then even if the
-        * checkpoint list is empty, the transaction obviously cannot be
-        * dropped!
+        * buffer off a running or committing transaction's checkpoing list,
+        * then even if the checkpoint list is empty, the transaction obviously
+        * cannot be dropped!
         *
-        * The locking here around j_committing_transaction is a bit sleazy.
+        * The locking here around t_state is a bit sleazy.
         * See the comment at the end of jbd2_journal_commit_transaction().
         */
-       if (transaction == journal->j_committing_transaction) {
-               JBUFFER_TRACE(jh, "belongs to committing transaction");
+       if (transaction->t_state != T_FINISHED) {
+               JBUFFER_TRACE(jh, "belongs to running/committing transaction");
                goto out;
        }
 
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 6986f33..39b5cee 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -867,10 +867,10 @@ restart_loop:
        }
        spin_unlock(&journal->j_list_lock);
        /*
-        * This is a bit sleazy.  We borrow j_list_lock to protect
-        * journal->j_committing_transaction in 
__jbd2_journal_remove_checkpoint.
-        * Really, __jbd2_journal_remove_checkpoint should be using 
j_state_lock but
-        * it's a bit hassle to hold that across 
__jbd2_journal_remove_checkpoint
+        * This is a bit sleazy.  We use j_list_lock to protect transition
+        * of a transaction into T_FINISHED state and calling
+        * __jbd2_journal_drop_transaction(). Otherwise we could race with
+        * other checkpointing code processing the transaction...
         */
        spin_lock(&journal->j_state_lock);
        spin_lock(&journal->j_list_lock);
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index d5f7cff..d861ffd 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -442,6 +442,8 @@ struct transaction_s
        /*
         * Transaction's current state
         * [no locking - only kjournald2 alters this]
+        * [j_list_lock] guards transition of a transaction into T_FINISHED
+        * state and subsequent call of __jbd2_journal_drop_transaction()
         * FIXME: needs barriers
         * KLUDGE: [use j_state_lock]
         */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to