Module Name: src Committed By: hannken Date: Sat Mar 26 14:58:13 UTC 2016
Modified Files: src/sys/miscfs/specfs: spec_vnops.c Log Message: Whhen spec_strategy() extracts v_rdev take care to avoid a race with spec_revoke. Fixes PR kern/50467 Panic from disconnecting phone while reading its contents To generate a diff of this commit: cvs rdiff -u -r1.160 -r1.161 src/sys/miscfs/specfs/spec_vnops.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/miscfs/specfs/spec_vnops.c diff -u src/sys/miscfs/specfs/spec_vnops.c:1.160 src/sys/miscfs/specfs/spec_vnops.c:1.161 --- src/sys/miscfs/specfs/spec_vnops.c:1.160 Tue Jan 5 09:07:19 2016 +++ src/sys/miscfs/specfs/spec_vnops.c Sat Mar 26 14:58:13 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: spec_vnops.c,v 1.160 2016/01/05 09:07:19 pgoyette Exp $ */ +/* $NetBSD: spec_vnops.c,v 1.161 2016/03/26 14:58:13 hannken Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.160 2016/01/05 09:07:19 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.161 2016/03/26 14:58:13 hannken Exp $"); #include <sys/param.h> #include <sys/proc.h> @@ -1029,26 +1029,45 @@ spec_strategy(void *v) } */ *ap = v; struct vnode *vp = ap->a_vp; struct buf *bp = ap->a_bp; + dev_t dev; int error; - KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp); + dev = NODEV; - error = 0; - bp->b_dev = vp->v_rdev; + /* + * Extract all the info we need from the vnode, taking care to + * avoid a race with VOP_REVOKE(). + */ - if (!(bp->b_flags & B_READ)) - error = fscow_run(bp, false); + mutex_enter(vp->v_interlock); + if (vdead_check(vp, VDEAD_NOWAIT) == 0 && vp->v_specnode != NULL) { + dev = vp->v_rdev; + } + mutex_exit(vp->v_interlock); - if (error) { - bp->b_error = error; - bp->b_resid = bp->b_bcount; - biodone(bp); - return (error); + if (dev == NODEV) { + error = ENXIO; + goto out; } + bp->b_dev = dev; + KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp); + + if (!(bp->b_flags & B_READ)) { + error = fscow_run(bp, false); + if (error) + goto out; + } bdev_strategy(bp); - return (0); + return 0; + +out: + bp->b_error = error; + bp->b_resid = bp->b_bcount; + biodone(bp); + + return error; } int