Module Name:    src
Committed By:   snj
Date:           Wed Feb  4 04:18:23 UTC 2015

Modified Files:
        src/sys/dev [netbsd-6]: vnd.c

Log Message:
Pull up following revision(s) (requested by bouyer in ticket #1242):
        sys/dev/vnd.c: revision 1.240, 1.241
As discussed in
http://mail-index.netbsd.org/tech-kern/2015/01/24/msg018339.html
don't bump v_numoutput if we need to vn_lock() the vnode before queuing
the corresponding I/O, because this may deadlock with genfs_do_putpages()
when called with the vnode locked (as can happen with fsync(2)).
Instead bump is just before the last VOP_STRATEGY(), or before calling
nestiobuf_done().
Thanks to Taylor R Campbell for review.
--
Fix typo in comment


To generate a diff of this commit:
cvs rdiff -u -r1.219.8.2 -r1.219.8.3 src/sys/dev/vnd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/vnd.c
diff -u src/sys/dev/vnd.c:1.219.8.2 src/sys/dev/vnd.c:1.219.8.3
--- src/sys/dev/vnd.c:1.219.8.2	Thu Jul  5 18:12:46 2012
+++ src/sys/dev/vnd.c	Wed Feb  4 04:18:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnd.c,v 1.219.8.2 2012/07/05 18:12:46 riz Exp $	*/
+/*	$NetBSD: vnd.c,v 1.219.8.3 2015/02/04 04:18:23 snj Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2008 The NetBSD Foundation, Inc.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.219.8.2 2012/07/05 18:12:46 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.219.8.3 2015/02/04 04:18:23 snj Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_vnd.h"
@@ -782,15 +782,10 @@ handle_with_strategy(struct vnd_softc *v
 	size_t resid, sz;
 	off_t bn, offset;
 	struct vnode *vp;
+	struct buf *nbp = NULL;
 
 	flags = obp->b_flags;
 
-	if (!(flags & B_READ)) {
-		vp = bp->b_vp;
-		mutex_enter(vp->v_interlock);
-		vp->v_numoutput++;
-		mutex_exit(vp->v_interlock);
-	}
 
 	/* convert to a byte offset within the file. */
 	bn = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize;
@@ -807,9 +802,8 @@ handle_with_strategy(struct vnd_softc *v
 	 */
 	error = 0;
 	bp->b_resid = bp->b_bcount;
-	for (offset = 0, resid = bp->b_resid; resid;
+	for (offset = 0, resid = bp->b_resid; /* true */;
 	    resid -= sz, offset += sz) {
-		struct buf *nbp;
 		daddr_t nbn;
 		int off, nra;
 
@@ -862,10 +856,34 @@ handle_with_strategy(struct vnd_softc *v
 			    nbp->vb_buf.b_flags, nbp->vb_buf.b_data,
 			    nbp->vb_buf.b_bcount);
 #endif
+		if (resid == sz) {
+			break;
+		}
 		VOP_STRATEGY(vp, nbp);
 		bn += sz;
 	}
-	nestiobuf_done(bp, skipped, error);
+	if (!(flags & B_READ)) {
+		struct vnode *w_vp;
+		/*
+		 * this is the last nested buf, account for
+		 * the parent buf write too.
+		 * This has to be done last, so that
+		 * fsync won't wait for this write which
+		 * has no chance to complete before all nested bufs
+		 * have been queued. But it has to be done
+		 * before the last VOP_STRATEGY() 
+		 * or the call to nestiobuf_done().
+		 */
+		w_vp = bp->b_vp;
+		mutex_enter(w_vp->v_interlock);
+		w_vp->v_numoutput++;
+		mutex_exit(w_vp->v_interlock);
+	}
+	KASSERT(skipped != 0 || nbp != NULL);
+	if (skipped) 
+		nestiobuf_done(bp, skipped, error);
+	else 
+		VOP_STRATEGY(vp, nbp);
 }
 
 static void

Reply via email to