Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys specfs: Remove specnode from hash table in spec_node_rev...



details:   https://anonhg.NetBSD.org/src/rev/dc714d194877
branches:  trunk
changeset: 364520:dc714d194877
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Mar 28 12:37:56 2022 +0000

description:
specfs: Remove specnode from hash table in spec_node_revoke.

Previously, it was possible for spec_node_lookup_by_dev to handle a
speconde that a concurrent spec_node_destroy is about to remove from
the hash table and then free, as soon as spec_node_lookup_by_dev
releases device_lock.

Now, the ordering is:

1. Remove specnode from hash table in spec_node_revoke.  At this
   point, no _new_ vnode references are possible (other than possibly
   one acquired by vcache_vget under v_interlock), but there may be
   existing ones.

2. Mark vnode reclaimed so vcache_vget will fail.

3. The last vrele (or equivalent logic in vcache_vget) will then free
   the specnode in spec_node_destroy.

This way, _if_ a thread in spec_node_lookup_by_dev finds a specnode
in the hash table under device_lock/v_interlock, _then_ it will not
be freed until the thread completes vcache_vget.

This change requires calling spec_node_revoke unconditionally for
device special nodes, not just for active ones.  Might introduce
slightly more contention on device_lock but not much because we
already have to take it in this path anyway a little later in
spec_node_destroy.

diffstat:

 sys/kern/vfs_vnode.c           |  11 ++++-------
 sys/miscfs/specfs/spec_vnops.c |  40 ++++++++++++++++++++--------------------
 2 files changed, 24 insertions(+), 27 deletions(-)

diffs (144 lines):

diff -r f1c45b242bc6 -r dc714d194877 sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c      Mon Mar 28 12:37:46 2022 +0000
+++ b/sys/kern/vfs_vnode.c      Mon Mar 28 12:37:56 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_vnode.c,v 1.140 2022/03/28 12:37:46 riastradh Exp $        */
+/*     $NetBSD: vfs_vnode.c,v 1.141 2022/03/28 12:37:56 riastradh Exp $        */
 
 /*-
  * Copyright (c) 1997-2011, 2019, 2020 The NetBSD Foundation, Inc.
@@ -148,7 +148,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.140 2022/03/28 12:37:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.141 2022/03/28 12:37:56 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pax.h"
@@ -1811,14 +1811,13 @@
        uint32_t hash;
        uint8_t temp_buf[64], *temp_key;
        size_t temp_key_len;
-       bool recycle, active;
+       bool recycle;
        int error;
 
        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
        KASSERT(mutex_owned(vp->v_interlock));
        KASSERT(vrefcnt(vp) != 0);
 
-       active = (vrefcnt(vp) > 1);
        temp_key_len = vip->vi_key.vk_key_len;
        /*
         * Prevent the vnode from being recycled or brought into use
@@ -1861,8 +1860,6 @@
 
        /*
         * Clean out any cached data associated with the vnode.
-        * If purging an active vnode, it must be closed and
-        * deactivated before being reclaimed.
         */
        error = vinvalbuf(vp, V_SAVE, NOCRED, l, 0, 0);
        if (error != 0) {
@@ -1872,7 +1869,7 @@
        }
        KASSERTMSG((error == 0), "vinvalbuf failed: %d", error);
        KASSERT((vp->v_iflag & VI_ONWORKLST) == 0);
-       if (active && (vp->v_type == VBLK || vp->v_type == VCHR)) {
+       if (vp->v_type == VBLK || vp->v_type == VCHR) {
                 spec_node_revoke(vp);
        }
 
diff -r f1c45b242bc6 -r dc714d194877 sys/miscfs/specfs/spec_vnops.c
--- a/sys/miscfs/specfs/spec_vnops.c    Mon Mar 28 12:37:46 2022 +0000
+++ b/sys/miscfs/specfs/spec_vnops.c    Mon Mar 28 12:37:56 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: spec_vnops.c,v 1.208 2022/03/28 12:37:46 riastradh Exp $       */
+/*     $NetBSD: spec_vnops.c,v 1.209 2022/03/28 12:37:56 riastradh 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.208 2022/03/28 12:37:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.209 2022/03/28 12:37:56 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -591,6 +591,7 @@
 {
        specnode_t *sn;
        specdev_t *sd;
+       struct vnode **vpp;
 
        KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
 
@@ -603,10 +604,10 @@
 
        mutex_enter(&device_lock);
        KASSERT(sn->sn_opencnt <= sd->sd_opencnt);
+       sn->sn_gone = true;
        if (sn->sn_opencnt != 0) {
                sd->sd_opencnt -= (sn->sn_opencnt - 1);
                sn->sn_opencnt = 1;
-               sn->sn_gone = true;
                mutex_exit(&device_lock);
 
                VOP_CLOSE(vp, FNONBLOCK, NOCRED);
@@ -624,6 +625,22 @@
         */
        while (sd->sd_closing)
                cv_wait(&specfs_iocv, &device_lock);
+
+       /*
+        * Remove from the hash so lookups stop returning this
+        * specnode.  We will dissociate it from the specdev -- and
+        * possibly free the specdev -- in spec_node_destroy.
+        */
+       KASSERT(sn->sn_gone);
+       KASSERT(sn->sn_opencnt == 0);
+       for (vpp = &specfs_hash[SPECHASH(vp->v_rdev)];;
+            vpp = &(*vpp)->v_specnext) {
+               if (*vpp == vp) {
+                       *vpp = vp->v_specnext;
+                       vp->v_specnext = NULL;
+                       break;
+               }
+       }
        mutex_exit(&device_lock);
 }
 
@@ -636,7 +653,6 @@
 {
        specnode_t *sn;
        specdev_t *sd;
-       vnode_t **vpp, *vp2;
        int refcnt;
 
        sn = vp->v_specnode;
@@ -647,22 +663,6 @@
        KASSERT(sn->sn_opencnt == 0);
 
        mutex_enter(&device_lock);
-       /* Remove from the hash and destroy the node. */
-       vpp = &specfs_hash[SPECHASH(vp->v_rdev)];
-       for (vp2 = *vpp;; vp2 = vp2->v_specnext) {
-               if (vp2 == NULL) {
-                       panic("spec_node_destroy: corrupt hash");
-               }
-               if (vp2 == vp) {
-                       KASSERT(vp == *vpp);
-                       *vpp = vp->v_specnext;
-                       break;
-               }
-               if (vp2->v_specnext == vp) {
-                       vp2->v_specnext = vp->v_specnext;
-                       break;
-               }
-       }
        sn = vp->v_specnode;
        vp->v_specnode = NULL;
        refcnt = sd->sd_refcnt--;



Home | Main Index | Thread Index | Old Index