spec_close() does a fair bit of extra work around the xlock flag.
Now spec_close() is called via VOP_CLOSE and either the vnode has VXLOCK
set (because it is called via vclean()) or it does not. In either case
VXLOCK can not change during call (at least that was my conclusion looking
at the code). Because of this it is enough to check VXLOCK once at the
beginning.

-- 
:wq Claudio

Index: spec_vnops.c
===================================================================
RCS file: /cvs/src/sys/kern/spec_vnops.c,v
retrieving revision 1.107
diff -u -p -r1.107 spec_vnops.c
--- spec_vnops.c        11 Dec 2021 09:28:26 -0000      1.107
+++ spec_vnops.c        27 Apr 2022 10:53:56 -0000
@@ -487,8 +487,12 @@ spec_close(void *v)
        int mode, relock, xlocked, error;
        int clone = 0;
 
-       switch (vp->v_type) {
+       /* lock can not change during call */
+       mtx_enter(&vnode_mtx);
+       xlocked = (vp->v_lflag & VXLOCK);
+       mtx_leave(&vnode_mtx);
 
+       switch (vp->v_type) {
        case VCHR:
                /*
                 * Hack: a tty device that is a controlling terminal
@@ -512,9 +516,6 @@ spec_close(void *v)
                         * of forcibly closing the device, otherwise we only
                         * close on last reference.
                         */
-                       mtx_enter(&vnode_mtx);
-                       xlocked = (vp->v_lflag & VXLOCK);
-                       mtx_leave(&vnode_mtx);
                        if (vcount(vp) > 1 && !xlocked)
                                return (0);
                }
@@ -530,9 +531,6 @@ spec_close(void *v)
                 * that, we must lock the vnode. If we are coming from
                 * vclean(), the vnode is already locked.
                 */
-               mtx_enter(&vnode_mtx);
-               xlocked = (vp->v_lflag & VXLOCK);
-               mtx_leave(&vnode_mtx);
                if (!xlocked)
                        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                error = vinvalbuf(vp, V_SAVE, ap->a_cred, p, 0, INFSLP);
@@ -549,9 +547,6 @@ spec_close(void *v)
                 * sum of the reference counts on all the aliased
                 * vnodes descends to one, we are on last close.
                 */
-               mtx_enter(&vnode_mtx);
-               xlocked = (vp->v_lflag & VXLOCK);
-               mtx_leave(&vnode_mtx);
                if (vcount(vp) > 1 && !xlocked)
                        return (0);
                devclose = bdevsw[major(dev)].d_close;
@@ -563,9 +558,6 @@ spec_close(void *v)
        }
 
        /* release lock if held and this isn't coming from vclean() */
-       mtx_enter(&vnode_mtx);
-       xlocked = (vp->v_lflag & VXLOCK);
-       mtx_leave(&vnode_mtx);
        relock = VOP_ISLOCKED(vp) && !xlocked;
        if (relock)
                VOP_UNLOCK(vp);

Reply via email to