fs/jbd/transaction.c |   43 ++++++++++++++++++++++++-------------------
 1 files changed, 24 insertions(+), 19 deletions(-)

diff -puN fs/jbd/transaction.c~jbd-060-b_committed_data-locking fs/jbd/transaction.c
--- 25/fs/jbd/transaction.c~jbd-060-b_committed_data-locking	2003-05-25 17:46:02.000000000 -0700
+++ 25-akpm/fs/jbd/transaction.c	2003-05-25 17:46:02.000000000 -0700
@@ -826,11 +826,12 @@ out:
  *
  * Returns error number or 0 on success.  
  */
-int journal_get_undo_access (handle_t *handle, struct buffer_head *bh)
+int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
 {
 	journal_t *journal = handle->h_transaction->t_journal;
 	int err;
 	struct journal_head *jh = journal_add_journal_head(bh);
+	char *committed_data = NULL;
 
 	JBUFFER_TRACE(jh, "entry");
 	lock_journal(journal);
@@ -842,33 +843,37 @@ int journal_get_undo_access (handle_t *h
 	if (err)
 		goto out;
 
-	/*
-	 * lock_journal() prevents jh->b_committed_data from getting set
-	 * by two CPUs at the same time.
-	 */
+repeat:
 	if (!jh->b_committed_data) {
-		/* Copy out the current buffer contents into the
-		 * preserved, committed copy. */
-		JBUFFER_TRACE(jh, "generate b_committed data");
-		jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, 
-						   GFP_NOFS);
-		if (!jh->b_committed_data) {
-			printk(KERN_EMERG
-			       "%s: No memory for committed data!\n",
-			       __FUNCTION__);
+		committed_data = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS);
+		if (!committed_data) {
+			printk(KERN_EMERG "%s: No memory for committed data\n",
+				__FUNCTION__);
 			err = -ENOMEM;
 			goto out;
 		}
-		
-		memcpy (jh->b_committed_data, jh2bh(jh)->b_data,
-				jh2bh(jh)->b_size);
 	}
 
+	jbd_lock_bh_state(bh);
+	if (!jh->b_committed_data) {
+		/* Copy out the current buffer contents into the
+		 * preserved, committed copy. */
+		JBUFFER_TRACE(jh, "generate b_committed data");
+		if (!committed_data) {
+			jbd_unlock_bh_state(bh);
+			goto repeat;
+		}
+
+		jh->b_committed_data = committed_data;
+		committed_data = NULL;
+		memcpy(jh->b_committed_data, bh->b_data, bh->b_size);
+	}
+	jbd_unlock_bh_state(bh);
 out:
-	if (!err)
-		J_ASSERT_JH(jh, jh->b_committed_data);
 	journal_put_journal_head(jh);
 	unlock_journal(journal);
+	if (committed_data)
+		kfree(committed_data);
 	return err;
 }
 

_