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