Source-Changes-HG archive

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

[src/trunk]: src Add a marker VUSECOUNT_VGET to v_usecount that gets set when...



details:   https://anonhg.NetBSD.org/src/rev/6146938e0198
branches:  trunk
changeset: 361604:6146938e0198
user:      hannken <hannken%NetBSD.org@localhost>
date:      Thu Feb 17 14:39:14 2022 +0000

description:
Add a marker VUSECOUNT_VGET to v_usecount that gets set whenever
vcache_vget() or vache_tryvget() succeeds.

Use it to rerun VOP_INACTIVE() if another thread ran a vget()..vrele()
cycle while we inactivated our last reference.

diffstat:

 sys/kern/vfs_vnode.c   |  112 ++++++++++++++++++++++++++++++------------------
 usr.sbin/pstat/pstat.c |    6 +-
 2 files changed, 72 insertions(+), 46 deletions(-)

diffs (223 lines):

diff -r c6de4ea88c38 -r 6146938e0198 sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c      Thu Feb 17 14:38:06 2022 +0000
+++ b/sys/kern/vfs_vnode.c      Thu Feb 17 14:39:14 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_vnode.c,v 1.131 2022/02/17 14:38:06 hannken Exp $  */
+/*     $NetBSD: vfs_vnode.c,v 1.132 2022/02/17 14:39:14 hannken 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.131 2022/02/17 14:38:06 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.132 2022/02/17 14:39:14 hannken Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pax.h"
@@ -232,9 +232,12 @@
 /*
  * The high bit of v_usecount is a gate for vcache_tryvget().  It's set
  * only when the vnode state is LOADED.
+ * The next bit of v_usecount is a flag for vrelel().  It's set
+ * from vcache_vget() and vcache_tryvget() whenever the operation succeeds.
  */
-#define        VUSECOUNT_MASK  0x7fffffff
+#define        VUSECOUNT_MASK  0x3fffffff
 #define        VUSECOUNT_GATE  0x80000000
+#define        VUSECOUNT_VGET  0x40000000
 
 /*
  * Return the current usecount of a vnode.
@@ -777,8 +780,10 @@
 {
        const bool async = ((flags & VRELEL_ASYNC) != 0);
        bool recycle, defer;
+       u_int use, next;
        int error;
 
+retry:
        KASSERT(mutex_owned(vp->v_interlock));
 
        if (__predict_false(vp->v_op == dead_vnodeop_p &&
@@ -787,17 +792,34 @@
        }
 
        /*
-        * If not the last reference, just drop the reference count and
-        * unlock.  VOP_UNLOCK() is called here without a vnode reference
-        * held, but is ok as the hold of v_interlock will stop the vnode
-        * from disappearing.
+        * If not the last reference, just unlock and drop the reference count.
+        *
+        * Otherwise make sure we pass a point in time where we hold the
+        * last reference with VGET flag unset.
         */
-       if (vtryrele(vp)) {
-               if (lktype != LK_NONE) {
-                       VOP_UNLOCK(vp);
+       for (use = atomic_load_relaxed(&vp->v_usecount);; use = next) {
+               if (__predict_false((use & VUSECOUNT_MASK) > 1)) {
+                       if (lktype != LK_NONE) {
+                               mutex_exit(vp->v_interlock);
+                               lktype = LK_NONE;
+                               VOP_UNLOCK(vp);
+                               mutex_enter(vp->v_interlock);
+                       }
+                       if (vtryrele(vp)) {
+                               mutex_exit(vp->v_interlock);
+                               return;
+                       }
+                       next = atomic_load_relaxed(&vp->v_usecount);
+                       continue;
                }
-               mutex_exit(vp->v_interlock);
-               return;
+               KASSERT((use & VUSECOUNT_MASK) == 1);
+               next = use & ~VUSECOUNT_VGET;
+               if (next != use) {
+                       next = atomic_cas_uint(&vp->v_usecount, use, next);
+               }
+               if (__predict_true(next == use)) {
+                       break;
+               }
        }
        if (vrefcnt(vp) <= 0 || vp->v_writecount != 0) {
                vnpanic(vp, "%s: bad ref count", __func__);
@@ -879,32 +901,20 @@
        rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
        mutex_enter(vp->v_interlock);
 
-       for (;;) {
-               /*
-                * If no longer the last reference, try to shed it. 
-                * On success, drop the interlock last thereby
-                * preventing the vnode being freed behind us.
-                */
-               if (vtryrele(vp)) {
-                       VOP_UNLOCK(vp);
-                       rw_exit(vp->v_uobj.vmobjlock);
-                       mutex_exit(vp->v_interlock);
-                       return;
+       /*
+        * Block new references then check again to see if a
+        * new reference was acquired in the meantime.  If
+        * it was, restore the vnode state and try again.
+        */
+       if (recycle) {
+               VSTATE_CHANGE(vp, VS_LOADED, VS_BLOCKED);
+               use = atomic_load_relaxed(&vp->v_usecount);
+               if ((use & VUSECOUNT_VGET) != 0 ||
+                   (use & VUSECOUNT_MASK) != 1) {
+                       VSTATE_CHANGE(vp, VS_BLOCKED, VS_LOADED);
+                       goto retry;
                }
-               /*
-                * Block new references then check again to see if a
-                * new reference was acquired in the meantime.  If
-                * it was, restore the vnode state and try again.
-                */
-               if (recycle) {
-                       VSTATE_CHANGE(vp, VS_LOADED, VS_BLOCKED);
-                       if (vrefcnt(vp) != 1) {
-                               VSTATE_CHANGE(vp, VS_BLOCKED, VS_LOADED);
-                               continue;
-                       }
-               }
-               break;
-               }
+       }
 
        /* Take care of space accounting. */
        if ((vp->v_iflag & VI_EXECMAP) != 0) {
@@ -921,17 +931,30 @@
        if (recycle) {
                VSTATE_ASSERT(vp, VS_BLOCKED);
                /* vcache_reclaim drops the lock. */
+               lktype = LK_NONE;
                vcache_reclaim(vp);
        } else {
+               lktype = LK_NONE;
                VOP_UNLOCK(vp);
        }
        KASSERT(vrefcnt(vp) > 0);
 
 out:
-       if ((atomic_dec_uint_nv(&vp->v_usecount) & VUSECOUNT_MASK) != 0) {
-               /* Gained another reference while being reclaimed. */
-               mutex_exit(vp->v_interlock);
-               return;
+       for (use = atomic_load_relaxed(&vp->v_usecount);; use = next) {
+               if (__predict_false((use & VUSECOUNT_VGET) != 0 &&
+                   (use & VUSECOUNT_MASK) == 1)) {
+                       /* Gained and released another reference, retry. */
+                       goto retry;
+               }
+               next = atomic_cas_uint(&vp->v_usecount, use, use - 1);
+               if (__predict_true(next == use)) {
+                       if (__predict_false((use & VUSECOUNT_MASK) != 1)) {
+                               /* Gained another reference. */
+                               mutex_exit(vp->v_interlock);
+                               return;
+                       }
+                       break;
+               }
        }
 
        if (VSTATE_GET(vp) == VS_RECLAIMED && vp->v_holdcnt == 0) {
@@ -1399,7 +1422,8 @@
                if (__predict_false((use & VUSECOUNT_GATE) == 0)) {
                        return EBUSY;
                }
-               next = atomic_cas_uint(&vp->v_usecount, use, use + 1);
+               next = atomic_cas_uint(&vp->v_usecount,
+                   use, (use + 1) | VUSECOUNT_VGET);
                if (__predict_true(next == use)) {
                        return 0;
                }
@@ -1416,6 +1440,7 @@
 int
 vcache_vget(vnode_t *vp)
 {
+       int error;
 
        KASSERT(mutex_owned(vp->v_interlock));
 
@@ -1433,7 +1458,8 @@
                return ENOENT;
        }
        VSTATE_ASSERT(vp, VS_LOADED);
-       atomic_inc_uint(&vp->v_usecount);
+       error = vcache_tryvget(vp);
+       KASSERT(error == 0);
        mutex_exit(vp->v_interlock);
 
        return 0;
diff -r c6de4ea88c38 -r 6146938e0198 usr.sbin/pstat/pstat.c
--- a/usr.sbin/pstat/pstat.c    Thu Feb 17 14:38:06 2022 +0000
+++ b/usr.sbin/pstat/pstat.c    Thu Feb 17 14:39:14 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pstat.c,v 1.133 2021/11/27 22:30:26 rillig Exp $       */
+/*     $NetBSD: pstat.c,v 1.134 2022/02/17 14:39:14 hannken Exp $      */
 
 /*-
  * Copyright (c) 1980, 1991, 1993, 1994
@@ -39,7 +39,7 @@
 #if 0
 static char sccsid[] = "@(#)pstat.c    8.16 (Berkeley) 5/9/95";
 #else
-__RCSID("$NetBSD: pstat.c,v 1.133 2021/11/27 22:30:26 rillig Exp $");
+__RCSID("$NetBSD: pstat.c,v 1.134 2022/02/17 14:39:14 hannken Exp $");
 #endif
 #endif /* not lint */
 
@@ -444,7 +444,7 @@
        PRWORD(ovflw, "%*lx", PTRSTRWIDTH, 0, (long)avnode);
        PRWORD(ovflw, " %*s", 4, 1, type);
        PRWORD(ovflw, " %*s", 6, 1, flags);
-#define   VUSECOUNT_MASK  0x7fffffff   /* XXX: kernel private */
+#define   VUSECOUNT_MASK  0x3fffffff   /* XXX: kernel private */
        PRWORD(ovflw, " %*d", 5, 1, vp->v_usecount & VUSECOUNT_MASK);
        PRWORD(ovflw, " %*d", 5, 1, vp->v_holdcnt);
        PRWORD(ovflw, " %*d", 4, 1, vp->v_tag);



Home | Main Index | Thread Index | Old Index