sart_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().



 25-akpm/fs/jbd/commit.c |   34 ++++++++++++----------------------
 1 files changed, 12 insertions(+), 22 deletions(-)

diff -puN fs/jbd/commit.c~jbd-620-commit-vs-start-race-fix fs/jbd/commit.c
--- 25/fs/jbd/commit.c~jbd-620-commit-vs-start-race-fix	Thu Jun  5 15:14:48 2003
+++ 25-akpm/fs/jbd/commit.c	Thu Jun  5 15:14:48 2003
@@ -68,6 +68,14 @@ void journal_commit_transaction(journal_
 	spin_unlock(&journal->j_list_lock);
 #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_committing_transaction == NULL);
 
@@ -77,17 +85,20 @@ void journal_commit_transaction(journal_
 	jbd_debug(1, "JBD: starting commit of transaction %d\n",
 			commit_transaction->t_tid);
 
+	spin_lock(&journal->j_state_lock);
 	commit_transaction->t_state = T_LOCKED;
 
 	spin_lock(&commit_transaction->t_handle_lock);
-	while (commit_transaction->t_updates != 0) {
+	while (commit_transaction->t_updates) {
 		DEFINE_WAIT(wait);
 
 		prepare_to_wait(&journal->j_wait_updates, &wait,
 					TASK_UNINTERRUPTIBLE);
 		if (commit_transaction->t_updates) {
 			spin_unlock(&commit_transaction->t_handle_lock);
+			spin_unlock(&journal->j_state_lock);
 			schedule();
+			spin_lock(&journal->j_state_lock);
 			spin_lock(&commit_transaction->t_handle_lock);
 		}
 		finish_wait(&journal->j_wait_updates, &wait);
@@ -97,14 +108,6 @@ void journal_commit_transaction(journal_
 	J_ASSERT (commit_transaction->t_outstanding_credits <=
 			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
 	 * BJ_Reserved buffers.  Note, it is _not_ permissible to assume
@@ -121,7 +124,6 @@ void journal_commit_transaction(journal_
 	 * that multiple journal_get_write_access() calls to the same
 	 * buffer are perfectly permissable.
 	 */
-
 	while (commit_transaction->t_reserved_list) {
 		jh = commit_transaction->t_reserved_list;
 		JBUFFER_TRACE(jh, "reserved, unused: refile");
@@ -137,17 +139,6 @@ void journal_commit_transaction(journal_
 	__journal_clean_checkpoint_list(journal);
 	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");
 
 	/*
@@ -155,7 +146,6 @@ void journal_commit_transaction(journal_
 	 */
 	journal_switch_revoke_table(journal);
 
-	spin_lock(&journal->j_state_lock);
 	commit_transaction->t_state = T_FLUSH;
 	journal->j_committing_transaction = commit_transaction;
 	journal->j_running_transaction = NULL;

_