patch for ext2fs unmount problem at shutdown

Don Lewis truckman at FreeBSD.org
Tue Sep 6 00:39:37 PDT 2005


Attached below is a patch to fix the problem caused by having any ext2fs
file systems mounted at system shutdown time that prevents any of the
file systems from being unmounted and then being marked dirty when the
system comes back up.  It works by tweaking ext2fs so that it marks the
bufs that it keeps locked as long as the file system is mounted, and
tweaks the shutdown code to ignore these bufs when it is counting the
number of busy buffers.

This patch applies cleanly to both HEAD and RELENG_6.  I rarely use
ext2fs and was only able to do runtime testing of this patch on HEAD.
I've done compile tests on RELENG_6.  I've also got a version of this
patch for RELENG_5 that I'll release for testing after I do the commit
to HEAD.

If you use ext2fs with HEAD or RELENG_6, I'd appreciate it if you could
test this patch before I commit it.  If possible, I'd like to get this
into 6.0-RELEASE.

Index: sys/kern/kern_shutdown.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_shutdown.c,v
retrieving revision 1.174
diff -u -r1.174 kern_shutdown.c
--- sys/kern/kern_shutdown.c	12 Apr 2005 05:45:58 -0000	1.174
+++ sys/kern/kern_shutdown.c	5 Sep 2005 19:21:38 -0000
@@ -236,6 +236,16 @@
 	dumpsys(&dumper);
 }
 
+static int
+isbufbusy(struct buf *bp)
+{
+	if (((bp->b_flags & (B_INVAL | B_PERSISTENT)) == 0 &&
+	    BUF_REFCNT(bp) > 0) ||
+	    ((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI))
+		return (1);
+	return (0);
+}
+
 /*
  * Shutdown the system cleanly to prepare for reboot, halt, or power off.
  */
@@ -288,16 +298,9 @@
 		 */
 		for (iter = pbusy = 0; iter < 20; iter++) {
 			nbusy = 0;
-			for (bp = &buf[nbuf]; --bp >= buf; ) {
-				if ((bp->b_flags & B_INVAL) == 0 &&
-				    BUF_REFCNT(bp) > 0) {
+			for (bp = &buf[nbuf]; --bp >= buf; )
+				if (isbufbusy(bp))
 					nbusy++;
-				} else if ((bp->b_flags & (B_DELWRI | B_INVAL))
-						== B_DELWRI) {
-					/* bawrite(bp);*/
-					nbusy++;
-				}
-			}
 			if (nbusy == 0) {
 				if (first_buf_printf)
 					printf("All buffers synced.");
@@ -343,8 +346,7 @@
 		 */
 		nbusy = 0;
 		for (bp = &buf[nbuf]; --bp >= buf; ) {
-			if (((bp->b_flags&B_INVAL) == 0 && BUF_REFCNT(bp)) ||
-			    ((bp->b_flags & (B_DELWRI|B_INVAL)) == B_DELWRI)) {
+			if (isbufbusy(bp)) {
 #if 0
 /* XXX: This is bogus.  We should probably have a BO_REMOTE flag instead */
 				if (bp->b_dev == NULL) {
Index: sys/kern/vfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_bio.c,v
retrieving revision 1.493
diff -u -r1.493 vfs_bio.c
--- sys/kern/vfs_bio.c	3 Aug 2005 05:02:08 -0000	1.493
+++ sys/kern/vfs_bio.c	5 Sep 2005 07:46:49 -0000
@@ -1365,7 +1365,8 @@
 	if (bp->b_bufsize || bp->b_kvasize)
 		bufspacewakeup();
 
-	bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF | B_DIRECT);
+	bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF | B_DIRECT |
+	    B_PERSISTENT);
 	if ((bp->b_flags & B_DELWRI) == 0 && (bp->b_xflags & BX_VNDIRTY))
 		panic("brelse: not dirty");
 	/* unlock */
Index: sys/sys/buf.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/buf.h,v
retrieving revision 1.188
diff -u -r1.188 buf.h
--- sys/sys/buf.h	13 Aug 2005 20:21:33 -0000	1.188
+++ sys/sys/buf.h	5 Sep 2005 19:36:24 -0000
@@ -195,7 +195,7 @@
 #define	B_CACHE		0x00000020	/* Bread found us in the cache. */
 #define	B_VALIDSUSPWRT	0x00000040	/* Valid write during suspension. */
 #define	B_DELWRI	0x00000080	/* Delay I/O until buffer reused. */
-#define	B_00000100	0x00000100	/* Available flag. */
+#define	B_PERSISTENT	0x00000100	/* Perm. ref'ed while fs mounted. */
 #define	B_DONE		0x00000200	/* I/O completed. */
 #define	B_EINTR		0x00000400	/* I/O was interrupted */
 #define	B_00000800	0x00000800	/* Available flag. */
@@ -220,10 +220,10 @@
 #define B_CLUSTER	0x40000000	/* pagein op, so swap() can count it */
 #define B_REMFREE	0x80000000	/* Delayed bremfree */
 
-#define PRINT_BUF_FLAGS "\20\40b31\37cluster\36vmio\35ram\34b27" \
+#define PRINT_BUF_FLAGS "\20\40remfree\37cluster\36vmio\35ram\34b27" \
 	"\33paging\32b25\31b24\30b23\27relbuf\26dirty\25b20" \
-	"\24b19\23phys\22clusterok\21malloc\20nocache\17locked\16inval" \
-	"\15scanned\14nowdrain\13eintr\12done\11b8\10delwri\7validsuspwrt" \
+	"\24b19\23b18\22clusterok\21malloc\20nocache\17b14\16inval" \
+	"\15b12\14b11\13eintr\12done\11persist\10delwri\7validsuspwrt" \
 	"\6cache\5deferred\4direct\3async\2needcommit\1age"
 
 /*
Index: sys/gnu/fs/ext2fs/fs.h
===================================================================
RCS file: /home/ncvs/src/sys/gnu/fs/ext2fs/fs.h,v
retrieving revision 1.17
diff -u -r1.17 fs.h
--- sys/gnu/fs/ext2fs/fs.h	6 Jan 2005 18:27:30 -0000	1.17
+++ sys/gnu/fs/ext2fs/fs.h	5 Sep 2005 21:29:11 -0000
@@ -150,11 +150,16 @@
 
 /*
  * Historically, ext2fs kept it's metadata buffers on the LOCKED queue.  Now,
- * we simply change the lock owner to kern so that it may be released from
- * another context.  Later, we release the buffer, and conditionally write it
- * when we're done.
+ * we simply change the lock owner to kern so that we may use it from contexts
+ * other than the one that originally locked it.  When we are finished with
+ * the buffer, we release it, writing it first if it was dirty.  The
+ * B_PERSISTENT flag is cleared by brelse(), which bwrite() calls after the
+ * buffer is written in the B_DIRTY case.
  */
-#define LCK_BUF(bp)	BUF_KERNPROC(bp);
+#define LCK_BUF(bp) { \
+	(bp)->b_flags |= B_PERSISTENT; \
+	BUF_KERNPROC(bp); \
+}
 
 #define ULCK_BUF(bp) { \
 	long flags; \



More information about the freebsd-current mailing list