diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2013-10-29 03:11:09 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2013-10-29 03:11:09 +0000 |
commit | 7adada48c656fd8168ea74214501643ef59f5cad (patch) | |
tree | 737aa816574f3b1b34e193586607049bc6a34a03 /sys | |
parent | 431ca71fec37fe3209496aa005f3248a21018e0f (diff) |
Unlock the vnode while calling a device's d_close routine, except when
it's locked for changing the type (i.e., revoke()). We already unlock
it while calling the d_open, d_read, and d_write routines and this is
safe for the same reason: the device routines operate at a lower level
and don't need the protection of the vnode locks. This is important
as the device close routine may block indefinitely.
"don't see anything wrong" tedu@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/spec_vnops.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c index 20ce5f2da03..69873142961 100644 --- a/sys/kern/spec_vnops.c +++ b/sys/kern/spec_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: spec_vnops.c,v 1.76 2013/08/06 08:22:37 kettenis Exp $ */ +/* $OpenBSD: spec_vnops.c,v 1.77 2013/10/29 03:11:08 guenther Exp $ */ /* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */ /* @@ -472,10 +472,11 @@ int spec_close(void *v) { struct vop_close_args *ap = v; + struct proc *p = ap->a_p; struct vnode *vp = ap->a_vp; dev_t dev = vp->v_rdev; int (*devclose)(dev_t, int, int, struct proc *); - int mode, error; + int mode, relock, error; switch (vp->v_type) { @@ -541,7 +542,14 @@ spec_close(void *v) panic("spec_close: not special"); } - return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); + /* release lock if held and this isn't coming from vclean() */ + relock = VOP_ISLOCKED(vp) && !(vp->v_flag & VXLOCK); + if (relock) + VOP_UNLOCK(vp, 0, p); + error = (*devclose)(dev, ap->a_fflag, mode, p); + if (relock) + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + return (error); } int |