[PATCH 2.4.21-pre4] JFS: Fix hang under heavy load

Dave Kleikamp <[email protected]> Tue, 11 Mar 2003 16:25:49 -0600
Newsgroups gmane.comp.file-systems.jfs.patches
Message-ID <[email protected]>
This patch fixes a hang when JFS is subjected to heavy stress.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1009  -> 1.1010 
#	 fs/jfs/jfs_txnmgr.c	1.21    -> 1.22   
#	 fs/jfs/jfs_logmgr.c	1.16    -> 1.17   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/03/10	[email protected]	1.1010
# JFS: Fix hang while flushing outstanding transactions under heavy load
#   
# During syncbarrier recovery, when JFS is waiting for all outstanding
# transactions to complete before allowing new ones to start, there was a
# window where a new transaction starts, but is not committed when JFS thought
# it could stop flushing the journal to disk.  This caused the log_SYNCBARRIER
# flag to not be reset, and no new transactions are allowed to start.
#   
# This is fixed by using the log->active field to determine when to reset the
# log_FLUSH flag.
# --------------------------------------------
#
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Tue Mar 11 16:17:40 2003
+++ b/fs/jfs/jfs_logmgr.c	Tue Mar 11 16:17:40 2003
@@ -673,28 +673,29 @@
 	}
 	jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
 
-	if (tblk->xflag & COMMIT_LAZY) {
-		/*
-		 * Lazy transactions can leave now
-		 */
+	if (tblk->xflag & COMMIT_LAZY)
 		tblk->flag |= tblkGC_LAZY;
-		LOGGC_UNLOCK(log);
-		return 0;
-	}
-	/*
-	 * group commit pageout in progress
-	 */
-	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head) {
+
+	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head &&
+	    (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag))) {
 		/*
-		 * only transaction in the commit queue:
+		 * No pageout in progress
 		 *
-		 * start one-transaction group commit as
-		 * its group leader.
+		 * start group commit as its group leader.
 		 */
 		log->cflag |= logGC_PAGEOUT;
 
 		lmGCwrite(log, 0);
 	}
+
+	if (tblk->xflag & COMMIT_LAZY) {
+		/*
+		 * Lazy transactions can leave now
+		 */
+		LOGGC_UNLOCK(log);
+		return 0;
+	}
+
 	/* lmGCwrite gives up LOGGC_LOCK, check again */
 
 	if (tblk->flag & tblkGC_COMMITTED) {
@@ -893,10 +894,8 @@
 	 * the first transaction entering group commit
 	 * will elect herself as new group leader.
 	 */
-	else {
+	else
 		log->cflag &= ~logGC_PAGEOUT;
-		clear_bit(log_FLUSH, &log->flag);
-	}
 
 	//LOGGC_UNLOCK(log);
 	spin_unlock_irqrestore(&log->gclock, flags);
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Tue Mar 11 16:17:40 2003
+++ b/fs/jfs/jfs_txnmgr.c	Tue Mar 11 16:17:40 2003
@@ -517,22 +517,24 @@
 	/*
 	 * mark the tblock not active
 	 */
-	--log->active;
+	if (--log->active == 0) {
+		clear_bit(log_FLUSH, &log->flag);
 
-	/*
-	 * synchronize with logsync barrier
-	 */
-	if (test_bit(log_SYNCBARRIER, &log->flag) && log->active == 0) {
-		/* forward log syncpt */
-		/* lmSync(log); */
+		/*
+		 * synchronize with logsync barrier
+		 */
+		if (test_bit(log_SYNCBARRIER, &log->flag)) {
+			/* forward log syncpt */
+			/* lmSync(log); */
 
-		jfs_info("     log barrier off: 0x%x", log->lsn);
+			jfs_info("log barrier off: 0x%x", log->lsn);
 
-		/* enable new transactions start */
-		clear_bit(log_SYNCBARRIER, &log->flag);
+			/* enable new transactions start */
+			clear_bit(log_SYNCBARRIER, &log->flag);
 
-		/* wakeup all waitors for logsync barrier */
-		TXN_WAKEUP(&log->syncwait);
+			/* wakeup all waitors for logsync barrier */
+			TXN_WAKEUP(&log->syncwait);
+		}
 	}
 
 	/*