Commit 2ab7407c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] JBD: fix race between journal_commit_transaction and

start_this_handle() can decide to add this handle to a transaction, but
kjournald then moves the handle into commit phase.

Extend the coverage of j_state_lock so that start_this_transaction()'s
examination of journal->j_state is atomic wrt journal_commit_transaction().
parent 7c221915
...@@ -68,6 +68,14 @@ void journal_commit_transaction(journal_t *journal) ...@@ -68,6 +68,14 @@ void journal_commit_transaction(journal_t *journal)
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
#endif #endif
/* Do we need to erase the effects of a prior journal_flush? */
if (journal->j_flags & JFS_FLUSHED) {
jbd_debug(3, "super block updated\n");
journal_update_superblock(journal, 1);
} else {
jbd_debug(3, "superblock not updated\n");
}
J_ASSERT(journal->j_running_transaction != NULL); J_ASSERT(journal->j_running_transaction != NULL);
J_ASSERT(journal->j_committing_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL);
...@@ -77,17 +85,20 @@ void journal_commit_transaction(journal_t *journal) ...@@ -77,17 +85,20 @@ void journal_commit_transaction(journal_t *journal)
jbd_debug(1, "JBD: starting commit of transaction %d\n", jbd_debug(1, "JBD: starting commit of transaction %d\n",
commit_transaction->t_tid); commit_transaction->t_tid);
spin_lock(&journal->j_state_lock);
commit_transaction->t_state = T_LOCKED; commit_transaction->t_state = T_LOCKED;
spin_lock(&commit_transaction->t_handle_lock); spin_lock(&commit_transaction->t_handle_lock);
while (commit_transaction->t_updates != 0) { while (commit_transaction->t_updates) {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
prepare_to_wait(&journal->j_wait_updates, &wait, prepare_to_wait(&journal->j_wait_updates, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
if (commit_transaction->t_updates) { if (commit_transaction->t_updates) {
spin_unlock(&commit_transaction->t_handle_lock); spin_unlock(&commit_transaction->t_handle_lock);
spin_unlock(&journal->j_state_lock);
schedule(); schedule();
spin_lock(&journal->j_state_lock);
spin_lock(&commit_transaction->t_handle_lock); spin_lock(&commit_transaction->t_handle_lock);
} }
finish_wait(&journal->j_wait_updates, &wait); finish_wait(&journal->j_wait_updates, &wait);
...@@ -97,14 +108,6 @@ void journal_commit_transaction(journal_t *journal) ...@@ -97,14 +108,6 @@ void journal_commit_transaction(journal_t *journal)
J_ASSERT (commit_transaction->t_outstanding_credits <= J_ASSERT (commit_transaction->t_outstanding_credits <=
journal->j_max_transaction_buffers); journal->j_max_transaction_buffers);
/* Do we need to erase the effects of a prior journal_flush? */
if (journal->j_flags & JFS_FLUSHED) {
jbd_debug(3, "super block updated\n");
journal_update_superblock(journal, 1);
} else {
jbd_debug(3, "superblock not updated\n");
}
/* /*
* First thing we are allowed to do is to discard any remaining * First thing we are allowed to do is to discard any remaining
* BJ_Reserved buffers. Note, it is _not_ permissible to assume * BJ_Reserved buffers. Note, it is _not_ permissible to assume
...@@ -121,7 +124,6 @@ void journal_commit_transaction(journal_t *journal) ...@@ -121,7 +124,6 @@ void journal_commit_transaction(journal_t *journal)
* that multiple journal_get_write_access() calls to the same * that multiple journal_get_write_access() calls to the same
* buffer are perfectly permissable. * buffer are perfectly permissable.
*/ */
while (commit_transaction->t_reserved_list) { while (commit_transaction->t_reserved_list) {
jh = commit_transaction->t_reserved_list; jh = commit_transaction->t_reserved_list;
JBUFFER_TRACE(jh, "reserved, unused: refile"); JBUFFER_TRACE(jh, "reserved, unused: refile");
...@@ -137,17 +139,6 @@ void journal_commit_transaction(journal_t *journal) ...@@ -137,17 +139,6 @@ void journal_commit_transaction(journal_t *journal)
__journal_clean_checkpoint_list(journal); __journal_clean_checkpoint_list(journal);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
/* First part of the commit: force the revoke list out to disk.
* The revoke code generates its own metadata blocks on disk for this.
*
* It is important that we do this while the transaction is
* still locked. Generating the revoke records should not
* generate any IO stalls, so this should be quick; and doing
* the work while we have the transaction locked means that we
* only ever have to maintain the revoke list for one
* transaction at a time.
*/
jbd_debug (3, "JBD: commit phase 1\n"); jbd_debug (3, "JBD: commit phase 1\n");
/* /*
...@@ -155,7 +146,6 @@ void journal_commit_transaction(journal_t *journal) ...@@ -155,7 +146,6 @@ void journal_commit_transaction(journal_t *journal)
*/ */
journal_switch_revoke_table(journal); journal_switch_revoke_table(journal);
spin_lock(&journal->j_state_lock);
commit_transaction->t_state = T_FLUSH; commit_transaction->t_state = T_FLUSH;
journal->j_committing_transaction = commit_transaction; journal->j_committing_transaction = commit_transaction;
journal->j_running_transaction = NULL; journal->j_running_transaction = NULL;
......
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