Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 4 Nov 2001 17:12:39 -0800 (PST)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        Mark Santcroos <marks@ripe.net>, current@FreeBSD.ORG
Subject:   patch #2 (was Re: buf_daemon() lockup)
Message-ID:  <200111050112.fA51Cdc42844@apollo.backplane.com>
References:  <20011101092118.A434@laptop.6bone.nl> <200111042259.fA4MxSc93566@apollo.backplane.com> <200111050006.fA506f309535@apollo.backplane.com> <200111050015.fA50Fdk09561@apollo.backplane.com>

next in thread | previous in thread | raw e-mail | index | archive | help

:
:    Hmm..  that last patch didn't do it.  I've noticed some errors on the
:    console before the lockup:
:
:unexpected md driver lock: 0xe1813900: type VREG, usecount 2, writecount 1, refcount 3871, flags (VOBJBUF)
:        tag VT_UFS, ino 4, on dev da0s1h (13, 131079) lock type inode: EXCL (count 1) by pid 6

    Ok.  I think these unexpected md driver lock messages are bogus... I'll
    leave it to Poul to remove it.  The syncer or buf_daemon can be flushing
    buffers associated with the underlying file simultaniously with other
    processes doing MD ops.

    Here's a new patch.  It's the same as the old one except I fixed a
    missing B_NOWDRAIN flag in the clustering code, and I added B_NOWDRAIN
    support to the nfs client code.  I think the missing drain flag in the
    clustering code was the problem.  Try this patch.

						-Matt

Index: dev/md/md.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/md/md.c,v
retrieving revision 1.47
diff -u -r1.47 md.c
--- dev/md/md.c	2001/10/11 23:38:13	1.47
+++ dev/md/md.c	2001/11/04 23:54:18
@@ -388,13 +388,18 @@
 		auio.uio_td = curthread;
 		if (VOP_ISLOCKED(sc->vnode, NULL))
 			vprint("unexpected md driver lock", sc->vnode);
+		/*
+		 * When reading set IO_DIRECT to try to avoid double-caching
+		 * the data.  When writing IO_DIRECT is not optimal, but we
+		 * must set IO_NOWDRAIN to avoid a wdrain deadlock.
+		 */
 		if (bp->bio_cmd == BIO_READ) {
 			vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
-			error = VOP_READ(sc->vnode, &auio, 0, sc->cred);
+			error = VOP_READ(sc->vnode, &auio, IO_DIRECT, sc->cred);
 		} else {
 			(void) vn_start_write(sc->vnode, &mp, V_WAIT);
 			vn_lock(sc->vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
-			error = VOP_WRITE(sc->vnode, &auio, 0, sc->cred);
+			error = VOP_WRITE(sc->vnode, &auio, IO_NOWDRAIN, sc->cred);
 			vn_finished_write(mp);
 		}
 		VOP_UNLOCK(sc->vnode, 0, curthread);
Index: kern/vfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_bio.c,v
retrieving revision 1.291
diff -u -r1.291 vfs_bio.c
--- kern/vfs_bio.c	2001/10/21 06:26:55	1.291
+++ kern/vfs_bio.c	2001/11/04 23:41:19
@@ -758,11 +758,15 @@
 		int rtval = bufwait(bp);
 		brelse(bp);
 		return (rtval);
-	} else {
+	} else if ((oldflags & B_NOWDRAIN) == 0) {
 		/*
 		 * don't allow the async write to saturate the I/O
-		 * system.  There is no chance of deadlock here because
-		 * we are blocking on I/O that is already in-progress.
+		 * system.  Deadlocks can occur only if a device strategy
+		 * routine (like in MD) turns around and issues another
+		 * high-level write, in which case B_NOWDRAIN is expected
+		 * to be set.  Otherwise we will not deadlock here because
+		 * we are blocking waiting for I/O that is already in-progress
+		 * to complete.
 		 */
 		waitrunningbufspace();
 	}
@@ -1286,7 +1290,8 @@
 
 	/* unlock */
 	BUF_UNLOCK(bp);
-	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_NOWDRAIN);
 	bp->b_ioflags &= ~BIO_ORDERED;
 	if ((bp->b_flags & B_DELWRI) == 0 && (bp->b_xflags & BX_VNDIRTY))
 		panic("brelse: not dirty");
Index: kern/vfs_cluster.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_cluster.c,v
retrieving revision 1.114
diff -u -r1.114 vfs_cluster.c
--- kern/vfs_cluster.c	2001/10/25 22:49:48	1.114
+++ kern/vfs_cluster.c	2001/11/05 00:49:33
@@ -836,7 +836,7 @@
 		bp->b_data = (char *)((vm_offset_t)bp->b_data |
 		    ((vm_offset_t)tbp->b_data & PAGE_MASK));
 		bp->b_flags |= B_CLUSTER |
-				(tbp->b_flags & (B_VMIO | B_NEEDCOMMIT));
+				(tbp->b_flags & (B_VMIO | B_NEEDCOMMIT | B_NOWDRAIN));
 		bp->b_iodone = cluster_callback;
 		pbgetvp(vp, bp);
 		/*
Index: nfsclient/nfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/nfsclient/nfs_bio.c,v
retrieving revision 1.102
diff -u -r1.102 nfs_bio.c
--- nfsclient/nfs_bio.c	2001/10/11 23:38:16	1.102
+++ nfsclient/nfs_bio.c	2001/11/05 01:07:42
@@ -961,6 +961,12 @@
 			}
 			vfs_bio_set_validclean(bp, on, n);
 		}
+		/*
+		 * If IO_NOWDRAIN then set B_NOWDRAIN (nfs-backed MD 
+		 * filesystem)
+		 */
+		if (ioflag & IO_NOWDRAIN)
+			bp->b_flags |= B_NOWDRAIN;
 
 		/*
 		 * If IO_SYNC do bwrite().
Index: sys/buf.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/buf.h,v
retrieving revision 1.121
diff -u -r1.121 buf.h
--- sys/buf.h	2001/09/12 08:38:04	1.121
+++ sys/buf.h	2001/11/04 23:30:25
@@ -192,6 +192,11 @@
  *			the pages underlying the buffer.  B_DIRECT is
  *			sticky until the buffer is released and typically
  *			only has an effect when B_RELBUF is also set.
+ *
+ *	B_NOWDRAIN	This flag should be set when a device (like MD)
+ *			does a turn-around VOP_WRITE from its strategy
+ *			routine.  This flag prevents bwrite() from blocking
+ *			in wdrain, avoiding a deadlock situation.
  */
 
 #define	B_AGE		0x00000001	/* Move to age queue when I/O done. */
@@ -204,7 +209,7 @@
 #define	B_DELWRI	0x00000080	/* Delay I/O until buffer reused. */
 #define	B_DONE		0x00000200	/* I/O completed. */
 #define	B_EINTR		0x00000400	/* I/O was interrupted */
-#define	B_00000800	0x00000800	/* Available flag. */
+#define	B_NOWDRAIN	0x00000800	/* Avoid wdrain deadlock */
 #define	B_SCANNED	0x00001000	/* VOP_FSYNC funcs mark written bufs */
 #define	B_INVAL		0x00002000	/* Does not contain valid info. */
 #define	B_LOCKED	0x00004000	/* Locked in core (not reusable). */
Index: sys/vnode.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/vnode.h,v
retrieving revision 1.162
diff -u -r1.162 vnode.h
--- sys/vnode.h	2001/10/27 19:58:55	1.162
+++ sys/vnode.h	2001/11/04 23:27:40
@@ -222,6 +222,7 @@
 #define	IO_INVAL	0x40		/* invalidate after I/O */
 #define	IO_ASYNC	0x80		/* bawrite rather then bdwrite */
 #define IO_DIRECT	0x100		/* attempt to bypass buffer cache */
+#define IO_NOWDRAIN	0x200		/* do not block on wdrain */
 
 /*
  *  Modes.  Some values same as Ixxx entries from inode.h for now.
Index: ufs/ufs/ufs_readwrite.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_readwrite.c,v
retrieving revision 1.82
diff -u -r1.82 ufs_readwrite.c
--- ufs/ufs/ufs_readwrite.c	2001/09/12 08:38:10	1.82
+++ ufs/ufs/ufs_readwrite.c	2001/11/04 23:29:15
@@ -511,6 +511,8 @@
 			break;
 		if (ioflag & IO_DIRECT)
 			bp->b_flags |= B_DIRECT;
+		if (ioflag & IO_NOWDRAIN)
+			bp->b_flags |= B_NOWDRAIN;
 
 		if (uio->uio_offset + xfersize > ip->i_size) {
 			ip->i_size = uio->uio_offset + xfersize;

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200111050112.fA51Cdc42844>