summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorVisa Hankala <visa@cvs.openbsd.org>2019-10-29 16:24:43 +0000
committerVisa Hankala <visa@cvs.openbsd.org>2019-10-29 16:24:43 +0000
commit48b4e939f20ea6953c1a5a2fb0ed0d5d7f83af40 (patch)
treef30b00b9512cb4dde4da3e695c4ed5f4cf4d3e29 /sys
parent3bffcac2d45eae520601bdc43cf9a3ccd0df9ed7 (diff)
Consistently release the vnode lock while calling d_close of cloned and
non-cloned devices. Combine spec_close() and spec_close_clone() to avoid code duplication. OK mpi@
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/spec_vnops.c51
1 files changed, 22 insertions, 29 deletions
diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c
index 235a5dc6106..7cdfd6b7708 100644
--- a/sys/kern/spec_vnops.c
+++ b/sys/kern/spec_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spec_vnops.c,v 1.97 2019/07/25 01:43:21 cheloha Exp $ */
+/* $OpenBSD: spec_vnops.c,v 1.98 2019/10/29 16:24:42 visa Exp $ */
/* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
/*
@@ -59,7 +59,6 @@
#define v_lastr v_specinfo->si_lastr
int spec_open_clone(struct vop_open_args *);
-int spec_close_clone(struct vop_close_args *);
struct vnode *speclisth[SPECHSZ];
@@ -481,6 +480,7 @@ spec_close(void *v)
dev_t dev = vp->v_rdev;
int (*devclose)(dev_t, int, int, struct proc *);
int mode, relock, error;
+ int clone = 0;
switch (vp->v_type) {
@@ -499,15 +499,17 @@ spec_close(void *v)
vrele(vp);
p->p_p->ps_pgrp->pg_session->s_ttyvp = NULL;
}
- if (cdevsw[major(dev)].d_flags & D_CLONE)
- return (spec_close_clone(ap));
- /*
- * If the vnode is locked, then we are in the midst
- * of forcably closing the device, otherwise we only
- * close on last reference.
- */
- if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
- return (0);
+ if (cdevsw[major(dev)].d_flags & D_CLONE) {
+ clone = 1;
+ } else {
+ /*
+ * If the vnode is locked, then we are in the midst
+ * of forcably closing the device, otherwise we only
+ * close on last reference.
+ */
+ if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
+ return (0);
+ }
devclose = cdevsw[major(dev)].d_close;
mode = S_IFCHR;
break;
@@ -553,6 +555,15 @@ spec_close(void *v)
error = (*devclose)(dev, ap->a_fflag, mode, p);
if (relock)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+
+ if (error == 0 && clone) {
+ struct vnode *pvp;
+
+ pvp = vp->v_specparent; /* get parent device */
+ clrbit(pvp->v_specbitmap, minor(dev) >> CLONE_SHIFT);
+ vrele(pvp);
+ }
+
return (error);
}
@@ -759,21 +770,3 @@ spec_open_clone(struct vop_open_args *ap)
return (0); /* device cloned */
}
-
-int
-spec_close_clone(struct vop_close_args *ap)
-{
- struct vnode *pvp, *vp = ap->a_vp;
- int error;
-
- error = cdevsw[major(vp->v_rdev)].d_close(vp->v_rdev, ap->a_fflag,
- S_IFCHR, ap->a_p);
- if (error)
- return (error); /* device close failed */
-
- pvp = vp->v_specparent; /* get parent device */
- clrbit(pvp->v_specbitmap, minor(vp->v_rdev) >> CLONE_SHIFT);
- vrele(pvp);
-
- return (0); /* clone closed */
-}