kernel - Rewrite vnode ref-counting code to improve performance
authorSascha Wildner <saw@online.de>
Sun, 20 Oct 2013 08:04:36 +0000 (10:04 +0200)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 21 Oct 2013 18:05:47 +0000 (11:05 -0700)
* Rewrite the vnode ref-counting code and modify operation to not
  immediately VOP_INACTIVE a vnode when its refs drops to 0.  By
  doing so we avoid cycling vnodes through exclusive locks when
  temporarily accessing them (such as in a path lookup).  Shared
  locks can be used throughout.

* Track active/inactive vnodes a bit differently, keep track of
  the number of vnodes that are still active but have zero refs,
  and rewrite the vnode freeing code to use the new statistics
  to deactivate cached vnodes.

37 files changed:
sys/gnu/vfs/ext2fs/ext2_inode.c
sys/gnu/vfs/ext2fs/ext2_vnops.c
sys/kern/vfs_cache.c
sys/kern/vfs_lock.c
sys/kern/vfs_mount.c
sys/kern/vfs_subr.c
sys/kern/vfs_syscalls.c
sys/sys/vnode.h
sys/vfs/fifofs/fifo_vnops.c
sys/vfs/hammer/hammer_inode.c
sys/vfs/hammer2/hammer2_inode.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/msdosfs/msdosfs_vfsops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nwfs/nwfs_node.c
sys/vfs/nwfs/nwfs_vfsops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/procfs/procfs_subr.c
sys/vfs/smbfs/smbfs_node.c
sys/vfs/smbfs/smbfs_vfsops.c
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/tmpfs/tmpfs_subr.c
sys/vfs/tmpfs/tmpfs_vfsops.c
sys/vfs/ufs/ufs_inode.c
sys/vfs/ufs/ufs_vnops.c
sys/vfs/union/union_subr.c
sys/vfs/union/union_vnops.c
sys/vm/vnode_pager.c
test/debug/vnodeinfo.c
usr.bin/systat/vmstat.c
usr.sbin/pstat/pstat.c

index 5f305cc..80e00b0 100644 (file)
@@ -482,7 +482,7 @@ ext2_inactive(struct vop_inactive_args *ap)
        int mode, error = 0;
 
        ext2_discard_prealloc(ip);
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("ext2_inactive: pushing active", vp);
 
        /*
@@ -528,7 +528,7 @@ ext2_reclaim(struct vop_reclaim_args *ap)
        int i;
 #endif
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("ext2_reclaim: pushing active", vp);
        ip = VTOI(vp);
 
index ae1e802..19e6973 100644 (file)
@@ -1300,7 +1300,7 @@ ext2_close(struct vop_close_args *ap)
 {
        struct vnode *vp = ap->a_vp;
 
-       if (vp->v_sysref.refcnt > 1)
+       if (VREFCNT(vp) > 1)
                ext2_itimes(vp);
        return (vop_stdclose(ap));
 }
@@ -1802,7 +1802,7 @@ ext2fifo_close(struct vop_close_args *ap)
 {
        struct vnode *vp = ap->a_vp;
 
-       if (vp->v_sysref.refcnt > 1)
+       if (VREFCNT(vp) > 1)
                ext2_itimes(vp);
        return (VOCALL(&fifo_vnode_vops, &ap->a_head));
 }
index d1d7f23..b5b3e43 100644 (file)
@@ -1788,13 +1788,16 @@ _cache_unlink(struct namecache *ncp)
        ncp->nc_flag |= NCF_DESTROYED;
 
        /*
-        * Attempt to trigger a deactivation.
+        * Attempt to trigger a deactivation.  Set VAUX_FINALIZE to
+        * force action on the 1->0 transition.
         */
        if ((ncp->nc_flag & NCF_UNRESOLVED) == 0 &&
-           (vp = ncp->nc_vp) != NULL &&
-           !sysref_isactive(&vp->v_sysref)) {
-               if (vget(vp, LK_SHARED) == 0)
-                       vput(vp);
+           (vp = ncp->nc_vp) != NULL) {
+               atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
+               if (VREFCNT(vp) <= 0) {
+                       if (vget(vp, LK_SHARED) == 0)
+                               vput(vp);
+               }
        }
 }
 
index e5394fb..f8b905d 100644 (file)
  */
 
 /*
- * External virtual filesystem routines
+ * External lock/ref-related vnode functions
+ *
+ * vs_state transition locking requirements:
+ *
+ *     INACTIVE -> CACHED|DYING        vx_lock(excl) + vfs_spin
+ *     DYING    -> CACHED              vx_lock(excl)
+ *     ACTIVE   -> INACTIVE            (none)       + v_spin + vfs_spin
+ *     INACTIVE -> ACTIVE              vn_lock(any) + v_spin + vfs_spin
+ *     CACHED   -> ACTIVE              vn_lock(any) + v_spin + vfs_spin
+ *
+ * NOTE: Switching to/from ACTIVE/INACTIVE requires v_spin and vfs_spin,
+ *
+ *      Switching into ACTIVE also requires a vref and vnode lock, however
+ *      the vnode lock is allowed to be SHARED.
+ *
+ *      Switching into a CACHED or DYING state requires an exclusive vnode
+ *      lock or vx_lock (which is almost the same thing).
  */
 
 #include <sys/param.h>
 
 #include <sys/buf2.h>
 #include <sys/thread2.h>
-#include <sys/sysref2.h>
 
 static void vnode_terminate(struct vnode *vp);
-static boolean_t vnode_ctor(void *obj, void *private, int ocflags);
-static void vnode_dtor(void *obj, void *private);
 
 static MALLOC_DEFINE(M_VNODE, "vnodes", "vnode structures");
-static struct sysref_class vnode_sysref_class = {
-       .name =         "vnode",
-       .mtype =        M_VNODE,
-       .proto =        SYSREF_PROTO_VNODE,
-       .offset =       offsetof(struct vnode, v_sysref),
-       .objsize =      sizeof(struct vnode),
-       .nom_cache =    256,
-       .flags =        SRC_MANAGEDINIT,
-       .ctor =         vnode_ctor,
-       .dtor =         vnode_dtor,
-       .ops = {
-               .terminate = (sysref_terminate_func_t)vnode_terminate,
-               .lock = (sysref_terminate_func_t)vx_lock,
-               .unlock = (sysref_terminate_func_t)vx_unlock
-       }
-};
 
 /*
  * The vnode free list hold inactive vnodes.  Aged inactive vnodes
  * are inserted prior to the mid point, and otherwise inserted
  * at the tail.
  */
-static TAILQ_HEAD(freelst, vnode) vnode_free_list;
-static struct vnode    vnode_free_mid1;
-static struct vnode    vnode_free_mid2;
-static struct vnode    vnode_free_rover;
+TAILQ_HEAD(freelst, vnode);
+static struct freelst  vnode_active_list;
+static struct freelst  vnode_inactive_list;
+static struct vnode    vnode_active_rover;
+static struct vnode    vnode_inactive_mid1;
+static struct vnode    vnode_inactive_mid2;
+static struct vnode    vnode_inactive_rover;
 static struct spinlock vfs_spin = SPINLOCK_INITIALIZER(vfs_spin);
 static enum { ROVER_MID1, ROVER_MID2 } rover_state = ROVER_MID2;
 
-int  freevnodes = 0;
-SYSCTL_INT(_debug, OID_AUTO, freevnodes, CTLFLAG_RD,
-       &freevnodes, 0, "Number of free nodes");
+int  activevnodes = 0;
+SYSCTL_INT(_debug, OID_AUTO, activevnodes, CTLFLAG_RD,
+       &activevnodes, 0, "Number of active nodes");
+int  cachedvnodes = 0;
+SYSCTL_INT(_debug, OID_AUTO, cachedvnodes, CTLFLAG_RD,
+       &cachedvnodes, 0, "Number of total cached nodes");
+int  inactivevnodes = 0;
+SYSCTL_INT(_debug, OID_AUTO, inactivevnodes, CTLFLAG_RD,
+       &inactivevnodes, 0, "Number of inactive nodes");
 static int wantfreevnodes = 25;
 SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW,
        &wantfreevnodes, 0, "Desired number of free vnodes");
@@ -110,10 +116,12 @@ SYSCTL_ULONG(_debug, OID_AUTO, trackvnode, CTLFLAG_RW,
 void
 vfs_lock_init(void)
 {
-       TAILQ_INIT(&vnode_free_list);
-       TAILQ_INSERT_TAIL(&vnode_free_list, &vnode_free_mid1, v_freelist);
-       TAILQ_INSERT_TAIL(&vnode_free_list, &vnode_free_mid2, v_freelist);
-       TAILQ_INSERT_TAIL(&vnode_free_list, &vnode_free_rover, v_freelist);
+       TAILQ_INIT(&vnode_inactive_list);
+       TAILQ_INIT(&vnode_active_list);
+       TAILQ_INSERT_TAIL(&vnode_active_list, &vnode_active_rover, v_list);
+       TAILQ_INSERT_TAIL(&vnode_inactive_list, &vnode_inactive_mid1, v_list);
+       TAILQ_INSERT_TAIL(&vnode_inactive_list, &vnode_inactive_mid2, v_list);
+       TAILQ_INSERT_TAIL(&vnode_inactive_list, &vnode_inactive_rover, v_list);
        spin_init(&vfs_spin);
        kmalloc_raise_limit(M_VNODE, 0);        /* unlimited */
 }
@@ -148,55 +156,49 @@ vclrflags(struct vnode *vp, int flags)
 }
 
 /*
- * Inline helper functions.
+ * Remove the vnode from the inactive list.
  *
- * WARNING: vbusy() may only be called while the vnode lock or VX lock
- *         is held.  The vnode spinlock need not be held.
- *
- * MPSAFE
+ * _vactivate() may only be called while the vnode lock or VX lock is held.
+ * The vnode spinlock need not be held.
  */
-static __inline
-void
-__vbusy_interlocked(struct vnode *vp)
-{
-       KKASSERT(vp->v_flag & VFREE);
-       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-       freevnodes--;
-       _vclrflags(vp, VFREE);
-}
-
 static __inline 
 void
-__vbusy(struct vnode *vp)
+_vactivate(struct vnode *vp)
 {
 #ifdef TRACKVNODE
        if ((ulong)vp == trackvnode)
-               kprintf("__vbusy %p %08x\n", vp, vp->v_flag);
+               kprintf("_vactivate %p %08x\n", vp, vp->v_flag);
 #endif
        spin_lock(&vfs_spin);
-       __vbusy_interlocked(vp);
+       KKASSERT(vp->v_state == VS_INACTIVE || vp->v_state == VS_CACHED);
+       if (vp->v_state == VS_INACTIVE) {
+               TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+               --inactivevnodes;
+       }
+       TAILQ_INSERT_TAIL(&vnode_active_list, vp, v_list);
+       vp->v_state = VS_ACTIVE;
+       ++activevnodes;
        spin_unlock(&vfs_spin);
 }
 
 /*
- * Put a vnode on the free list.  The caller has cleared VCACHED or owns the
- * implied sysref related to having removed the vnode from the freelist
- * (and VCACHED is already clear in that case).
+ * Put a vnode on the inactive list.  The vnode must not currently reside on
+ * any list (must be VS_CACHED).  Vnode should be VINACTIVE.
  *
- * MPSAFE
+ * Caller must hold v_spin
  */
 static __inline
 void
-__vfree(struct vnode *vp)
+_vinactive(struct vnode *vp)
 {
 #ifdef TRACKVNODE
        if ((ulong)vp == trackvnode) {
-               kprintf("__vfree %p %08x\n", vp, vp->v_flag);
+               kprintf("_vinactive %p %08x\n", vp, vp->v_flag);
                print_backtrace(-1);
        }
 #endif
        spin_lock(&vfs_spin);
-       KKASSERT((vp->v_flag & VFREE) == 0);
+       KKASSERT(vp->v_state == VS_CACHED);
 
        /*
         * Distinguish between basically dead vnodes, vnodes with cached
@@ -204,48 +206,42 @@ __vfree(struct vnode *vp)
         * vnodes around as their cache status is lost.
         */
        if (vp->v_flag & VRECLAIMED) {
-               TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
+               TAILQ_INSERT_HEAD(&vnode_inactive_list, vp, v_list);
        } else if (vp->v_object && vp->v_object->resident_page_count) {
-               TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
+               TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list);
        } else if (vp->v_object && vp->v_object->swblock_count) {
-               TAILQ_INSERT_BEFORE(&vnode_free_mid2, vp, v_freelist);
+               TAILQ_INSERT_BEFORE(&vnode_inactive_mid2, vp, v_list);
        } else {
-               TAILQ_INSERT_BEFORE(&vnode_free_mid1, vp, v_freelist);
+               TAILQ_INSERT_BEFORE(&vnode_inactive_mid1, vp, v_list);
        }
-       freevnodes++;
-       _vsetflags(vp, VFREE);
+       ++inactivevnodes;
+       vp->v_state = VS_INACTIVE;
        spin_unlock(&vfs_spin);
 }
 
-/*
- * Put a vnode on the free list.  The caller has cleared VCACHED or owns the
- * implied sysref related to having removed the vnode from the freelist
- * (and VCACHED is already clear in that case).
- *
- * MPSAFE
- */
 static __inline
 void
-__vfreetail(struct vnode *vp)
+_vinactive_tail(struct vnode *vp)
 {
 #ifdef TRACKVNODE
        if ((ulong)vp == trackvnode)
-               kprintf("__vfreetail %p %08x\n", vp, vp->v_flag);
+               kprintf("_vinactive_tail %p %08x\n", vp, vp->v_flag);
 #endif
        spin_lock(&vfs_spin);
-       KKASSERT((vp->v_flag & VFREE) == 0);
-       TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
-       freevnodes++;
-       _vsetflags(vp, VFREE);
+       KKASSERT(vp->v_state == VS_CACHED);
+       TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list);
+       ++inactivevnodes;
+       vp->v_state = VS_INACTIVE;
        spin_unlock(&vfs_spin);
 }
 
 /*
- * Return a C boolean if we should put the vnode on the freelist (VFREE),
- * or leave it / mark it as VCACHED.
+ * Return a C boolean if we should put the vnode on the inactive list
+ * (VS_INACTIVE) or leave it alone.
  *
- * This routine is only valid if the vnode is already either VFREE or
- * VCACHED, or if it can become VFREE or VCACHED via vnode_terminate().
+ * This routine is only valid if the vnode is already either VS_INACTIVE or
+ * VS_CACHED, or if it can become VS_INACTIV or VS_CACHED via
+ * vnode_terminate().
  *
  * WARNING!  We used to indicate FALSE if the vnode had an object with
  *          resident pages but we no longer do that because it makes
@@ -253,42 +249,72 @@ __vfreetail(struct vnode *vp)
  *          to place the vnode properly on the list.
  *
  * WARNING!  This functions is typically called with v_spin held.
- *
- * MPSAFE
  */
 static __inline boolean_t
 vshouldfree(struct vnode *vp)
 {
        return (vp->v_auxrefs == 0);
-#if 0
-        && (vp->v_object == NULL || vp->v_object->resident_page_count == 0));
-#endif
 }
 
 /*
  * Add a ref to an active vnode.  This function should never be called
- * with an inactive vnode (use vget() instead).
- *
- * MPSAFE
+ * with an inactive vnode (use vget() instead), but might be called
+ * with other states.
  */
 void
 vref(struct vnode *vp)
 {
-       KKASSERT(vp->v_sysref.refcnt > 0 && 
-                (vp->v_flag & (VFREE|VINACTIVE)) == 0);
-       sysref_get(&vp->v_sysref);
+       KASSERT((VREFCNT(vp) > 0 && vp->v_state != VS_INACTIVE),
+               ("vref: bad refcnt %08x %d", vp->v_refcnt, vp->v_state));
+       atomic_add_int(&vp->v_refcnt, 1);
 }
 
 /*
- * Release a ref on an active or inactive vnode.  The sysref termination
- * function will be called when the active last active reference is released,
- * and the vnode is returned to the objcache when the last inactive
- * reference is released.
+ * Release a ref on an active or inactive vnode.
+ *
+ * If VREF_FINALIZE is set this will deactivate the vnode on the 1->0
+ * transition, otherwise we leave the vnode in the active list and
+ * do a lockless transition to 0, which is very important for the
+ * critical path.
  */
 void
 vrele(struct vnode *vp)
 {
-       sysref_put(&vp->v_sysref);
+       for (;;) {
+               int count = vp->v_refcnt;
+               cpu_ccfence();
+               KKASSERT((count & VREF_MASK) > 0);
+
+               /*
+                * 2+ case
+                */
+               if ((count & VREF_MASK) > 1) {
+                       if (atomic_cmpset_int(&vp->v_refcnt, count, count - 1))
+                               break;
+                       continue;
+               }
+
+               /*
+                * 1->0 transition case must handle possible finalization.
+                * When finalizing we transition 1->0x40000000.  Note that
+                * cachedvnodes is only adjusted on transitions to ->0.
+                */
+               if (count & VREF_FINALIZE) {
+                       vx_lock(vp);
+                       if (atomic_cmpset_int(&vp->v_refcnt,
+                                             count, VREF_TERMINATE)) {
+                               vnode_terminate(vp);
+                               break;
+                       }
+                       vx_unlock(vp);
+               } else {
+                       if (atomic_cmpset_int(&vp->v_refcnt, count, 0)) {
+                               atomic_add_int(&cachedvnodes, 1);
+                               break;
+                       }
+               }
+               /* retry */
+       }
 }
 
 /*
@@ -300,24 +326,15 @@ vrele(struct vnode *vp)
  * An auxiliary reference DOES prevent the vnode from being destroyed,
  * allowing you to vx_lock() it, test state, etc.
  *
- * An auxiliary reference DOES NOT move a vnode out of the VFREE state
- * once it has entered it.
+ * An auxiliary reference DOES NOT move a vnode out of the VS_INACTIVE
+ * state once it has entered it.
  *
- * WARNING!  vhold() and vhold_interlocked() must not acquire v_spin.
- *          The spinlock may or may not already be held by the caller.
- *          vdrop() will clean up the free list state.
- *
- * MPSAFE
+ * WARNING!  vhold() must not acquire v_spin.  The spinlock may or may not
+ *          already be held by the caller.  vdrop() will clean up the
+ *          free list state.
  */
 void
 vhold(struct vnode *vp)
-{
-       KKASSERT(vp->v_sysref.refcnt != 0);
-       atomic_add_int(&vp->v_auxrefs, 1);
-}
-
-void
-vhold_interlocked(struct vnode *vp)
 {
        atomic_add_int(&vp->v_auxrefs, 1);
 }
@@ -325,124 +342,95 @@ vhold_interlocked(struct vnode *vp)
 /*
  * Remove an auxiliary reference from the vnode.
  *
- * vdrop needs to check for a VCACHE->VFREE transition to catch cases
- * where a vnode is held past its reclamation.  We use v_spin to
- * interlock VCACHED -> !VCACHED transitions.
- *
- * MPSAFE
+ * vdrop must check for the case where a vnode is held past its reclamation.
+ * We use v_spin to interlock VS_CACHED -> VS_INACTIVE transitions.
  */
 void
 vdrop(struct vnode *vp)
 {
-       KKASSERT(vp->v_sysref.refcnt != 0 && vp->v_auxrefs > 0);
-       spin_lock(&vp->v_spin);
-       atomic_subtract_int(&vp->v_auxrefs, 1);
-       if ((vp->v_flag & VCACHED) && vshouldfree(vp)) {
-               _vclrflags(vp, VCACHED);
-               __vfree(vp);
+       for (;;) {
+               int count = vp->v_auxrefs;
+               cpu_ccfence();
+               KKASSERT(count > 0);
+
+               /*
+                * 2+ case
+                */
+               if (count > 1) {
+                       if (atomic_cmpset_int(&vp->v_auxrefs, count, count - 1))
+                               break;
+                       continue;
+               }
+
+               /*
+                * 1->0 transition case must check for reclaimed vnodes that
+                * are expected to be placed on the inactive list.
+                *
+                * v_spin is required for the 1->0 transition.
+                *
+                * 1->0 and 0->1 transitions are allowed to race.  The
+                * vp simply remains on the inactive list.
+                */
+               spin_lock(&vp->v_spin);
+               if (atomic_cmpset_int(&vp->v_auxrefs, 1, 0)) {
+                       if (vp->v_state == VS_CACHED && vshouldfree(vp))
+                               _vinactive(vp);
+                       spin_unlock(&vp->v_spin);
+                       break;
+               }
+               spin_unlock(&vp->v_spin);
+               /* retry */
        }
-       spin_unlock(&vp->v_spin);
 }
 
 /*
- * This function is called when the last active reference on the vnode
- * is released, typically via vrele().  SYSREF will VX lock the vnode
- * and then give the vnode a negative ref count, indicating that it is
- * undergoing termination or is being set aside for the cache, and one
- * final sysref_put() is required to actually return it to the memory
- * subsystem.
+ * This function is called with vp vx_lock'd when the last active reference
+ * on the vnode is released, typically via vrele().  v_refcnt will be set
+ * to VREF_TERMINATE.
  *
- * Additional inactive sysrefs may race us but that's ok.  Reactivations
- * cannot race us because the sysref code interlocked with the VX lock
- * (which is held on call).
+ * Additional vrefs are allowed to race but will not result in a reentrant
+ * call to vnode_terminate() due to VREF_TERMINATE.
  *
- * MPSAFE
+ * NOTE: v_mount may be NULL due to assigmment to dead_vnode_vops
+ *
+ * NOTE: The vnode may be marked inactive with dirty buffers
+ *      or dirty pages in its cached VM object still present.
+ *
+ * NOTE: VS_FREE should not be set on entry (the vnode was expected to
+ *      previously be active).  We lose control of the vnode the instant
+ *      it is placed on the free list.
+ *
+ *      The VX lock is required when transitioning to VS_CACHED but is
+ *      not sufficient for the vshouldfree() interlocked test or when
+ *      transitioning away from VS_CACHED.  v_spin is also required for
+ *      those cases.
  */
 void
 vnode_terminate(struct vnode *vp)
 {
-       /*
-        * We own the VX lock, it should not be possible for someone else
-        * to have reactivated the vp.
-        */
-       KKASSERT(sysref_isinactive(&vp->v_sysref));
+       KKASSERT(vp->v_state == VS_ACTIVE);
 
-       /*
-        * Deactivate the vnode by marking it VFREE or VCACHED.
-        * The vnode can be reactivated from either state until
-        * reclaimed.  These states inherit the 'last' sysref on the
-        * vnode.
-        *
-        * NOTE: There may be additional inactive references from
-        * other entities blocking on the VX lock while we hold it,
-        * but this does not prevent us from changing the vnode's
-        * state.
-        *
-        * NOTE: The vnode could already be marked inactive.  XXX
-        *       how?
-        *
-        * NOTE: v_mount may be NULL due to assignment to
-        *       dead_vnode_vops
-        *
-        * NOTE: The vnode may be marked inactive with dirty buffers
-        *       or dirty pages in its cached VM object still present.
-        *
-        * NOTE: VCACHED should not be set on entry.  We lose control
-        *       of the sysref the instant the vnode is placed on the
-        *       free list or when VCACHED is set.
-        *
-        *       The VX lock is required when transitioning to
-        *       +VCACHED but is not sufficient for the vshouldfree()
-        *       interlocked test or when transitioning to -VCACHED.
-        */
        if ((vp->v_flag & VINACTIVE) == 0) {
                _vsetflags(vp, VINACTIVE);
                if (vp->v_mount)
                        VOP_INACTIVE(vp);
+               /* might deactivate page */
        }
        spin_lock(&vp->v_spin);
-       KKASSERT((vp->v_flag & (VFREE|VCACHED)) == 0);
-       if (vshouldfree(vp))
-               __vfree(vp);
-       else
-               _vsetflags(vp, VCACHED); /* inactive but not yet free*/
+       if (vp->v_state == VS_ACTIVE) {
+               spin_lock(&vfs_spin);
+               KKASSERT(vp->v_state == VS_ACTIVE);
+               TAILQ_REMOVE(&vnode_active_list, vp, v_list);
+               --activevnodes;
+               vp->v_state = VS_CACHED;
+               spin_unlock(&vfs_spin);
+       }
+       if (vp->v_state == VS_CACHED && vshouldfree(vp))
+               _vinactive(vp);
        spin_unlock(&vp->v_spin);
        vx_unlock(vp);
 }
 
-/*
- * Physical vnode constructor / destructor.  These are only executed on
- * the backend of the objcache.  They are NOT executed on every vnode
- * allocation or deallocation.
- *
- * MPSAFE
- */
-boolean_t
-vnode_ctor(void *obj, void *private, int ocflags)
-{
-       struct vnode *vp = obj;
-
-       lwkt_token_init(&vp->v_token, "vnode");
-       lockinit(&vp->v_lock, "vnode", 0, 0);
-       TAILQ_INIT(&vp->v_namecache);
-       RB_INIT(&vp->v_rbclean_tree);
-       RB_INIT(&vp->v_rbdirty_tree);
-       RB_INIT(&vp->v_rbhash_tree);
-       spin_init(&vp->v_spin);
-       return(TRUE);
-}
-
-/*
- * MPSAFE
- */
-void
-vnode_dtor(void *obj, void *private)
-{
-       struct vnode *vp __debugvar = obj;
-
-       KKASSERT((vp->v_flag & (VCACHED|VFREE)) == 0);
-}
-
 /****************************************************************
  *                     VX LOCKING FUNCTIONS                    *
  ****************************************************************
@@ -490,9 +478,10 @@ vx_unlock(struct vnode *vp)
  *                     VNODE ACQUISITION FUNCTIONS             *
  ****************************************************************
  *
- * These functions must be used when accessing a vnode via an auxiliary
- * reference such as the namecache or free list, or when you wish to
- * do a combo ref+lock sequence.
+ * These functions must be used when accessing a vnode that has no
+ * chance of being destroyed in a SMP race.  That means the caller will
+ * usually either hold an auxiliary reference (such as the namecache)
+ * or hold some other lock that ensures that the vnode cannot be destroyed.
  *
  * These functions are MANDATORY for any code chain accessing a vnode
  * whos activation state is not known.
@@ -518,19 +507,20 @@ vget(struct vnode *vp, int flags)
        }
 
        /*
-        * Reference the structure and then acquire the lock.  0->1
-        * transitions and refs during termination are allowed here so
-        * call sysref directly.
+        * Reference the structure and then acquire the lock.
         *
         * NOTE: The requested lock might be a shared lock and does
         *       not protect our access to the refcnt or other fields.
         */
-       sysref_get(&vp->v_sysref);
+       if (atomic_fetchadd_int(&vp->v_refcnt, 1) == 0)
+               atomic_add_int(&cachedvnodes, -1);
+
        if ((error = vn_lock(vp, flags)) != 0) {
                /*
-                * The lock failed, undo and return an error.
+                * The lock failed, undo and return an error.  This will not
+                * normally trigger a termination.
                 */
-               sysref_put(&vp->v_sysref);
+               vrele(vp);
        } else if (vp->v_flag & VRECLAIMED) {
                /*
                 * The node is being reclaimed and cannot be reactivated
@@ -539,39 +529,53 @@ vget(struct vnode *vp, int flags)
                vn_unlock(vp);
                vrele(vp);
                error = ENOENT;
+       } else if (vp->v_state == VS_ACTIVE) {
+               /*
+                * A VS_ACTIVE vnode coupled with the fact that we have
+                * a vnode lock (even if shared) prevents v_state from
+                * changing.  Since the vnode is not in a VRECLAIMED state,
+                * we can safely clear VINACTIVE.
+                *
+                * NOTE! Multiple threads may clear VINACTIVE if this is
+                *       shared lock.  This race is allowed.
+                */
+               _vclrflags(vp, VINACTIVE);
+               error = 0;
        } else {
                /*
-                * If the vnode is marked VFREE or VCACHED it needs to be
-                * reactivated, otherwise it had better already be active.
-                * VINACTIVE must also be cleared.
+                * If the vnode is not VS_ACTIVE it must be reactivated
+                * in addition to clearing VINACTIVE.  An exclusive spin_lock
+                * is needed to manipulate the vnode's list.
                 *
-                * In the VFREE/VCACHED case we have to throw away the
-                * sysref that was earmarking those cases and preventing
-                * the vnode from being destroyed.  Our sysref is still held.
+                * Because the lockmgr lock might be shared, we might race
+                * another reactivation, which we handle.  In this situation,
+                * however, the refcnt prevents other v_state races.
                 *
-                * We are allowed to reactivate the vnode while we hold
-                * the VX lock, assuming it can be reactivated.
+                * As with above, clearing VINACTIVE is allowed to race other
+                * clearings of VINACTIVE.
                 */
+               _vclrflags(vp, VINACTIVE);
                spin_lock(&vp->v_spin);
-               if (vp->v_flag & VFREE) {
-                       __vbusy(vp);
-                       sysref_activate(&vp->v_sysref);
+
+               switch(vp->v_state) {
+               case VS_INACTIVE:
+                       _vactivate(vp);
+                       atomic_clear_int(&vp->v_refcnt, VREF_TERMINATE);
                        spin_unlock(&vp->v_spin);
-                       sysref_put(&vp->v_sysref);
-               } else if (vp->v_flag & VCACHED) {
-                       _vclrflags(vp, VCACHED);
-                       sysref_activate(&vp->v_sysref);
+                       break;
+               case VS_CACHED:
+                       _vactivate(vp);
+                       atomic_clear_int(&vp->v_refcnt, VREF_TERMINATE);
                        spin_unlock(&vp->v_spin);
-                       sysref_put(&vp->v_sysref);
-               } else {
-                       if (sysref_isinactive(&vp->v_sysref)) {
-                               sysref_activate(&vp->v_sysref);
-                               kprintf("Warning vp %p reactivation race\n",
-                                       vp);
-                       }
+                       break;
+               case VS_ACTIVE:
+                       spin_unlock(&vp->v_spin);
+                       break;
+               case VS_DYING:
                        spin_unlock(&vp->v_spin);
+                       panic("Impossible VS_DYING state");
+                       break;
                }
-               _vclrflags(vp, VINACTIVE);
                error = 0;
        }
        return(error);
@@ -602,51 +606,45 @@ vput(struct vnode *vp)
 #endif
 
 /*
- * XXX The vx_*() locks should use auxrefs, not the main reference counter.
+ * Acquire the vnode lock unguarded.
  *
- * MPSAFE
+ * XXX The vx_*() locks should use auxrefs, not the main reference counter.
  */
 void
 vx_get(struct vnode *vp)
 {
-       sysref_get(&vp->v_sysref);
+       if (atomic_fetchadd_int(&vp->v_refcnt, 1) == 0)
+               atomic_add_int(&cachedvnodes, -1);
        lockmgr(&vp->v_lock, LK_EXCLUSIVE);
 }
 
-/*
- * MPSAFE
- */
 int
 vx_get_nonblock(struct vnode *vp)
 {
        int error;
 
-       sysref_get(&vp->v_sysref);
        error = lockmgr(&vp->v_lock, LK_EXCLUSIVE | LK_NOWAIT);
-       if (error)
-               sysref_put(&vp->v_sysref);
+       if (error == 0) {
+               if (atomic_fetchadd_int(&vp->v_refcnt, 1) == 0)
+                       atomic_add_int(&cachedvnodes, -1);
+       }
        return(error);
 }
 
 /*
  * Relase a VX lock that also held a ref on the vnode.
  *
- * vx_put needs to check for a VCACHED->VFREE transition to catch the
- * case where e.g. vnlru issues a vgone*().
- *
- * MPSAFE
+ * vx_put needs to check for VS_CACHED->VS_INACTIVE transitions to catch
+ * the case where e.g. vnlru issues a vgone*(), but should otherwise
+ * not mess with the v_state.
  */
 void
 vx_put(struct vnode *vp)
 {
-       spin_lock(&vp->v_spin);
-       if ((vp->v_flag & VCACHED) && vshouldfree(vp)) {
-               _vclrflags(vp, VCACHED);
-               __vfree(vp);
-       }
-       spin_unlock(&vp->v_spin);
+       if (vp->v_state == VS_CACHED && vshouldfree(vp))
+               _vinactive(vp);
        lockmgr(&vp->v_lock, LK_RELEASE);
-       sysref_put(&vp->v_sysref);
+       vrele(vp);
 }
 
 /*
@@ -664,24 +662,25 @@ vnode_free_rover_scan_locked(void)
         * Get the vnode after the rover.  The rover roves between mid1 and
         * the end so the only special vnode it can encounter is mid2.
         */
-       vp = TAILQ_NEXT(&vnode_free_rover, v_freelist);
-       if (vp == &vnode_free_mid2) {
-               vp = TAILQ_NEXT(vp, v_freelist);
+       vp = TAILQ_NEXT(&vnode_inactive_rover, v_list);
+       if (vp == &vnode_inactive_mid2) {
+               vp = TAILQ_NEXT(vp, v_list);
                rover_state = ROVER_MID2;
        }
-       KKASSERT(vp != &vnode_free_mid1);
+       KKASSERT(vp != &vnode_inactive_mid1);
 
        /*
         * Start over if we finished the scan.
         */
-       TAILQ_REMOVE(&vnode_free_list, &vnode_free_rover, v_freelist);
+       TAILQ_REMOVE(&vnode_inactive_list, &vnode_inactive_rover, v_list);
        if (vp == NULL) {
-               TAILQ_INSERT_AFTER(&vnode_free_list, &vnode_free_mid1,
-                                  &vnode_free_rover, v_freelist);
+               TAILQ_INSERT_AFTER(&vnode_inactive_list, &vnode_inactive_mid1,
+                                  &vnode_inactive_rover, v_list);
                rover_state = ROVER_MID1;
                return;
        }
-       TAILQ_INSERT_AFTER(&vnode_free_list, vp, &vnode_free_rover, v_freelist);
+       TAILQ_INSERT_AFTER(&vnode_inactive_list, vp,
+                          &vnode_inactive_rover, v_list);
 
        /*
         * Shift vp if appropriate.
@@ -691,26 +690,29 @@ vnode_free_rover_scan_locked(void)
                 * Promote vnode with resident pages to section 3.
                 */
                if (rover_state == ROVER_MID1) {
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-                       TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
+                       TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+                       TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list);
                }
        } else if (vp->v_object && vp->v_object->swblock_count) {
                /*
                 * Demote vnode with only swap pages to section 2
                 */
                if (rover_state == ROVER_MID2) {
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-                       TAILQ_INSERT_BEFORE(&vnode_free_mid2, vp, v_freelist);
+                       TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+                       TAILQ_INSERT_BEFORE(&vnode_inactive_mid2, vp, v_list);
                }
        } else {
                /*
                 * Demote vnode with no cached data to section 1
                 */
-               TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-               TAILQ_INSERT_BEFORE(&vnode_free_mid1, vp, v_freelist);
+               TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+               TAILQ_INSERT_BEFORE(&vnode_inactive_mid1, vp, v_list);
        }
 }
 
+/*
+ * Called from vnlru_proc()
+ */
 void
 vnode_free_rover_scan(int count)
 {
@@ -736,54 +738,92 @@ vnode_free_rover_scan(int count)
  */
 static
 struct vnode *
-allocfreevnode(int maxcount)
+cleanfreevnode(int maxcount)
 {
        struct vnode *vp;
        int count;
 
+       /*
+        * Try to deactivate some vnodes cached on the active list.
+        */
        for (count = 0; count < maxcount; count++) {
+               if (cachedvnodes - inactivevnodes < inactivevnodes)
+                       break;
+
+               spin_lock(&vfs_spin);
+               vp = TAILQ_NEXT(&vnode_active_rover, v_list);
+               TAILQ_REMOVE(&vnode_active_list, &vnode_active_rover, v_list);
+               if (vp == NULL) {
+                       TAILQ_INSERT_HEAD(&vnode_active_list,
+                                         &vnode_active_rover, v_list);
+               } else {
+                       TAILQ_INSERT_AFTER(&vnode_active_list, vp,
+                                          &vnode_active_rover, v_list);
+               }
+               if (vp == NULL || vp->v_refcnt != 0) {
+                       spin_unlock(&vfs_spin);
+                       continue;
+               }
+
                /*
-                * Try to lock the first vnode on the free list.
-                * Cycle if we can't.
-                *
-                * We use a bad hack in vx_lock_nonblock() which avoids
-                * the lock order reversal between vfs_spin and v_spin.
-                * This is very fragile code and I don't want to use
-                * vhold here.
+                * Try to deactivate the vnode.
                 */
+               if (atomic_fetchadd_int(&vp->v_refcnt, 1) == 0)
+                       atomic_add_int(&cachedvnodes, -1);
+               atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
+               spin_unlock(&vfs_spin);
+               vrele(vp);
+       }
+
+       /*
+        * Loop trying to lock the first vnode on the free list.
+        * Cycle if we can't.
+        *
+        * We use a bad hack in vx_lock_nonblock() which avoids
+        * the lock order reversal between vfs_spin and v_spin.
+        * This is very fragile code and I don't want to use
+        * vhold here.
+        */
+       for (count = 0; count < maxcount; count++) {
                spin_lock(&vfs_spin);
                vnode_free_rover_scan_locked();
                vnode_free_rover_scan_locked();
-               vp = TAILQ_FIRST(&vnode_free_list);
-               while (vp == &vnode_free_mid1 || vp == &vnode_free_mid2 ||
-                      vp == &vnode_free_rover) {
-                       vp = TAILQ_NEXT(vp, v_freelist);
+               vp = TAILQ_FIRST(&vnode_inactive_list);
+               while (vp == &vnode_inactive_mid1 ||
+                      vp == &vnode_inactive_mid2 ||
+                      vp == &vnode_inactive_rover) {
+                       vp = TAILQ_NEXT(vp, v_list);
                }
                if (vp == NULL) {
                        spin_unlock(&vfs_spin);
                        break;
                }
                if (vx_lock_nonblock(vp)) {
-                       KKASSERT(vp->v_flag & VFREE);
-                       TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
-                       TAILQ_INSERT_TAIL(&vnode_free_list,
-                                         vp, v_freelist);
+                       KKASSERT(vp->v_state == VS_INACTIVE);
+                       TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+                       TAILQ_INSERT_TAIL(&vnode_inactive_list, vp, v_list);
                        spin_unlock(&vfs_spin);
                        continue;
                }
 
                /*
-                * We inherit the sysref associated the vnode on the free
-                * list.  Because VCACHED is clear the vnode will not
-                * be placed back on the free list.  We own the sysref
-                * free and clear and thus control the disposition of
-                * the vnode.
+                * The vnode should be inactive (VREF_TERMINATE should still
+                * be set in v_refcnt).  Since we pulled it from the inactive
+                * list it should obviously not be VS_CACHED.  Activate the
+                * vnode.
+                *
+                * Once removed from the inactive list we inherit the
+                * VREF_TERMINATE which prevents loss of control while
+                * we mess with the vnode.
                 */
-               __vbusy_interlocked(vp);
+               KKASSERT(vp->v_state == VS_INACTIVE);
+               TAILQ_REMOVE(&vnode_inactive_list, vp, v_list);
+               --inactivevnodes;
+               vp->v_state = VS_DYING;
                spin_unlock(&vfs_spin);
 #ifdef TRACKVNODE
                if ((ulong)vp == trackvnode)
-                       kprintf("allocfreevnode %p %08x\n", vp, vp->v_flag);
+                       kprintf("cleanfreevnode %p %08x\n", vp, vp->v_flag);
 #endif
                /*
                 * Do not reclaim/reuse a vnode while auxillary refs exists.
@@ -796,26 +836,17 @@ allocfreevnode(int maxcount)
                 * until we have removed all namecache and inode references
                 * to the vnode.
                 *
-                * Because VCACHED is already in the correct state (cleared)
-                * we cannot race other vdrop()s occuring at the same time
-                * and can safely place vp on the free list.
-                *
-                * The free list association reinherits the sysref.
+                * The inactive list association reinherits the v_refcnt.
                 */
                if (vp->v_auxrefs) {
-                       __vfreetail(vp);
+                       vp->v_state = VS_CACHED;
+                       _vinactive_tail(vp);
                        vx_unlock(vp);
                        continue;
                }
 
-               /*
-                * We inherit the reference that was previously associated
-                * with the vnode being on the free list.  VCACHED had better
-                * not be set because the reference and VX lock prevents
-                * the sysref from transitioning to an active state.
-                */
-               KKASSERT((vp->v_flag & (VINACTIVE|VCACHED)) == VINACTIVE);
-               KKASSERT(sysref_isinactive(&vp->v_sysref));
+               KKASSERT(vp->v_flag & VINACTIVE);
+               KKASSERT(vp->v_refcnt & VREF_TERMINATE);
 
                /*
                 * Holding the VX lock on an inactive vnode prevents it
@@ -833,7 +864,8 @@ allocfreevnode(int maxcount)
                 */
                if ((vp->v_flag & VRECLAIMED) == 0) {
                        if (cache_inval_vp_nonblock(vp)) {
-                               __vfreetail(vp);
+                               vp->v_state = VS_CACHED;
+                               _vinactive_tail(vp);
                                vx_unlock(vp);
                                continue;
                        }
@@ -842,7 +874,7 @@ allocfreevnode(int maxcount)
                }
 
                /*
-                * We can reuse the vnode if no primary or auxiliary
+                * We can destroy the vnode if no primary or auxiliary
                 * references remain other then ours, else put it
                 * back on the free list and keep looking.
                 *
@@ -853,18 +885,28 @@ allocfreevnode(int maxcount)
                 * Since the vnode is in a VRECLAIMED state, no new
                 * namecache associations could have been made.
                 */
+               KKASSERT(vp->v_state == VS_DYING);
                KKASSERT(TAILQ_EMPTY(&vp->v_namecache));
                if (vp->v_auxrefs ||
-                   !sysref_islastdeactivation(&vp->v_sysref)) {
-                       __vfreetail(vp);
+                   (vp->v_refcnt & ~VREF_FINALIZE) != VREF_TERMINATE) {
+                       vp->v_state = VS_CACHED;
+                       _vinactive_tail(vp);
                        vx_unlock(vp);
                        continue;
                }
 
+               /*
+                * Nothing should have been able to access this vp.
+                */
+               atomic_clear_int(&vp->v_refcnt, VREF_TERMINATE|VREF_FINALIZE);
+               KASSERT(vp->v_refcnt == 0,
+                       ("vp %p badrefs %08x", vp, vp->v_refcnt));
+
                /*
                 * Return a VX locked vnode suitable for reuse.  The caller
                 * inherits the sysref.
                 */
+               KKASSERT(vp->v_state == VS_DYING);
                return(vp);
        }
        return(NULL);
@@ -889,47 +931,26 @@ allocvnode(int lktimeout, int lkflags)
         * Do not flag for recyclement unless there are enough free vnodes
         * to recycle and the number of vnodes has exceeded our target.
         */
-       if (freevnodes >= wantfreevnodes && numvnodes >= desiredvnodes) {
+       if (inactivevnodes >= wantfreevnodes && numvnodes >= desiredvnodes) {
                struct thread *td = curthread;
                if (td->td_lwp)
                        atomic_set_int(&td->td_lwp->lwp_mpflags, LWP_MP_VNLRU);
        }
-       vp = sysref_alloc(&vnode_sysref_class);
-       KKASSERT((vp->v_flag & (VCACHED|VFREE)) == 0);
+
+       vp = kmalloc(sizeof(*vp), M_VNODE, M_ZERO | M_WAITOK);
+
+       lwkt_token_init(&vp->v_token, "vnode");
+       lockinit(&vp->v_lock, "vnode", 0, 0);
+       TAILQ_INIT(&vp->v_namecache);
+       RB_INIT(&vp->v_rbclean_tree);
+       RB_INIT(&vp->v_rbdirty_tree);
+       RB_INIT(&vp->v_rbhash_tree);
+       spin_init(&vp->v_spin);
+
        lockmgr(&vp->v_lock, LK_EXCLUSIVE);
        atomic_add_int(&numvnodes, 1);
-
-       /*
-        * We are using a managed sysref class, vnode fields are only
-        * zerod on initial allocation from the backing store, not
-        * on reallocation.  Thus we have to clear these fields for both
-        * reallocation and reuse.
-        */
-#ifdef INVARIANTS
-       if (vp->v_data)
-               panic("cleaned vnode isn't");
-       if (bio_track_active(&vp->v_track_read) ||
-           bio_track_active(&vp->v_track_write)) {
-               panic("Clean vnode has pending I/O's");
-       }
-       if (vp->v_flag & VONWORKLST)
-               panic("Clean vnode still pending on syncer worklist!");
-       if (!RB_EMPTY(&vp->v_rbdirty_tree))
-               panic("Clean vnode still has dirty buffers!");
-       if (!RB_EMPTY(&vp->v_rbclean_tree))
-               panic("Clean vnode still has clean buffers!");
-       if (!RB_EMPTY(&vp->v_rbhash_tree))
-               panic("Clean vnode still on hash tree!");
-       KKASSERT(vp->v_mount == NULL);
-#endif
+       vp->v_refcnt = 1;
        vp->v_flag = VAGE0 | VAGE1;
-       vp->v_lastw = 0;
-       vp->v_lasta = 0;
-       vp->v_cstart = 0;
-       vp->v_clen = 0;
-       vp->v_socket = 0;
-       vp->v_opencount = 0;
-       vp->v_writecount = 0;   /* XXX */
 
        /*
         * lktimeout only applies when LK_TIMELOCK is used, and only
@@ -942,19 +963,11 @@ allocvnode(int lktimeout, int lkflags)
        KKASSERT(TAILQ_EMPTY(&vp->v_namecache));
        /* exclusive lock still held */
 
-       /*
-        * Note: sysref needs to be activated to convert -0x40000000 to +1.
-        * The -0x40000000 comes from the last ref on reuse, and from
-        * sysref_init() on allocate.
-        */
-       sysref_activate(&vp->v_sysref);
        vp->v_filesize = NOOFFSET;
        vp->v_type = VNON;
        vp->v_tag = 0;
-       vp->v_ops = NULL;
-       vp->v_data = NULL;
-       vp->v_pfsmp = NULL;
-       KKASSERT(vp->v_mount == NULL);
+       vp->v_state = VS_CACHED;
+       _vactivate(vp);
 
        return (vp);
 }
@@ -980,9 +993,8 @@ allocvnode(int lktimeout, int lkflags)
 void
 allocvnode_gc(void)
 {
-       if (numvnodes > desiredvnodes && freevnodes > wantfreevnodes) {
+       if (numvnodes > desiredvnodes && cachedvnodes > wantfreevnodes)
                freesomevnodes(batchfreevnodes);
-       }
 }
 
 /*
@@ -995,11 +1007,11 @@ freesomevnodes(int n)
        int count = 0;
 
        while (n) {
-               if ((vp = allocfreevnode(n * 2)) == NULL)
+               if ((vp = cleanfreevnode(n * 2)) == NULL)
                        break;
                --n;
                ++count;
-               vx_put(vp);
+               kfree(vp, M_VNODE);
                atomic_add_int(&numvnodes, -1);
        }
        return(count);
index c28128c..3c00910 100644 (file)
@@ -437,11 +437,7 @@ vmightfree(struct vnode *vp, int page_count, int pass)
 {
        if (vp->v_flag & VRECLAIMED)
                return (0);
-#if 0
-       if ((vp->v_flag & VFREE) && TAILQ_EMPTY(&vp->v_namecache))
-               return (0);
-#endif
-       if (sysref_isactive(&vp->v_sysref))
+       if (VREFCNT(vp) > 0)
                return (0);
        if (vp->v_object && vp->v_object->resident_page_count >= page_count)
                return (0);
@@ -509,17 +505,14 @@ visleaf(struct vnode *vp)
 /*
  * Try to clean up the vnode to the point where it can be vgone()'d, returning
  * 0 if it cannot be vgone()'d (or already has been), 1 if it can.  Unlike
- * vmightfree() this routine may flush the vnode and block.  Vnodes marked
- * VFREE are still candidates for vgone()ing because they may hold namecache
- * resources and could be blocking the namecache directory hierarchy (and
- * related vnodes) from being freed.
+ * vmightfree() this routine may flush the vnode and block.
  */
 static int
 vtrytomakegoneable(struct vnode *vp, int page_count)
 {
        if (vp->v_flag & VRECLAIMED)
                return (0);
-       if (vp->v_sysref.refcnt > 1)
+       if (VREFCNT(vp) > 1)
                return (0);
        if (vp->v_object && vp->v_object->resident_page_count >= page_count)
                return (0);
@@ -542,11 +535,11 @@ vtrytomakegoneable(struct vnode *vp, int page_count)
         * held here).  Finally, we have to check for other references one
         * last time in case something snuck in during the inval.
         */
-       if (vp->v_sysref.refcnt > 1 || vp->v_auxrefs != 0)
+       if (VREFCNT(vp) > 1 || vp->v_auxrefs != 0)
                return (0);
        if (cache_inval_vp_nonblock(vp))
                return (0);
-       return (vp->v_sysref.refcnt <= 1 && vp->v_auxrefs == 0);
+       return (VREFCNT(vp) <= 1 && vp->v_auxrefs == 0);
 }
 
 /*
@@ -712,11 +705,11 @@ vnlru_proc(void)
                 * (long) -> deal with 64 bit machines, intermediate overflow
                 */
                if (numvnodes > desiredvnodes &&
-                   freevnodes > desiredvnodes * 2 / 10) {
+                   cachedvnodes > desiredvnodes * 2 / 10) {
                        int count = numvnodes - desiredvnodes;
 
-                       if (count > freevnodes / 100)
-                               count = freevnodes / 100;
+                       if (count > cachedvnodes / 100)
+                               count = cachedvnodes / 100;
                        if (count < 5)
                                count = 5;
                        freesomevnodes(count);
@@ -733,7 +726,7 @@ vnlru_proc(void)
                 * Nothing to do if most of our vnodes are already on
                 * the free list.
                 */
-               if (numvnodes - freevnodes <= (long)desiredvnodes * 9 / 10) {
+               if (numvnodes - cachedvnodes <= (long)desiredvnodes * 9 / 10) {
                        tsleep(vnlruthread, 0, "vlruwt", hz);
                        continue;
                }
@@ -1196,7 +1189,7 @@ next:
  *
  * `rootrefs' specifies the base reference count for the root vnode
  * of this filesystem. The root vnode is considered busy if its
- * v_sysref.refcnt exceeds this value. On a successful return, vflush()
+ * v_refcnt exceeds this value. On a successful return, vflush()
  * will call vrele() on the root vnode exactly rootrefs times.
  * If the SKIPSYSTEM or WRITECLOSE flags are specified, rootrefs must
  * be zero.
@@ -1250,8 +1243,8 @@ vflush(struct mount *mp, int rootrefs, int flags)
                 * is equal to `rootrefs', then go ahead and kill it.
                 */
                KASSERT(vflush_info.busy > 0, ("vflush: not busy"));
-               KASSERT(rootvp->v_sysref.refcnt >= rootrefs, ("vflush: rootrefs"));
-               if (vflush_info.busy == 1 && rootvp->v_sysref.refcnt == rootrefs) {
+               KASSERT(VREFCNT(rootvp) >= rootrefs, ("vflush: rootrefs"));
+               if (vflush_info.busy == 1 && VREFCNT(rootvp) == rootrefs) {
                        vx_lock(rootvp);
                        vgone_vxlocked(rootvp);
                        vx_unlock(rootvp);
@@ -1275,6 +1268,11 @@ vflush_scan(struct mount *mp, struct vnode *vp, void *data)
        struct vattr vattr;
        int flags = info->flags;
 
+       /*
+        * Generally speaking try to deactivate on 0 refs (catch-all)
+        */
+       atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
+
        /*
         * Skip over a vnodes marked VSYSTEM.
         */
@@ -1305,7 +1303,7 @@ vflush_scan(struct mount *mp, struct vnode *vp, void *data)
         * If we are the only holder (refcnt of 1) or the vnode is in
         * termination (refcnt < 0), we can vgone the vnode.
         */
-       if (vp->v_sysref.refcnt <= 1) {
+       if (VREFCNT(vp) <= 1) {
                vgone_vxlocked(vp);
                return(0);
        }
index 9e58ef1..4d7fbeb 100644 (file)
@@ -151,7 +151,7 @@ vshouldmsync(struct vnode *vp)
 {
        vm_object_t object;
 
-       if (vp->v_auxrefs != 0 || vp->v_sysref.refcnt > 0)
+       if (vp->v_auxrefs != 0 || VREFCNT(vp) > 0)
                return (0);             /* other holders */
        object = vp->v_object;
        cpu_ccfence();
@@ -1143,12 +1143,15 @@ addaliasu(struct vnode *nvp, int x, int y)
  *
  * The filesystem can check whether its in-memory inode structure still
  * references the vp on return.
+ *
+ * May only be called if the vnode is in a known state (i.e. being prevented
+ * from being deallocated by some other condition such as a vfs inode hold).
  */
 void
 vclean_unlocked(struct vnode *vp)
 {
        vx_get(vp);
-       if (sysref_isactive(&vp->v_sysref) == 0)
+       if (VREFCNT(vp) <= 0)
                vgone_vxlocked(vp);
        vx_put(vp);
 }
@@ -1195,7 +1198,7 @@ vclean_vxlocked(struct vnode *vp, int flags)
         * before we clean it out so that its count cannot fall to zero and
         * generate a race against ourselves to recycle it.
         */
-       active = sysref_isactive(&vp->v_sysref);
+       active = (VREFCNT(vp) > 0);
 
        /*
         * Clean out any buffers associated with the vnode and destroy its
@@ -1332,7 +1335,7 @@ restart:
        if (vqn)
                vhold(vqn);
        while ((vq = vqn) != NULL) {
-               if (sysref_isactive(&vq->v_sysref)) {
+               if (VREFCNT(vq) > 0) {
                        vref(vq);
                        fdrevoke(vq, DTYPE_VNODE, cred);
                        /*v_release_rdev(vq);*/
@@ -1367,7 +1370,7 @@ restart:
 int
 vrecycle(struct vnode *vp)
 {
-       if (vp->v_sysref.refcnt <= 1 && (vp->v_flag & VRECLAIMED) == 0) {
+       if (VREFCNT(vp) <= 1 && (vp->v_flag & VRECLAIMED) == 0) {
                if (cache_inval_vp_nonblock(vp))
                        return(0);
                vgone_vxlocked(vp);
@@ -1401,7 +1404,8 @@ vmaxiosize(struct vnode *vp)
 }
 
 /*
- * Eliminate all activity associated with a vnode in preparation for reuse.
+ * Eliminate all activity associated with a vnode in preparation for
+ * destruction.
  *
  * The vnode must be VX locked and refd and will remain VX locked and refd
  * on return.  This routine may be called with the vnode in any state, as
@@ -1454,6 +1458,7 @@ vgone_vxlocked(struct vnode *vp)
         * Set us to VBAD
         */
        vp->v_type = VBAD;
+       atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
 }
 
 /*
@@ -1572,9 +1577,9 @@ vprint(char *label, struct vnode *vp)
                kprintf("%s: %p: ", label, (void *)vp);
        else
                kprintf("%p: ", (void *)vp);
-       kprintf("type %s, sysrefs %d, writecount %d, holdcnt %d,",
+       kprintf("type %s, refcnt %08x, writecount %d, holdcnt %d,",
                typename[vp->v_type],
-               vp->v_sysref.refcnt, vp->v_writecount, vp->v_auxrefs);
+               vp->v_refcnt, vp->v_writecount, vp->v_auxrefs);
        buf[0] = '\0';
        if (vp->v_flag & VROOT)
                strcat(buf, "|VROOT");
@@ -1584,8 +1589,6 @@ vprint(char *label, struct vnode *vp)
                strcat(buf, "|VTEXT");
        if (vp->v_flag & VSYSTEM)
                strcat(buf, "|VSYSTEM");
-       if (vp->v_flag & VFREE)
-               strcat(buf, "|VFREE");
        if (vp->v_flag & VOBJBUF)
                strcat(buf, "|VOBJBUF");
        if (buf[0] != '\0')
index b4077bb..82fc960 100644 (file)
@@ -467,7 +467,7 @@ checkdirs(struct nchandle *old_nch, struct nchandle *new_nch)
         * being held as a descriptor anywhere.
         */
        olddp = old_nch->ncp->nc_vp;
-       if (olddp == NULL || olddp->v_sysref.refcnt == 1)
+       if (olddp == NULL || VREFCNT(olddp) == 1)
                return;
 
        /*
@@ -743,6 +743,7 @@ dounmount(struct mount *mp, int flags)
         */
        if ((vp = mp->mnt_syncer) != NULL) {
                mp->mnt_syncer = NULL;
+               atomic_set_int(&vp->v_refcnt, VREF_FINALIZE);
                vrele(vp);
        }
        if ((mp->mnt_flag & MNT_RDONLY) == 0)
index 37be9f2..85b7961 100644 (file)
@@ -155,18 +155,20 @@ struct vnode {
        int     v_writecount;
        int     v_opencount;                    /* number of explicit opens */
        int     v_auxrefs;                      /* auxiliary references */
-       struct sysref v_sysref;                 /* normal references */
+       int     v_refcnt;
        struct bio_track v_track_read;          /* track I/O's in progress */
        struct bio_track v_track_write;         /* track I/O's in progress */
        struct mount *v_mount;                  /* ptr to vfs we are in */
        struct vop_ops **v_ops;                 /* vnode operations vector */
-       TAILQ_ENTRY(vnode) v_freelist;          /* vnode freelist/cachelist */
+       TAILQ_ENTRY(vnode) v_list;              /* vnode act/inact/cache/free */
        TAILQ_ENTRY(vnode) v_nmntvnodes;        /* vnodes for mount point */
+       LIST_ENTRY(vnode) v_synclist;           /* vnodes with dirty buffers */
        struct buf_rb_tree v_rbclean_tree;      /* RB tree of clean bufs */
        struct buf_rb_tree v_rbdirty_tree;      /* RB tree of dirty bufs */
        struct buf_rb_hash v_rbhash_tree;       /* RB tree general lookup */
-       LIST_ENTRY(vnode) v_synclist;           /* vnodes with dirty buffers */
        enum    vtype v_type;                   /* vnode type */
+       int16_t         v_act;                  /* use heuristic */
+       int16_t         v_state;                /* active/free/cached */
        union {
                struct socket   *vu_socket;     /* unix ipc (VSOCK) */
                struct {
@@ -221,14 +223,14 @@ struct vnode {
 /* open for business    0x00000200 */
 #define VAGE0          0x00000400      /* Age count for recycling - 2 bits */
 #define VAGE1          0x00000800      /* Age count for recycling - 2 bits */
-#define VCACHED                0x00001000      /* No active references but has cache value */
+/* open for business   0x00001000 */
 #define        VOBJBUF         0x00002000      /* Allocate buffers in VM object */
-#define        VINACTIVE       0x00004000      /* The vnode is inactive (did VOP_INACTIVE) */
+#define        VINACTIVE       0x00004000      /* ran VOP_INACTIVE */
 /* open for business    0x00008000 */
-#define        VOLOCK          0x00010000      /* vnode is locked waiting for an object */
+#define        VOLOCK          0x00010000      /* vnode locked waiting for object */
 #define        VOWANT          0x00020000      /* a process is waiting for VOLOCK */
 #define        VRECLAIMED      0x00040000      /* This vnode has been destroyed */
-#define        VFREE           0x00080000      /* This vnode is on the freelist */
+/* open for business   0x00080000 */
 #define VNOTSEEKABLE   0x00100000      /* rd/wr ignores file offset */
 #define        VONWORKLST      0x00200000      /* On syncer work-list */
 #define VISDIRTY       0x00400000      /* inode dirty from VFS */
@@ -237,6 +239,30 @@ struct vnode {
 /* open for business   0x02000000 */
 /* open for business   0x04000000 */
 
+/*
+ * v_state flags (v_state is interlocked by v_spin and vfs_spin)
+ */
+#define VS_CACHED      0
+#define VS_ACTIVE      1
+#define VS_INACTIVE    2
+#define VS_DYING       3
+
+/*
+ * v_refcnt uses bit 30 to flag that 1->0 transitions require finalization
+ * (actual deactivation) and bit 31 to indicate that deactivation is in
+ * progress.
+ *
+ * The VREFCNT() macro returns a negative number if the vnode is undergoing
+ * termination (value should not be interpreted beyond being negative),
+ * zero if it is cached and has no references, or a positive number
+ * indicating the number of refs.
+ */
+#define VREF_TERMINATE 0x80000000      /* termination in progress */
+#define VREF_FINALIZE  0x40000000      /* deactivate on last vrele */
+#define VREF_MASK      0xBFFFFFFF      /* includes VREF_TERMINATE */
+
+#define VREFCNT(vp)    ((int)((vp)->v_refcnt & VREF_MASK))
+
 /*
  * vmntvnodescan() flags
  */
@@ -335,7 +361,9 @@ extern      struct objcache *namei_oc;
 extern int prtactive;                  /* nonzero to call vprint() */
 extern struct vattr va_null;           /* predefined null vattr structure */
 extern int numvnodes;
-extern int freevnodes;
+extern int inactivevnodes;
+extern int activevnodes;
+extern int cachedvnodes;
 
 /*
  * This macro is very helpful in defining those offsets in the vdesc struct.
@@ -529,7 +557,6 @@ void        vx_put (struct vnode *vp);
 int    vget (struct vnode *vp, int lockflag);
 void   vput (struct vnode *vp);
 void   vhold (struct vnode *);
-void   vhold_interlocked (struct vnode *);
 void   vdrop (struct vnode *);
 void   vref (struct vnode *vp);
 void   vrele (struct vnode *vp);
index 87d456d..29373bc 100644 (file)
@@ -511,7 +511,7 @@ fifo_close(struct vop_close_args *ap)
                if (fip->fi_writers == 0)
                        soisdisconnected(fip->fi_readsock);
        }
-       if (vp->v_sysref.refcnt > 1) {
+       if (VREFCNT(vp) > 1) {
                vop_stdclose(ap);
                lwkt_reltoken(&vp->v_token);
                return (0);
index aa45ae4..c074e00 100644 (file)
@@ -360,7 +360,7 @@ hammer_get_vnode(struct hammer_inode *ip, struct vnode **vpp)
                        hammer_unlock(&ip->lock);
                        continue;
                }
-               vhold_interlocked(vp);
+               vhold(vp);
                hammer_unlock(&ip->lock);
 
                /*
index 3bba430..b48742f 100644 (file)
@@ -328,7 +328,7 @@ hammer2_igetv(hammer2_inode_t *ip, int *errorp)
                         * vget().  The vget() can still fail if we lost
                         * a reclaim race on the vnode.
                         */
-                       vhold_interlocked(vp);
+                       vhold(vp);
                        ostate = hammer2_inode_lock_temp_release(ip);
                        if (vget(vp, LK_EXCLUSIVE)) {
                                vdrop(vp);
@@ -413,8 +413,8 @@ hammer2_igetv(hammer2_inode_t *ip, int *errorp)
         * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
         */
        if (hammer2_debug & 0x0002) {
-               kprintf("igetv vp %p refs %d aux %d\n",
-                       vp, vp->v_sysref.refcnt, vp->v_auxrefs);
+               kprintf("igetv vp %p refs 0x%08x aux 0x%08x\n",
+                       vp, vp->v_refcnt, vp->v_auxrefs);
        }
        return (vp);
 }
index 44d5d46..0b6d825 100644 (file)
@@ -609,7 +609,7 @@ hpfs_inactive(struct vop_inactive_args *ap)
                        return (error);
        }
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("hpfs_inactive: pushing active", vp);
 
        if (hp->h_flag & H_INVAL) {
index 2fd3156..e10bcd0 100644 (file)
@@ -195,7 +195,7 @@ cd9660_inactive(struct vop_inactive_args *ap)
        struct iso_node *ip = VTOI(vp);
        int error = 0;
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("cd9660_inactive: pushing active", vp);
 
        if (ip)
@@ -220,7 +220,7 @@ cd9660_reclaim(struct vop_reclaim_args *ap)
        struct vnode *vp = ap->a_vp;
        struct iso_node *ip = VTOI(vp);
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("cd9660_reclaim: pushing active", vp);
        /*
         * Remove the inode from its hash chain.
index 213a4fe..e14f606 100644 (file)
@@ -685,7 +685,7 @@ msdosfs_reclaim(struct vop_reclaim_args *ap)
            dep, dep ? (char *)dep->de_Name : "?", dep ? dep->de_refcnt : -1);
 #endif
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("msdosfs_reclaim(): pushing active", vp);
        /*
         * Remove the denode from its hash chain.
@@ -717,7 +717,7 @@ msdosfs_inactive(struct vop_inactive_args *ap)
                dep, (dep ? dep->de_Name[0] : 0));
 #endif
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("msdosfs_inactive(): pushing active", vp);
 
        /*
@@ -748,8 +748,8 @@ out:
         * so that it can be reused immediately.
         */
 #ifdef MSDOSFS_DEBUG
-       kprintf("msdosfs_inactive(): v_sysrefs %d, de_Name[0] %x\n",
-               vp->v_sysref.refcnt, (dep ? dep->de_Name[0] : 0));
+       kprintf("msdosfs_inactive(): v_refcnt 0x%08x, de_Name[0] %x\n",
+               vp->v_refcnt, (dep ? dep->de_Name[0] : 0));
 #endif
        if (dep == NULL || dep->de_Name[0] == SLOT_DELETED)
                vrecycle(vp);
index 4acaf67..4e56563 100644 (file)
@@ -654,9 +654,10 @@ msdosfs_unmount(struct mount *mp, int mntflags)
                struct vnode *vp = pmp->pm_devvp;
 
                kprintf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
-               kprintf("flag %08x, sysrefs %d, writecount %d, auxrefs %d\n",
-                   vp->v_flag, vp->v_sysref.refcnt,
-                   vp->v_writecount, vp->v_auxrefs);
+               kprintf("flag %08x, refcnt 0x%08x, writecount %d, "
+                       "auxrefs 0x%08x\n",
+                       vp->v_flag, vp->v_refcnt,
+                       vp->v_writecount, vp->v_auxrefs);
                kprintf("mount %p, op %p\n", vp->v_mount, vp->v_ops);
                kprintf("mount %p\n", vp->v_mount);
                kprintf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
index 222a29e..183dcc2 100644 (file)
@@ -230,7 +230,7 @@ msdosfs_close(struct vop_close_args *ap)
        struct denode *dep = VTODE(vp);
        struct timespec ts;
 
-       if (vp->v_sysref.refcnt > 1) {
+       if (VREFCNT(vp) > 1) {
                getnanotime(&ts);
                DETIMES(dep, &ts, &ts, &ts);
        }
@@ -842,8 +842,8 @@ msdosfs_remove(struct vop_old_remove_args *ap)
        else
                error = removede(ddep, dep);
 #ifdef MSDOSFS_DEBUG
-       kprintf("msdosfs_remove(), dep %p, v_sysrefs %d\n",
-               dep, ap->a_vp->v_sysref.refcnt);
+       kprintf("msdosfs_remove(), dep %p, v_refcnt 0x%08x\n",
+               dep, ap->a_vp->v_refcnt);
 #endif
        return (error);
 }
index 5cbda86..e22a39c 100644 (file)
@@ -379,7 +379,7 @@ nfs_inactive(struct vop_inactive_args *ap)
        lwkt_gettoken(&nmp->nm_token);
 
        np = VTONFS(ap->a_vp);
-       if (prtactive && ap->a_vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(ap->a_vp) > 1)
                vprint("nfs_inactive: pushing active", ap->a_vp);
        if (ap->a_vp->v_type != VDIR) {
                sp = np->n_sillyrename;
@@ -428,7 +428,7 @@ nfs_reclaim(struct vop_reclaim_args *ap)
        struct nfsdmap *dp, *dp2;
 /*     struct nfsmount *nmp = VFSTONFS(vp->v_mount);*/
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("nfs_reclaim: pushing active", vp);
 
 
index f8b1a05..2ef7999 100644 (file)
@@ -1776,7 +1776,7 @@ nfsmout:
  * To try and make nfs semantics closer to ufs semantics, a file that has
  * other processes using the vnode is renamed instead of removed and then
  * removed later on the last close.
- * - If v_sysref.refcnt > 1
+ * - If v_refcnt > 1
  *       If a rename is not already in the works
  *          call nfs_sillyrename() to set it up
  *     else
@@ -1798,12 +1798,12 @@ nfs_remove(struct vop_old_remove_args *ap)
 
        lwkt_gettoken(&nmp->nm_token);
 #ifndef DIAGNOSTIC
-       if (vp->v_sysref.refcnt < 1)
-               panic("nfs_remove: bad v_sysref.refcnt");
+       if (VREFCNT(vp) < 1)
+               panic("nfs_remove: bad v_refcnt");
 #endif
        if (vp->v_type == VDIR) {
                error = EPERM;
-       } else if (vp->v_sysref.refcnt == 1 || (np->n_sillyrename &&
+       } else if (VREFCNT(vp) == 1 || (np->n_sillyrename &&
                   VOP_GETATTR(vp, &vattr) == 0 && vattr.va_nlink > 1)) {
                /*
                 * throw away biocache buffers, mainly to avoid
@@ -1926,7 +1926,7 @@ nfs_rename(struct vop_old_rename_args *ap)
         * routine.  The new API compat functions have access to the actual
         * namecache structures and will do it for us.
         */
-       if (tvp && tvp->v_sysref.refcnt > 1 && !VTONFS(tvp)->n_sillyrename &&
+       if (tvp && VREFCNT(tvp) > 1 && !VTONFS(tvp)->n_sillyrename &&
                tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
                vput(tvp);
                tvp = NULL;
@@ -3616,7 +3616,7 @@ nfsfifo_close(struct vop_close_args *ap)
                if (np->n_flag & NUPD)
                        np->n_mtim = ts;
                np->n_flag |= NCHG;
-               if (vp->v_sysref.refcnt == 1 &&
+               if (VREFCNT(vp) == 1 &&
                    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
                        VATTR_NULL(&vattr);
                        if (np->n_flag & NACC)
index c67625f..a1c64ee 100644 (file)
@@ -641,7 +641,7 @@ ntfs_unmount(struct mount *mp, int mntflags)
        /* Check if only system vnodes are left */
        for(i=0;i<NTFS_SYSNODESNUM;i++)
                 if((ntmp->ntm_sysvn[i]) && 
-                   (ntmp->ntm_sysvn[i]->v_sysref.refcnt > 1)) return (EBUSY);
+                   (VREFCNT(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY);
 
        /* Dereference all system vnodes */
        for(i=0;i<NTFS_SYSNODESNUM;i++)
index ad94f90..0fcf31c 100644 (file)
@@ -248,7 +248,7 @@ ntfs_inactive(struct vop_inactive_args *ap)
 
        dprintf(("ntfs_inactive: vnode: %p, ntnode: %ju\n", vp, (uintmax_t)ip->i_number));
 
-       if (ntfs_prtactive && vp->v_sysref.refcnt > 1)
+       if (ntfs_prtactive && VREFCNT(vp) > 1)
                vprint("ntfs_inactive: pushing active", vp);
 
        /*
@@ -273,7 +273,7 @@ ntfs_reclaim(struct vop_reclaim_args *ap)
 
        dprintf(("ntfs_reclaim: vnode: %p, ntnode: %ju\n", vp, (uintmax_t)ip->i_number));
 
-       if (ntfs_prtactive && vp->v_sysref.refcnt > 1)
+       if (ntfs_prtactive && VREFCNT(vp) > 1)
                vprint("ntfs_reclaim: pushing active", vp);
 
        if ((error = ntfs_ntget(ip)) != 0)
index 3ae7ef4..e56bdd9 100644 (file)
@@ -100,8 +100,8 @@ nwfs_sysctl_vnprint(SYSCTL_HANDLER_ARGS)
                LIST_FOREACH(np, nhpp, n_hash) {
                        vp = NWTOV(np);
                        vprint(NULL, vp);
-                       kprintf("%s:%d:%d:%d:%d\n",
-                               np->n_name, vp->v_sysref.refcnt, vp->v_auxrefs,
+                       kprintf("%s:%08x:%08x:%d:%d\n",
+                               np->n_name, vp->v_refcnt, vp->v_auxrefs,
                                np->n_fid.f_id, np->n_fid.f_parent);
                }
        }
@@ -221,7 +221,7 @@ nwfs_reclaim(struct vop_reclaim_args *ap)
        struct nwmount *nmp = VTONWFS(vp);
        struct thread *td = curthread;  /* XXX */
        
-       NCPVNDEBUG("%s,%d\n", (np ? np->n_name : "?"), vp->v_sysref.refcnt);
+       NCPVNDEBUG("%s,%08x\n", (np ? np->n_name : "?"), vp->v_refcnt);
        if (np && np->n_refparent) {
                np->n_refparent = 0;
                if (nwfs_lookupnp(nmp, np->n_parent, td, &dnp) == 0) {
@@ -260,7 +260,7 @@ nwfs_inactive(struct vop_inactive_args *ap)
        KKASSERT(td->td_proc);          /* XXX */
        cred = td->td_proc->p_ucred;    /* XXX */
 
-       NCPVNDEBUG("%s: %d\n", VTONW(vp)->n_name, vp->v_sysref.refcnt);
+       NCPVNDEBUG("%s: %08x\n", VTONW(vp)->n_name, vp->v_refcnt);
        if (np && np->opened) {
                error = nwfs_vinvalbuf(vp, V_SAVE, 1);
                error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, td, cred);
index 16382c8..fd0cee0 100644 (file)
@@ -213,7 +213,7 @@ nwfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
         * Lose the lock but keep the ref.
         */
        vn_unlock(vp);
-       NCPVODEBUG("rootvp.vrefcnt=%d\n",vp->v_sysref.refcnt);
+       NCPVODEBUG("rootvp.vrefcnt=0x%08x\n", vp->v_refcnt);
        return error;
 bad:
         if (nmp)
index a9a18eb..7dee2f1 100644 (file)
@@ -436,7 +436,7 @@ nwfs_remove(struct vop_old_remove_args *ap)
        struct nwmount *nmp = VTONWFS(vp);
        int error;
 
-       if (vp->v_type == VDIR || np->opened || vp->v_sysref.refcnt > 1) {
+       if (vp->v_type == VDIR || np->opened || VREFCNT(vp) > 1) {
                error = EPERM;
        } else if (!ncp_conn_valid(NWFSTOCONN(nmp))) {
                error = EIO;
@@ -478,7 +478,7 @@ nwfs_rename(struct vop_old_rename_args *ap)
                goto out;
        }
 
-       if (tvp && tvp->v_sysref.refcnt > 1) {
+       if (tvp && VREFCNT(tvp) > 1) {
                error = EBUSY;
                goto out;
        }
index 7362c20..c4b3c43 100644 (file)
@@ -90,7 +90,7 @@ loop:
                if (pfs->pfs_pid == pid && pfs->pfs_type == pfs_type &&
                    PFSTOV(pfs)->v_mount == mp) {
                        vp = PFSTOV(pfs);
-                       vhold_interlocked(vp);
+                       vhold(vp);
                        if (vget(vp, LK_EXCLUSIVE)) {
                                vdrop(vp);
                                goto loop;
index ce3964c..27cbc89 100644 (file)
@@ -298,7 +298,7 @@ smbfs_reclaim(struct vop_reclaim_args *ap)
        struct smbnode *np = VTOSMB(vp);
        struct smbmount *smp = VTOSMBFS(vp);
        
-       SMBVDEBUG("%s,%d\n", np->n_name, vp->v_sysref.refcnt);
+       SMBVDEBUG("%s,%08x\n", np->n_name, vp->v_refcnt);
 
        smbfs_hash_lock(smp, td);
 
@@ -339,7 +339,7 @@ smbfs_inactive(struct vop_inactive_args *ap)
        struct smb_cred scred;
        int error;
 
-       SMBVDEBUG("%s: %d\n", VTOSMB(vp)->n_name, vp->v_sysref.refcnt);
+       SMBVDEBUG("%s: %08x\n", VTOSMB(vp)->n_name, vp->v_refcnt);
        if (np->n_opencount) {
                error = smbfs_vinvalbuf(vp, V_SAVE, 1);
                cred = np->n_cached_cred;
index 4a686d4..9ac6ab6 100644 (file)
@@ -208,7 +208,7 @@ smbfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
        if (error)
                goto bad;
        vn_unlock(vp);
-       SMBVDEBUG("root.v_sysrefs = %d\n", vp->v_sysref.refcnt);
+       SMBVDEBUG("root.v_refcnt = %08x\n", vp->v_refcnt);
 
 #ifdef DIAGNOSTICS
        SMBERROR("mp=%p\n", mp);
index dbda5de..bac760f 100644 (file)
@@ -502,7 +502,7 @@ smbfs_remove(struct vop_old_remove_args *ap)
        struct smb_cred scred;
        int error;
 
-       if (vp->v_type == VDIR || np->n_opencount || vp->v_sysref.refcnt > 1)
+       if (vp->v_type == VDIR || np->n_opencount || VREFCNT(vp) > 1)
                return EPERM;
        smb_makescred(&scred, cnp->cn_td, cnp->cn_cred);
        error = smbfs_smb_delete(np, &scred);
@@ -536,7 +536,7 @@ smbfs_rename(struct vop_old_rename_args *ap)
                goto out;
        }
 
-       if (tvp && tvp->v_sysref.refcnt > 1) {
+       if (tvp && VREFCNT(tvp) > 1) {
                error = EBUSY;
                goto out;
        }
index 8310b88..4310fb3 100644 (file)
@@ -372,7 +372,7 @@ loop:
        TMPFS_NODE_LOCK(node);
        if ((vp = node->tn_vnode) != NULL) {
                KKASSERT((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0);
-               vhold_interlocked(vp);
+               vhold(vp);
                TMPFS_NODE_UNLOCK(node);
 
                if (vget(vp, lkflag | LK_EXCLUSIVE) != 0) {
index 536a15c..d1b4bbe 100644 (file)
@@ -332,7 +332,7 @@ tmpfs_unmount(struct mount *mp, int mntflags)
                ++node->tn_links;
                while (node->tn_type == VREG && node->tn_vnode) {
                        vp = node->tn_vnode;
-                       vhold_interlocked(vp);
+                       vhold(vp);
                        lwkt_yield();
 
                        /*
index 48a4f67..d53aec3 100644 (file)
@@ -69,7 +69,7 @@ ufs_inactive(struct vop_inactive_args *ap)
        struct inode *ip = VTOI(vp);
        int mode, error = 0;
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("ufs_inactive: pushing active", vp);
 
        /*
@@ -119,7 +119,7 @@ ufs_reclaim(struct vop_reclaim_args *ap)
 
        ump = VFSTOUFS(vp->v_mount);
 
-       if (prtactive && vp->v_sysref.refcnt > 1)
+       if (prtactive && VREFCNT(vp) > 1)
                vprint("ufs_reclaim: pushing active", vp);
        ip = VTOI(vp);
 
index 52fa064..51b67a0 100644 (file)
@@ -271,7 +271,7 @@ ufs_close(struct vop_close_args *ap)
 {
        struct vnode *vp = ap->a_vp;
 
-       if (vp->v_sysref.refcnt > 1)
+       if (VREFCNT(vp) > 1)
                ufs_itimes(vp);
        return (vop_stdclose(ap));
 }
@@ -1880,7 +1880,7 @@ ufsfifo_close(struct vop_close_args *ap)
 {
        struct vnode *vp = ap->a_vp;
 
-       if (vp->v_sysref.refcnt > 1)
+       if (VREFCNT(vp) > 1)
                ufs_itimes(vp);
        return (VOCALL(&fifo_vnode_vops, &ap->a_head));
 }
index b2fb50f..733370a 100644 (file)
@@ -459,16 +459,22 @@ loop:
                 */
                UDEBUG(("Modify existing un %p vn %p upper %p(refs %d) -> %p(refs %d)\n",
                        un, un->un_vnode, un->un_uppervp, 
-                       (un->un_uppervp ? un->un_uppervp->v_sysref.refcnt : -99),
+                       (un->un_uppervp ? VREFCNT(un->un_uppervp) : -99),
                        uppervp,
-                       (uppervp ? uppervp->v_sysref.refcnt : -99)
+                       (uppervp ? VREFCNT(uppervp) : -99)
                ));
 
                if (uppervp != un->un_uppervp) {
-                       KASSERT(uppervp == NULL || uppervp->v_sysref.refcnt > 0, ("union_allocvp: too few refs %d (at least 1 required) on uppervp", uppervp->v_sysref.refcnt));
+                       KASSERT(uppervp == NULL || VREFCNT(uppervp) > 0,
+                               ("union_allocvp: too few refs %d (at least 1 "
+                                "required) on uppervp",
+                               VREFCNT(uppervp)));
                        union_newupper(un, uppervp);
                } else if (uppervp) {
-                       KASSERT(uppervp->v_sysref.refcnt > 1, ("union_allocvp: too few refs %d (at least 2 required) on uppervp", uppervp->v_sysref.refcnt));
+                       KASSERT(VREFCNT(uppervp) > 1,
+                               ("union_allocvp: too few refs %d (at least "
+                                "2 required) on uppervp",
+                                VREFCNT(uppervp)));
                        vrele(uppervp);
                }
 
@@ -730,7 +736,8 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred,
 
        lvp = un->un_lowervp;
 
-       KASSERT(uvp->v_sysref.refcnt > 0, ("copy: uvp refcount 0: %d", uvp->v_sysref.refcnt));
+       KASSERT(VREFCNT(uvp) > 0,
+               ("copy: uvp refcount 0: %d", VREFCNT(uvp)));
        if (docopy) {
                /*
                 * XX - should not ignore errors
@@ -749,9 +756,9 @@ union_copyup(struct union_node *un, int docopy, struct ucred *cred,
        }
        vn_unlock(uvp);
        union_newupper(un, uvp);
-       KASSERT(uvp->v_sysref.refcnt > 0, ("copy: uvp refcount 0: %d", uvp->v_sysref.refcnt));
+       KASSERT(VREFCNT(uvp) > 0, ("copy: uvp refcount 0: %d", VREFCNT(uvp)));
        union_vn_close(uvp, FWRITE, cred);
-       KASSERT(uvp->v_sysref.refcnt > 0, ("copy: uvp refcount 0: %d", uvp->v_sysref.refcnt));
+       KASSERT(VREFCNT(uvp) > 0, ("copy: uvp refcount 0: %d", VREFCNT(uvp)));
        /*
         * Subsequent IOs will go to the top layer, so
         * call close on the lower vnode and open on the
@@ -1153,10 +1160,12 @@ union_dircache(struct vnode *vp, struct thread *td)
                goto out;
 
        /*vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);*/
-       UDEBUG(("ALLOCVP-3 %p ref %d\n", *vpp, (*vpp ? (*vpp)->v_sysref.refcnt : -99)));
+       UDEBUG(("ALLOCVP-3 %p ref %08x\n",
+               *vpp, (*vpp ? (*vpp)->v_refcnt : -99)));
        vref(*vpp);
        error = union_allocvp(&nvp, vp->v_mount, NULLVP, NULLVP, NULL, *vpp, NULLVP, 0);
-       UDEBUG(("ALLOCVP-3B %p ref %d\n", nvp, (*vpp ? (*vpp)->v_sysref.refcnt : -99)));
+       UDEBUG(("ALLOCVP-3B %p ref %08x\n",
+               nvp, (*vpp ? (*vpp)->v_refcnt : -99)));
        if (error)
                goto out;
 
index f8c019a..4009504 100644 (file)
@@ -110,7 +110,8 @@ union_lock_upper(struct union_node *un, struct thread *td)
                vref(uppervp);
                vn_lock(uppervp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
        }
-       KASSERT((uppervp == NULL || uppervp->v_sysref.refcnt > 0), ("uppervp usecount is 0"));
+       KASSERT((uppervp == NULL || VREFCNT(uppervp) > 0),
+               ("uppervp usecount is 0"));
        return(uppervp);
 }
 
@@ -366,10 +367,10 @@ union_lookup(struct vop_old_lookup_args *ap)
                    "uerror %d upperdvp %p %d/%d, uppervp %p ref=%d/lck=%d\n",
                    uerror,
                    upperdvp,
-                   upperdvp->v_sysref.refcnt,
+                   VREFCNT(upperdvp),
                    vn_islocked(upperdvp),
                    uppervp,
-                   (uppervp ? uppervp->v_sysref.refcnt : -99),
+                   (uppervp ? VREFCNT(uppervp) : -99),
                    (uppervp ? vn_islocked(uppervp) : -99)
                ));
 
@@ -546,7 +547,9 @@ union_lookup(struct vop_old_lookup_args *ap)
        error = union_allocvp(ap->a_vpp, dvp->v_mount, dvp, upperdvp, cnp,
                              uppervp, lowervp, 1);
 
-       UDEBUG(("Create %p = %p %p refs=%d\n", *ap->a_vpp, uppervp, lowervp, (*ap->a_vpp) ? ((*ap->a_vpp)->v_sysref.refcnt) : -99));
+       UDEBUG(("Create %p = %p %p refs=%d\n",
+               *ap->a_vpp, uppervp, lowervp,
+               (*ap->a_vpp) ? (VREFCNT(*ap->a_vpp)) : -99));
 
        uppervp = NULL;
        upperdvp = NULL;
@@ -586,7 +589,7 @@ out:
                cnp->cn_flags &= ~CNP_LOCKPARENT;
 
        UDEBUG(("Out %d vpp %p/%d lower %p upper %p\n", error, *ap->a_vpp,
-               ((*ap->a_vpp) ? (*ap->a_vpp)->v_sysref.refcnt : -99),
+               ((*ap->a_vpp) ? (*ap->a_vpp)->v_refcnt : -99),
                lowervp, uppervp));
 
        /*
@@ -648,10 +651,12 @@ union_create(struct vop_old_create_args *ap)
                if (error == 0) {
                        mp = ap->a_dvp->v_mount;
                        vn_unlock(vp);
-                       UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n", vp, vp->v_sysref.refcnt));
+                       UDEBUG(("ALLOCVP-1 FROM %p REFS %d\n",
+                               vp, vp->v_refcnt));
                        error = union_allocvp(ap->a_vpp, mp, NULLVP, NULLVP,
                                cnp, vp, NULLVP, 1);
-                       UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vp->v_sysref.refcnt));
+                       UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n",
+                               *ap->a_vpp, vp->v_refcnt));
                }
                union_unlock_upper(dvp, td);
        }
@@ -1470,10 +1475,12 @@ union_mkdir(struct vop_old_mkdir_args *ap)
 
                if (error == 0) {
                        vn_unlock(vp);
-                       UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n", vp, vp->v_sysref.refcnt));
+                       UDEBUG(("ALLOCVP-2 FROM %p REFS %d\n",
+                               vp, vp->v_refcnt));
                        error = union_allocvp(ap->a_vpp, ap->a_dvp->v_mount,
                                ap->a_dvp, NULLVP, cnp, vp, NULLVP, 1);
-                       UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n", *ap->a_vpp, vp->v_sysref.refcnt));
+                       UDEBUG(("ALLOCVP-2B FROM %p REFS %d\n",
+                               *ap->a_vpp, vp->v_refcnt));
                }
        }
        return (error);
index 121a8a1..420e2dd 100644 (file)
@@ -149,7 +149,7 @@ vnode_pager_alloc(void *handle, off_t length, vm_prot_t prot, off_t offset,
                vm_object_drop(object);
        }
 
-       if (vp->v_sysref.refcnt <= 0)
+       if (VREFCNT(vp) <= 0)
                panic("vnode_pager_alloc: no vnode reference");
 
        /*
index 5085e78..fa73f5e 100644 (file)
@@ -73,7 +73,8 @@
 
 struct nlist Nl[] = {
     { "_mountlist" },
-    { "_vnode_free_list" },
+    { "_vnode_inactive_list" },
+    { "_vnode_active_list" },
     { NULL }
 };
 
@@ -140,8 +141,13 @@ main(int ac, char **av)
     kkread(kd, Nl[0].n_value, &mp, sizeof(mp));
     while (mp)
        mp = dumpmount(kd, mp);
+    printf("INACTIVELIST {\n");
     kkread(kd, Nl[1].n_value, &vp, sizeof(vp));
-    printf("VNODEFREELIST {\n");
+    while (vp)
+       vp = dumpvp(kd, vp, 0);
+    printf("}\n");
+    printf("ACTIVELIST {\n");
+    kkread(kd, Nl[2].n_value, &vp, sizeof(vp));
     while (vp)
        vp = dumpvp(kd, vp, 0);
     printf("}\n");
@@ -213,8 +219,8 @@ dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
 
     kkread(kd, (u_long)vp, &vn, sizeof(vn));
 
-    printf("    vnode %p usecnt %08x holdcnt %d type=%s flags %08x",
-       vp, vn.v_sysref.refcnt, vn.v_auxrefs, vtype(vn.v_type), vn.v_flag);
+    printf("    vnode %p.%d refcnt %08x auxcnt %d type=%s flags %08x",
+       vp, vn.v_state, vn.v_refcnt, vn.v_auxrefs, vtype(vn.v_type), vn.v_flag);
 
     if ((vn.v_flag & VOBJBUF) && vn.v_object) {
        int npages = getobjpages(kd, vn.v_object);
@@ -271,10 +277,6 @@ dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
     if (vn.v_flag & VDOOMED)
        printf(" VDOOMED");
 #endif
-    if (vn.v_flag & VFREE)
-       printf(" VFREE");
-    if (vn.v_flag & VCACHED)
-       printf(" VCACHED");
 #ifdef VINFREE
     if (vn.v_flag & VINFREE)
        printf(" VINFREE");
@@ -338,7 +340,7 @@ dumpvp(kvm_t *kd, struct vnode *vp, int whichlist)
     if (whichlist)
        return(vn.v_nmntvnodes.tqe_next);
     else
-       return(vn.v_freelist.tqe_next);
+       return(vn.v_list.tqe_next);
 }
 
 static void
index 136682f..d5b3452 100644 (file)
@@ -72,8 +72,9 @@ static struct Info {
        long    *intrcnt;
        long    bufspace;
        int     desiredvnodes;
-       int     numvnodes;
-       int     freevnodes;
+       int     cachedvnodes;
+       int     inactivevnodes;
+       int     activevnodes;
        long    dirtybufspace;
 } s, s1, s2, z;
 
@@ -137,11 +138,13 @@ static struct nlist namelist[] = {
        { .n_name = "_nchstats" },
 #define        X_DESIREDVNODES 2
        { .n_name = "_desiredvnodes" },
-#define        X_NUMVNODES     3
-       { .n_name = "_numvnodes" },
-#define        X_FREEVNODES    4
-       { .n_name = "_freevnodes" },
-#define X_NUMDIRTYBUFFERS 5
+#define        X_CACHEDVNODES  3
+       { .n_name = "_cachedvnodes" },
+#define        X_INACTIVEVNODES 4
+       { .n_name = "_inactivevnodes" },
+#define        X_ACTIVEVNODES  5
+       { .n_name = "_activevnodes" },
+#define X_NUMDIRTYBUFFERS 6
        { .n_name = "_dirtybufspace" },
        { .n_name = "" },
 };
@@ -294,9 +297,9 @@ labelkre(void)
        mvprintw(VMSTATROW + 13, VMSTATCOL + 8, "buf");
        mvprintw(VMSTATROW + 14, VMSTATCOL + 8, "dirtybuf");
 
-       mvprintw(VMSTATROW + 15, VMSTATCOL + 8, "desiredvnodes");
-       mvprintw(VMSTATROW + 16, VMSTATCOL + 8, "numvnodes");
-       mvprintw(VMSTATROW + 17, VMSTATCOL + 8, "freevnodes");
+       mvprintw(VMSTATROW + 15, VMSTATCOL + 8, "activ-vp");
+       mvprintw(VMSTATROW + 16, VMSTATCOL + 8, "cachd-vp");
+       mvprintw(VMSTATROW + 17, VMSTATCOL + 8, "inact-vp");
 
        mvprintw(GENSTATROW, GENSTATCOL, "  Csw  Trp  Sys  Int  Sof  Flt");
 
@@ -517,9 +520,9 @@ showkre(void)
 
        put64(s.bufspace, VMSTATROW + 13, VMSTATCOL, 7, 0);
        put64(s.dirtybufspace/1024, VMSTATROW + 14, VMSTATCOL, 7, 'k');
-       put64(s.desiredvnodes, VMSTATROW + 15, VMSTATCOL, 7, 'D');
-       put64(s.numvnodes, VMSTATROW + 16, VMSTATCOL, 7, 'D');
-       put64(s.freevnodes, VMSTATROW + 17, VMSTATCOL, 7, 'D');
+       put64(s.activevnodes, VMSTATROW + 15, VMSTATCOL, 7, 'D');
+       put64(s.cachedvnodes, VMSTATROW + 16, VMSTATCOL, 7, 'D');
+       put64(s.inactivevnodes, VMSTATROW + 17, VMSTATCOL, 7, 'D');
        PUTRATE(Vmm.v_vnodein, PAGEROW + 2, PAGECOL + 6, 4);
        PUTRATE(Vmm.v_vnodeout, PAGEROW + 2, PAGECOL + 11, 4);
        PUTRATE(Vmm.v_swapin, PAGEROW + 2, PAGECOL + 18, 4);
@@ -817,8 +820,10 @@ getinfo(struct Info *ls)
                err(1, "kinfo_get_sched_cputime");
        NREAD(X_BUFFERSPACE, &ls->bufspace, sizeof(ls->bufspace));
        NREAD(X_DESIREDVNODES, &ls->desiredvnodes, sizeof(ls->desiredvnodes));
-       NREAD(X_NUMVNODES, &ls->numvnodes, sizeof(ls->numvnodes));
-       NREAD(X_FREEVNODES, &ls->freevnodes, sizeof(ls->freevnodes));
+       NREAD(X_CACHEDVNODES, &ls->cachedvnodes, sizeof(ls->cachedvnodes));
+       NREAD(X_INACTIVEVNODES, &ls->inactivevnodes,
+                                               sizeof(ls->inactivevnodes));
+       NREAD(X_ACTIVEVNODES, &ls->activevnodes, sizeof(ls->activevnodes));
        NREAD(X_NUMDIRTYBUFFERS, &ls->dirtybufspace, sizeof(ls->dirtybufspace));
 
        if (nintr) {
index 7f17778..57c4249 100644 (file)
@@ -447,9 +447,8 @@ vnode_print(struct vnode *avnode, struct vnode *vp)
         * Convert SYSREF ref counts into something more
         * human readable for display.
         */
-       if ((refs = vp->v_sysref.refcnt) < 0)
-               refs = -(refs + 0x40000001);
-       printf("%8lx %s %5s %4d %4d",
+       refs = vp->v_refcnt;
+       printf("%8lx %s %5s %08x %4d",
            (u_long)(void *)avnode, type, flags, refs, vp->v_auxrefs);
 }