Commit 28a4dd1b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] JBD: additional transaction shutdown locking

Plug a conceivable race with the freeing up of trasnactions, and add some
more debug checks.
parent 833f3d15
...@@ -538,7 +538,8 @@ void __journal_remove_checkpoint(struct journal_head *jh) ...@@ -538,7 +538,8 @@ void __journal_remove_checkpoint(struct journal_head *jh)
* checkpoint list is empty, the transaction obviously cannot be * checkpoint list is empty, the transaction obviously cannot be
* dropped! * dropped!
* *
* AKPM2: locking here around j_committing_transaction is a bit flakey. * The locking here around j_committing_transaction is a bit sleazy.
* See the comment at the end of journal_commit_transaction().
*/ */
if (transaction == journal->j_committing_transaction) { if (transaction == journal->j_committing_transaction) {
JBUFFER_TRACE(jh, "belongs to committing transaction"); JBUFFER_TRACE(jh, "belongs to committing transaction");
...@@ -608,6 +609,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) ...@@ -608,6 +609,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
journal->j_checkpoint_transactions = NULL; journal->j_checkpoint_transactions = NULL;
} }
J_ASSERT(transaction->t_state == T_FINISHED);
J_ASSERT(transaction->t_buffers == NULL); J_ASSERT(transaction->t_buffers == NULL);
J_ASSERT(transaction->t_sync_datalist == NULL); J_ASSERT(transaction->t_sync_datalist == NULL);
J_ASSERT(transaction->t_forget == NULL); J_ASSERT(transaction->t_forget == NULL);
...@@ -617,10 +619,9 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) ...@@ -617,10 +619,9 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
J_ASSERT(transaction->t_checkpoint_list == NULL); J_ASSERT(transaction->t_checkpoint_list == NULL);
J_ASSERT(transaction->t_updates == 0); J_ASSERT(transaction->t_updates == 0);
J_ASSERT(list_empty(&transaction->t_jcb)); J_ASSERT(list_empty(&transaction->t_jcb));
J_ASSERT(journal->j_committing_transaction != transaction); J_ASSERT(journal->j_committing_transaction != transaction);
J_ASSERT(journal->j_running_transaction != transaction);
jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
kfree(transaction); kfree(transaction);
} }
...@@ -704,14 +704,20 @@ void journal_commit_transaction(journal_t *journal) ...@@ -704,14 +704,20 @@ void journal_commit_transaction(journal_t *journal)
J_ASSERT(commit_transaction->t_state == T_COMMIT); J_ASSERT(commit_transaction->t_state == T_COMMIT);
/*
* This is a bit sleazy. We borrow j_list_lock to protect
* journal->j_committing_transaction in __journal_remove_checkpoint.
* Really, __jornal_remove_checkpoint should be using j_state_lock but
* it's a bit hassle to hold that across __journal_remove_checkpoint
*/
spin_lock(&journal->j_state_lock); spin_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
commit_transaction->t_state = T_FINISHED; commit_transaction->t_state = T_FINISHED;
J_ASSERT(commit_transaction == journal->j_committing_transaction); J_ASSERT(commit_transaction == journal->j_committing_transaction);
journal->j_commit_sequence = commit_transaction->t_tid; journal->j_commit_sequence = commit_transaction->t_tid;
journal->j_committing_transaction = NULL; journal->j_committing_transaction = NULL;
spin_unlock(&journal->j_state_lock); spin_unlock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock);
if (commit_transaction->t_checkpoint_list == NULL) { if (commit_transaction->t_checkpoint_list == NULL) {
__journal_drop_transaction(journal, commit_transaction); __journal_drop_transaction(journal, commit_transaction);
} else { } else {
......
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