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.


 25-akpm/fs/jbd/journal.c     |    2 +-
 25-akpm/fs/jbd/transaction.c |    6 +++---
 25-akpm/include/linux/jbd.h  |    1 +
 3 files changed, 5 insertions(+), 4 deletions(-)

diff -puN fs/jbd/transaction.c~jbd-580-log_start_commit-race-fix fs/jbd/transaction.c
--- 25/fs/jbd/transaction.c~jbd-580-log_start_commit-race-fix	Thu Jun  5 15:14:37 2003
+++ 25-akpm/fs/jbd/transaction.c	Thu Jun  5 15:14:37 2003
@@ -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 -puN fs/jbd/journal.c~jbd-580-log_start_commit-race-fix fs/jbd/journal.c
--- 25/fs/jbd/journal.c~jbd-580-log_start_commit-race-fix	Thu Jun  5 15:14:37 2003
+++ 25-akpm/fs/jbd/journal.c	Thu Jun  5 15:14:37 2003
@@ -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 -puN include/linux/jbd.h~jbd-580-log_start_commit-race-fix include/linux/jbd.h
--- 25/include/linux/jbd.h~jbd-580-log_start_commit-race-fix	Thu Jun  5 15:14:37 2003
+++ 25-akpm/include/linux/jbd.h	Thu Jun  5 15:14:37 2003
@@ -991,6 +991,7 @@ extern void	journal_switch_revoke_table(
 
 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);
 

_