summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-06-17 18:31:15 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-06-17 18:31:15 -0700
commitfba1fdeecf6a0ddc41277bb200beec5ad89f8c61 (patch)
tree41e78427a68e9d608fad46c3c41476641f99e9c9
parent28a4dd1ba782d5b0f27dca9632296a452c204286 (diff)
[PATCH] JBD: fix log_start_commit race
In start_this_handle() the caller does not have a handle ref pinning the transaction open, and so the call to log_start_commit() is racy because some other CPU could take the transaction into commit state independently. Fix that by holding j_state_lock (which pins j_running_transaction) across the log_start_commit() call.
-rw-r--r--fs/jbd/journal.c2
-rw-r--r--fs/jbd/transaction.c6
-rw-r--r--include/linux/jbd.h1
3 files changed, 5 insertions, 4 deletions
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index fc40cff80ac2..488980909319 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -442,7 +442,7 @@ int __log_space_left(journal_t *journal)
/*
* Called under j_state_lock.
*/
-static tid_t __log_start_commit(journal_t *journal, transaction_t *transaction)
+tid_t __log_start_commit(journal_t *journal, transaction_t *transaction)
{
tid_t target = journal->j_commit_request;
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index f42f25429858..5a3461dd8c05 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -171,12 +171,12 @@ repeat:
*/
DEFINE_WAIT(wait);
- spin_unlock(&transaction->t_handle_lock);
- spin_unlock(&journal->j_state_lock);
jbd_debug(2, "Handle %p starting new commit...\n", handle);
+ spin_unlock(&transaction->t_handle_lock);
prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
TASK_UNINTERRUPTIBLE);
- log_start_commit(journal, transaction);
+ __log_start_commit(journal, transaction);
+ spin_unlock(&journal->j_state_lock);
schedule();
finish_wait(&journal->j_wait_transaction_locked, &wait);
goto repeat;
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index e0501a317e31..567c835eb73e 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -991,6 +991,7 @@ extern void journal_switch_revoke_table(journal_t *journal);
int __log_space_left(journal_t *); /* Called with journal locked */
extern tid_t log_start_commit (journal_t *, transaction_t *);
+extern tid_t __log_start_commit(journal_t *, transaction_t *);
extern int log_wait_commit (journal_t *, tid_t);
extern int log_do_checkpoint (journal_t *, int);