tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: vnode lock and v_numoutput



On Mon, Jan 26, 2015 at 12:10:53PM +0100, Manuel Bouyer wrote:
> [...]
> 
> I agree that hidding this to the nestiobuf API is probably the right thing
> to do. But I'm also looking for a fix that is safe to pull up to netbsd-5
> and netbsd-6 (the problem was first noticed on netbsd-5, and I reproduced
> it, and tested the patch, on netbsd-6). So if the attached
> patch looks semantically correct, I'll commit it and request pullups.
> Then I'll look at a better fix that can be commited to HEAD pulled up
> to netbsd-7.

with the patch this time ...

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: vnd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/vnd.c,v
retrieving revision 1.219.8.2
diff -u -p -u -r1.219.8.2 vnd.c
--- vnd.c	5 Jul 2012 18:12:46 -0000	1.219.8.2
+++ vnd.c	26 Jan 2015 11:11:40 -0000
@@ -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;
 
 	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,33 @@ 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 to 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);
+	}
+	if (skipped) 
+		nestiobuf_done(bp, skipped, error);
+	else 
+		VOP_STRATEGY(vp, nbp);
 }
 
 static void


Home | Main Index | Thread Index | Old Index