tech-kern archive

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

Re: vnode lock and v_numoutput



   Date: Mon, 26 Jan 2015 12:10:53 +0100
   From: Manuel Bouyer <bouyer%antioche.eu.org@localhost>

   I'm not sure I understand; the "bump v_numoutput" is always needed;
   but if skipped is 0 the last nestiobuf_done() call is done by
   biodone() callback and not by the called. So the bump has to happen
   before the last buf is queued.

Ah, yes, sorry -- we need one bump for every nested buf that will be
queued and biodone'd, and always one bump for the parent which will
always be biodone'd either by a nested buf or by nestiobuf_done on the
parent.

However, I think there's a bug in your new patch too: suppose VOP_BMAP
fails on one of the middle blocks -- then we won't call VOP_STRATEGY
for the last block even if VOP_BMAP succeeds for that block.

I believe the attached patch will fix that, but I haven't tested it.

1. Guarantee to call VOP_STRATEGY on every nestiobuf.
2. Guarantee no blocking between nestiobuf_setup or v_numoutput++ and
the corresponding VOP_STRATEGY or nestiobuf_done.
3. Guarantee one nestiobuf_setup or v_numoutput++ per VOP_STRATEGY or
nestiobuf_done.
diff -c /home/riastradh/netbsd/nbdev/src/sys/dev/vnd.c /tmp/riastradh/buffer-content-14028wVF
--- /home/riastradh/netbsd/nbdev/src/sys/dev/vnd.c	2015-01-07 01:37:45.000000000 +0000
+++ /tmp/riastradh/buffer-content-14028wVF	2015-01-26 18:49:09.000000000 +0000
@@ -795,6 +795,7 @@
 	size_t resid, sz;
 	off_t bn, offset;
 	struct vnode *vp;
+	struct buf *nbp = NULL;
 
 	flags = obp->b_flags;
 
@@ -822,10 +823,14 @@
 	bp->b_resid = bp->b_bcount;
 	for (offset = 0, resid = bp->b_resid; resid;
 	    resid -= sz, offset += sz) {
-		struct buf *nbp;
 		daddr_t nbn;
 		int off, nra;
 
+		if (nbp) {
+			VOP_STRATEGY(vp, nbp);
+			nbp = NULL;
+		}
+
 		nra = 0;
 		vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
 		error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
@@ -862,6 +867,7 @@
 			    nbn, sz);
 #endif
 
+		KASSERT(nbp == NULL);
 		nbp = getiobuf(vp, true);
 		nestiobuf_setup(bp, nbp, offset, sz);
 		nbp->b_blkno = nbn + btodb(off);
@@ -875,9 +881,21 @@
 			    nbp->vb_buf.b_flags, nbp->vb_buf.b_data,
 			    nbp->vb_buf.b_bcount);
 #endif
-		VOP_STRATEGY(vp, nbp);
 		bn += sz;
 	}
+	/*
+	 * Bump v_numoutput for the nested I/O master only after we
+	 * have done all the blocking we will do and before submitting
+	 * the last buf to disk.
+	 */
+	if (!(flags & B_READ)) {
+		vp = bp->b_vp;
+		mutex_enter(vp->v_interlock);
+		vp->v_numoutput++;
+		mutex_exit(vp->v_interlock);
+	}
+	if (nbp)
+		VOP_STRATEGY(vp, nbp);
 	nestiobuf_done(bp, skipped, error);
 }
 

Diff finished.  Mon Jan 26 18:49:09 2015


Home | Main Index | Thread Index | Old Index