Index: sys/fs/msdosfs/msdosfs_vfsops.c =================================================================== --- sys/fs/msdosfs/msdosfs_vfsops.c +++ sys/fs/msdosfs/msdosfs_vfsops.c @@ -792,7 +792,7 @@ vn_printf(vp, "msdosfs_umount(): just before calling VOP_CLOSE()\n"); printf("freef %p, freeb %p, mount %p\n", - TAILQ_NEXT(vp, v_actfreelist), vp->v_actfreelist.tqe_prev, + TAILQ_NEXT(vp, v_vnodelist), vp->v_vnodelist.tqe_prev, vp->v_mount); printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", TAILQ_FIRST(&vp->v_bufobj.bo_clean.bv_hd), Index: sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdport.c +++ sys/fs/nfsserver/nfs_nfsdport.c @@ -3317,7 +3317,6 @@ inited = 1; nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED); TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist); - TAILQ_INIT(&nfsv4root_mnt.mnt_activevnodelist); TAILQ_INIT(&nfsv4root_mnt.mnt_dirtyvnodelist); nfsv4root_mnt.mnt_export = NULL; TAILQ_INIT(&nfsv4root_opt); @@ -3325,7 +3324,6 @@ nfsv4root_mnt.mnt_opt = &nfsv4root_opt; nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt; nfsv4root_mnt.mnt_nvnodelistsize = 0; - nfsv4root_mnt.mnt_activevnodelistsize = 0; nfsv4root_mnt.mnt_dirtyvnodelistsize = 0; } Index: sys/fs/tmpfs/tmpfs_vfsops.c =================================================================== --- sys/fs/tmpfs/tmpfs_vfsops.c +++ sys/fs/tmpfs/tmpfs_vfsops.c @@ -101,7 +101,7 @@ /* * Handle updates of time from writes to mmaped regions. Use - * MNT_VNODE_FOREACH_ALL instead of MNT_VNODE_FOREACH_ACTIVE, since + * MNT_VNODE_FOREACH_ALL instead of MNT_VNODE_FOREACH_DIRTY, since * unmap of the tmpfs-backed vnode does not call vinactive(), due to * vm object type is OBJT_SWAP. * If lazy, only handle delayed update of mtime due to the writes to Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -1706,7 +1706,7 @@ error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp); else { VI_LOCK(vp); - if (vp->v_iflag & VI_FREE) + if (vp->v_holdcnt == 0) error = EOPNOTSUPP; else error = EACCES; Index: sys/kern/vfs_mount.c =================================================================== --- sys/kern/vfs_mount.c +++ sys/kern/vfs_mount.c @@ -502,10 +502,6 @@ __rangeof(struct mount, mnt_startzero, mnt_endzero)); TAILQ_INIT(&mp->mnt_nvnodelist); mp->mnt_nvnodelistsize = 0; - TAILQ_INIT(&mp->mnt_activevnodelist); - mp->mnt_activevnodelistsize = 0; - TAILQ_INIT(&mp->mnt_tmpfreevnodelist); - mp->mnt_tmpfreevnodelistsize = 0; TAILQ_INIT(&mp->mnt_dirtyvnodelist); mp->mnt_dirtyvnodelistsize = 0; if (mp->mnt_ref != 0 || mp->mnt_lockref != 0 || @@ -573,10 +569,6 @@ KASSERT(TAILQ_EMPTY(&mp->mnt_uppers), ("mnt_uppers")); if (mp->mnt_nvnodelistsize != 0) panic("vfs_mount_destroy: nonzero nvnodelistsize"); - if (mp->mnt_activevnodelistsize != 0) - panic("vfs_mount_destroy: nonzero activevnodelistsize"); - if (mp->mnt_tmpfreevnodelistsize != 0) - panic("vfs_mount_destroy: nonzero tmpfreevnodelistsize"); if (mp->mnt_dirtyvnodelistsize != 0) panic("vfs_mount_destroy: nonzero dirtyvnodelistsize"); if (mp->mnt_lockref != 0) Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -114,7 +114,6 @@ static void vfs_knlunlock(void *arg); static void vfs_knl_assert_locked(void *arg); static void vfs_knl_assert_unlocked(void *arg); -static void vnlru_return_batches(struct vfsops *mnt_op); static void destroy_vpollinfo(struct vpollinfo *vi); static int v_inval_buf_range_locked(struct vnode *vp, struct bufobj *bo, daddr_t startlbn, daddr_t endlbn); @@ -148,10 +147,6 @@ SYSCTL_COUNTER_U64(_vfs, OID_AUTO, vnodes_created, CTLFLAG_RD, &vnodes_created, "Number of vnodes created by getnewvnode"); -static u_long mnt_free_list_batch = 128; -SYSCTL_ULONG(_vfs, OID_AUTO, mnt_free_list_batch, CTLFLAG_RW, - &mnt_free_list_batch, 0, "Limit of vnodes held on mnt's free list"); - /* * Conversion tables for conversion from vnode types to inode formats * and back. @@ -166,9 +161,10 @@ }; /* - * List of vnodes that are ready for recycling. + * List of allocates vnodes in the system. */ -static TAILQ_HEAD(freelst, vnode) vnode_free_list; +static TAILQ_HEAD(freelst, vnode) vnode_list; +static struct vnode *vnode_list_marker; /* * "Free" vnode target. Free vnodes are rarely completely free, but are @@ -196,7 +192,7 @@ static u_long wantfreevnodes; SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, "Target for minimum number of \"free\" vnodes"); -static u_long freevnodes; +static u_long __exclusive_cache_line freevnodes; SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, "Number of \"free\" vnodes"); @@ -226,11 +222,11 @@ /* * Lock for any access to the following: - * vnode_free_list + * vnode_list * numvnodes * freevnodes */ -static struct mtx __exclusive_cache_line vnode_free_list_mtx; +static struct mtx __exclusive_cache_line vnode_list_mtx; /* Publicly exported FS */ struct nfs_public nfs_pub; @@ -517,6 +513,10 @@ * Initialize rangelocks. */ rangelock_init(&vp->v_rl); + + mtx_lock(&vnode_list_mtx); + TAILQ_INSERT_BEFORE(vnode_list_marker, vp, v_vnodelist); + mtx_unlock(&vnode_list_mtx); return (0); } @@ -530,6 +530,9 @@ struct bufobj *bo; vp = mem; + mtx_lock(&vnode_list_mtx); + TAILQ_REMOVE(&vnode_list, vp, v_vnodelist); + mtx_unlock(&vnode_list_mtx); rangelock_destroy(&vp->v_rl); lockdestroy(vp->v_vnlock); mtx_destroy(&vp->v_interlock); @@ -588,8 +591,10 @@ } wantfreevnodes = desiredvnodes / 4; mtx_init(&mntid_mtx, "mntid", NULL, MTX_DEF); - TAILQ_INIT(&vnode_free_list); - mtx_init(&vnode_free_list_mtx, "vnode_free_list", NULL, MTX_DEF); + TAILQ_INIT(&vnode_list); + mtx_init(&vnode_list_mtx, "vnode_list", NULL, MTX_DEF); + vnode_list_marker = vn_alloc_marker(NULL); + TAILQ_INSERT_HEAD(&vnode_list, vnode_list_marker, v_vnodelist); vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL, vnode_init, vnode_fini, UMA_ALIGN_PTR, 0); vnodepoll_zone = uma_zcreate("VNODEPOLL", sizeof (struct vpollinfo), @@ -1058,7 +1063,7 @@ */ if (vp->v_usecount || (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) || - ((vp->v_iflag & VI_FREE) != 0) || + vp->v_holdcnt == 0 || VN_IS_DOOMED(vp) || (vp->v_object != NULL && vp->v_object->resident_page_count > trigger)) { VI_UNLOCK(vp); @@ -1129,35 +1134,21 @@ { struct vnode *vp; struct mount *mp; - bool tried_batches; - tried_batches = false; - mtx_assert(&vnode_free_list_mtx, MA_OWNED); + mtx_assert(&vnode_list_mtx, MA_OWNED); if (count > max_vnlru_free) count = max_vnlru_free; - for (; count > 0; count--) { - vp = TAILQ_FIRST(&vnode_free_list); - /* - * The list can be modified while the free_list_mtx - * has been dropped and vp could be NULL here. - */ - if (vp == NULL) { - if (tried_batches) - break; - mtx_unlock(&vnode_free_list_mtx); - vnlru_return_batches(mnt_op); - tried_batches = true; - mtx_lock(&vnode_free_list_mtx); - continue; +restart: + vp = vnode_list_marker; + while (count > 0) { + vp = TAILQ_NEXT(vp, v_vnodelist); + if (__predict_false(vp == NULL)) { + TAILQ_REMOVE(&vnode_list, vnode_list_marker, v_vnodelist); + TAILQ_INSERT_TAIL(&vnode_list, vnode_list_marker, v_vnodelist); + break; } - - VNASSERT(vp->v_op != NULL, vp, - ("vnlru_free: vnode already reclaimed.")); - KASSERT((vp->v_iflag & VI_FREE) != 0, - ("Removing vnode not on freelist")); - KASSERT((vp->v_iflag & VI_ACTIVE) == 0, - ("Mangling active vnode")); - TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist); + if (__predict_false(vp->v_type == VMARKER)) + continue; /* * Don't recycle if our vnode is from different type @@ -1167,28 +1158,19 @@ * Don't recycle if we can't get the interlock without * blocking. */ - if ((mnt_op != NULL && (mp = vp->v_mount) != NULL && + if (vp->v_holdcnt > 0 || (mnt_op != NULL && (mp = vp->v_mount) != NULL && mp->mnt_op != mnt_op) || !VI_TRYLOCK(vp)) { - TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_actfreelist); continue; } - VNASSERT((vp->v_iflag & VI_FREE) != 0 && vp->v_holdcnt == 0, - vp, ("vp inconsistent on freelist")); - - /* - * The clear of VI_FREE prevents activation of the - * vnode. There is no sense in putting the vnode on - * the mount point active list, only to remove it - * later during recycling. Inline the relevant part - * of vholdl(), to avoid triggering assertions or - * activating. - */ - freevnodes--; - vp->v_iflag &= ~VI_FREE; - VNODE_REFCOUNT_FENCE_REL(); - refcount_acquire(&vp->v_holdcnt); - - mtx_unlock(&vnode_free_list_mtx); + TAILQ_REMOVE(&vnode_list, vnode_list_marker, v_vnodelist); + TAILQ_INSERT_AFTER(&vnode_list, vp, vnode_list_marker, v_vnodelist); + if (__predict_false(vp->v_type == VBAD || vp->v_type == VNON)) { + VI_UNLOCK(vp); + continue; + } + vholdl(vp); + count--; + mtx_unlock(&vnode_list_mtx); VI_UNLOCK(vp); vtryrecycle(vp); /* @@ -1197,7 +1179,8 @@ * the free list. */ vdrop(vp); - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); + goto restart; } } @@ -1205,9 +1188,9 @@ vnlru_free(int count, struct vfsops *mnt_op) { - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); vnlru_free_locked(count, mnt_op); - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); } @@ -1231,63 +1214,6 @@ return (space); } -static void -vnlru_return_batch_locked(struct mount *mp) -{ - struct vnode *vp; - - mtx_assert(&mp->mnt_listmtx, MA_OWNED); - - if (mp->mnt_tmpfreevnodelistsize == 0) - return; - - TAILQ_FOREACH(vp, &mp->mnt_tmpfreevnodelist, v_actfreelist) { - VNASSERT((vp->v_mflag & VMP_TMPMNTFREELIST) != 0, vp, - ("vnode without VMP_TMPMNTFREELIST on mnt_tmpfreevnodelist")); - vp->v_mflag &= ~VMP_TMPMNTFREELIST; - } - mtx_lock(&vnode_free_list_mtx); - TAILQ_CONCAT(&vnode_free_list, &mp->mnt_tmpfreevnodelist, v_actfreelist); - freevnodes += mp->mnt_tmpfreevnodelistsize; - mtx_unlock(&vnode_free_list_mtx); - mp->mnt_tmpfreevnodelistsize = 0; -} - -static void -vnlru_return_batch(struct mount *mp) -{ - - mtx_lock(&mp->mnt_listmtx); - vnlru_return_batch_locked(mp); - mtx_unlock(&mp->mnt_listmtx); -} - -static void -vnlru_return_batches(struct vfsops *mnt_op) -{ - struct mount *mp, *nmp; - bool need_unbusy; - - mtx_lock(&mountlist_mtx); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - need_unbusy = false; - if (mnt_op != NULL && mp->mnt_op != mnt_op) - goto next; - if (mp->mnt_tmpfreevnodelistsize == 0) - goto next; - if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK) == 0) { - vnlru_return_batch(mp); - need_unbusy = true; - mtx_lock(&mountlist_mtx); - } -next: - nmp = TAILQ_NEXT(mp, mnt_list); - if (need_unbusy) - vfs_unbusy(mp); - } - mtx_unlock(&mountlist_mtx); -} - /* * Attempt to recycle vnodes in a context that is always safe to block. * Calling vlrurecycle() from the bowels of filesystem code has some @@ -1311,7 +1237,7 @@ force = 0; for (;;) { kproc_suspend_check(vnlruproc); - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); rnumvnodes = atomic_load_long(&numvnodes); /* * If numvnodes is too large (due to desiredvnodes being @@ -1335,11 +1261,11 @@ if (vsp >= vlowat && force == 0) { vnlruproc_sig = 0; wakeup(&vnlruproc_sig); - msleep(vnlruproc, &vnode_free_list_mtx, + msleep(vnlruproc, &vnode_list_mtx, PVFS|PDROP, "vlruwt", hz); continue; } - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); done = 0; rnumvnodes = atomic_load_long(&numvnodes); rfreevnodes = atomic_load_long(&freevnodes); @@ -1498,7 +1424,7 @@ getnewvnode_wait(int suspended) { - mtx_assert(&vnode_free_list_mtx, MA_OWNED); + mtx_assert(&vnode_list_mtx, MA_OWNED); if (numvnodes >= desiredvnodes) { if (suspended) { /* @@ -1512,7 +1438,7 @@ vnlruproc_sig = 1; /* avoid unnecessary wakeups */ wakeup(vnlruproc); } - msleep(&vnlruproc_sig, &vnode_free_list_mtx, PVFS, + msleep(&vnlruproc_sig, &vnode_list_mtx, PVFS, "vlruwk", hz); } /* Post-adjust like the pre-adjust in getnewvnode(). */ @@ -1533,13 +1459,13 @@ /* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */ /* XXX no longer so quick, but this part is not racy. */ - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); rnumvnodes = atomic_load_long(&numvnodes); rfreevnodes = atomic_load_long(&freevnodes); if (rnumvnodes + count > desiredvnodes && rfreevnodes > wantfreevnodes) vnlru_free_locked(ulmin(rnumvnodes + count - desiredvnodes, rfreevnodes - wantfreevnodes), NULL); - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); td = curthread; /* First try to be quick and racy. */ @@ -1550,7 +1476,7 @@ } else atomic_subtract_long(&numvnodes, count); - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); while (count > 0) { if (getnewvnode_wait(0) == 0) { count--; @@ -1559,7 +1485,7 @@ } } vcheckspace(); - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); } /* @@ -1604,7 +1530,7 @@ td->td_vp_reserv -= 1; goto alloc; } - mtx_lock(&vnode_free_list_mtx); + mtx_lock(&vnode_list_mtx); if (numvnodes < desiredvnodes) cyclecount = 0; else if (cyclecount++ >= freevnodes) { @@ -1630,14 +1556,14 @@ MNTK_SUSPEND)); #if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */ if (error != 0) { - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); return (error); } #endif } vcheckspace(); atomic_add_long(&numvnodes, 1); - mtx_unlock(&vnode_free_list_mtx); + mtx_unlock(&vnode_list_mtx); alloc: counter_u64_add(vnodes_created, 1); vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK); @@ -1719,8 +1645,6 @@ CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); atomic_subtract_long(&numvnodes, 1); bo = &vp->v_bufobj; - VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, - ("cleaned vnode still on the free list.")); VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); VNASSERT(vp->v_holdcnt == 0, vp, ("Non-zero hold count")); VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); @@ -1774,16 +1698,6 @@ return; MNT_ILOCK(mp); VI_LOCK(vp); - KASSERT(mp->mnt_activevnodelistsize <= mp->mnt_nvnodelistsize, - ("Active vnode list size %d > Vnode list size %d", - mp->mnt_activevnodelistsize, mp->mnt_nvnodelistsize)); - if (vp->v_iflag & VI_ACTIVE) { - vp->v_iflag &= ~VI_ACTIVE; - mtx_lock(&mp->mnt_listmtx); - TAILQ_REMOVE(&mp->mnt_activevnodelist, vp, v_actfreelist); - mp->mnt_activevnodelistsize--; - mtx_unlock(&mp->mnt_listmtx); - } if (vp->v_mflag & VMP_DIRTYLIST) { mtx_lock(&mp->mnt_listmtx); if (vp->v_mflag & VMP_DIRTYLIST) { @@ -1853,13 +1767,6 @@ VNASSERT(mp->mnt_nvnodelistsize >= 0, vp, ("neg mount point vnode list size")); mp->mnt_nvnodelistsize++; - KASSERT((vp->v_iflag & VI_ACTIVE) == 0, - ("Activating already active vnode")); - vp->v_iflag |= VI_ACTIVE; - mtx_lock(&mp->mnt_listmtx); - TAILQ_INSERT_HEAD(&mp->mnt_activevnodelist, vp, v_actfreelist); - mp->mnt_activevnodelistsize++; - mtx_unlock(&mp->mnt_listmtx); VI_UNLOCK(vp); MNT_IUNLOCK(mp); return (0); @@ -3219,38 +3126,13 @@ static void vhold_activate(struct vnode *vp) { - struct mount *mp; ASSERT_VI_LOCKED(vp, __func__); VNASSERT(vp->v_holdcnt == 0, vp, ("%s: wrong hold count", __func__)); VNASSERT(vp->v_op != NULL, vp, ("%s: vnode already reclaimed.", __func__)); - /* - * Remove a vnode from the free list, mark it as in use, - * and put it on the active list. - */ - VNASSERT(vp->v_mount != NULL, vp, - ("_vhold: vnode not on per mount vnode list")); - mp = vp->v_mount; - mtx_lock(&mp->mnt_listmtx); - if ((vp->v_mflag & VMP_TMPMNTFREELIST) != 0) { - TAILQ_REMOVE(&mp->mnt_tmpfreevnodelist, vp, v_actfreelist); - mp->mnt_tmpfreevnodelistsize--; - vp->v_mflag &= ~VMP_TMPMNTFREELIST; - } else { - mtx_lock(&vnode_free_list_mtx); - TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist); - freevnodes--; - mtx_unlock(&vnode_free_list_mtx); - } - KASSERT((vp->v_iflag & VI_ACTIVE) == 0, - ("Activating already active vnode")); - vp->v_iflag &= ~VI_FREE; - vp->v_iflag |= VI_ACTIVE; - TAILQ_INSERT_HEAD(&mp->mnt_activevnodelist, vp, v_actfreelist); - mp->mnt_activevnodelistsize++; - mtx_unlock(&mp->mnt_listmtx); + atomic_subtract_long(&freevnodes, 1); refcount_acquire(&vp->v_holdcnt); } @@ -3260,12 +3142,8 @@ ASSERT_VI_UNLOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - if (refcount_acquire_if_not_zero(&vp->v_holdcnt)) { - VNODE_REFCOUNT_FENCE_ACQ(); - VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, - ("vhold: vnode with holdcnt is free")); + if (refcount_acquire_if_not_zero(&vp->v_holdcnt)) return; - } VI_LOCK(vp); vholdl(vp); VI_UNLOCK(vp); @@ -3277,7 +3155,7 @@ ASSERT_VI_LOCKED(vp, __func__); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - if ((vp->v_iflag & VI_FREE) == 0) { + if (vp->v_holdcnt > 0) { refcount_acquire(&vp->v_holdcnt); return; } @@ -3320,34 +3198,26 @@ ("vdrop: returning doomed vnode")); VNASSERT(vp->v_op != NULL, vp, ("vdrop: vnode already reclaimed.")); - VNASSERT((vp->v_iflag & VI_FREE) == 0, vp, - ("vnode already free")); + VNASSERT(vp->v_holdcnt == 0, vp, + ("vdrop: freeing when we shouldn't")); VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, ("vnode with VI_OWEINACT set")); VNASSERT((vp->v_iflag & VI_DEFINACT) == 0, vp, ("vnode with VI_DEFINACT set")); - VNASSERT(vp->v_holdcnt == 0, vp, - ("vdrop: freeing when we shouldn't")); - mp = vp->v_mount; - mtx_lock(&mp->mnt_listmtx); if (vp->v_mflag & VMP_DIRTYLIST) { + mp = vp->v_mount; + mtx_lock(&mp->mnt_listmtx); vp->v_mflag &= ~VMP_DIRTYLIST; TAILQ_REMOVE(&mp->mnt_dirtyvnodelist, vp, v_dirtylist); mp->mnt_dirtyvnodelistsize--; + mtx_unlock(&mp->mnt_listmtx); } - if (vp->v_iflag & VI_ACTIVE) { - vp->v_iflag &= ~VI_ACTIVE; - TAILQ_REMOVE(&mp->mnt_activevnodelist, vp, v_actfreelist); - mp->mnt_activevnodelistsize--; - } - TAILQ_INSERT_TAIL(&mp->mnt_tmpfreevnodelist, vp, v_actfreelist); - mp->mnt_tmpfreevnodelistsize++; - vp->v_iflag |= VI_FREE; - vp->v_mflag |= VMP_TMPMNTFREELIST; + mtx_lock(&vnode_list_mtx); + TAILQ_REMOVE(&vnode_list, vp, v_vnodelist); + TAILQ_INSERT_TAIL(&vnode_list, vp, v_vnodelist); + mtx_unlock(&vnode_list_mtx); + atomic_add_long(&freevnodes, 1); VI_UNLOCK(vp); - if (mp->mnt_tmpfreevnodelistsize >= mnt_free_list_batch) - vnlru_return_batch_locked(mp); - mtx_unlock(&mp->mnt_listmtx); } void @@ -3894,27 +3764,21 @@ strlcat(buf, "|VI_TEXT_REF", sizeof(buf)); if (vp->v_iflag & VI_MOUNT) strlcat(buf, "|VI_MOUNT", sizeof(buf)); - if (vp->v_iflag & VI_FREE) - strlcat(buf, "|VI_FREE", sizeof(buf)); - if (vp->v_iflag & VI_ACTIVE) - strlcat(buf, "|VI_ACTIVE", sizeof(buf)); if (vp->v_iflag & VI_DOINGINACT) strlcat(buf, "|VI_DOINGINACT", sizeof(buf)); if (vp->v_iflag & VI_OWEINACT) strlcat(buf, "|VI_OWEINACT", sizeof(buf)); if (vp->v_iflag & VI_DEFINACT) strlcat(buf, "|VI_DEFINACT", sizeof(buf)); - flags = vp->v_iflag & ~(VI_TEXT_REF | VI_MOUNT | VI_FREE | VI_ACTIVE | - VI_DOINGINACT | VI_OWEINACT | VI_DEFINACT); + flags = vp->v_iflag & ~(VI_TEXT_REF | VI_MOUNT | VI_DOINGINACT | + VI_OWEINACT | VI_DEFINACT); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VI(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); } - if (vp->v_mflag & VMP_TMPMNTFREELIST) - strlcat(buf, "|VMP_TMPMNTFREELIST", sizeof(buf)); if (vp->v_mflag & VMP_DIRTYLIST) strlcat(buf, "|VMP_DIRTYLIST", sizeof(buf)); - flags = vp->v_mflag & ~(VMP_TMPMNTFREELIST | VMP_DIRTYLIST); + flags = vp->v_mflag & ~(VMP_DIRTYLIST); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VMP(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); @@ -4132,8 +3996,6 @@ vfs_mount_fetch_counter(mp, MNT_COUNT_REF), mp->mnt_ref); db_printf(" mnt_gen = %d\n", mp->mnt_gen); db_printf(" mnt_nvnodelistsize = %d\n", mp->mnt_nvnodelistsize); - db_printf(" mnt_activevnodelistsize = %d\n", - mp->mnt_activevnodelistsize); db_printf(" mnt_dirtyvnodelistsize = %d\n", mp->mnt_dirtyvnodelistsize); db_printf(" mnt_writeopcount = %d (with %d in the struct)\n", @@ -4151,8 +4013,8 @@ db_printf(" mnt_vfs_ops = %d\n", mp->mnt_vfs_ops); db_printf("\n\nList of active vnodes\n"); - TAILQ_FOREACH(vp, &mp->mnt_activevnodelist, v_actfreelist) { - if (vp->v_type != VMARKER) { + TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) { + if (vp->v_type != VMARKER && vp->v_holdcnt > 0) { vn_printf(vp, "vnode "); if (db_pager_quit) break; @@ -4160,7 +4022,7 @@ } db_printf("\n\nList of inactive vnodes\n"); TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes) { - if (vp->v_type != VMARKER && (vp->v_iflag & VI_ACTIVE) == 0) { + if (vp->v_type != VMARKER && vp->v_holdcnt == 0) { vn_printf(vp, "vnode "); if (db_pager_quit) break; @@ -4810,7 +4672,6 @@ * The filesystem at hand may be idle with free vnodes stored in the * batch. Return them instead of letting them stay there indefinitely. */ - vnlru_return_batch(mp); vfs_periodic(mp, MNT_NOWAIT); error = VFS_SYNC(mp, MNT_LAZY); curthread_pflags_restore(save); @@ -6097,7 +5958,7 @@ MNT_ILOCK(mp); MNT_REL(mp); MNT_IUNLOCK(mp); - free(*mvp, M_VNODE_MARKER); + vn_free_marker(*mvp); *mvp = NULL; } @@ -6241,7 +6102,6 @@ TAILQ_INSERT_AFTER(&mp->mnt_dirtyvnodelist, vp, *mvp, v_dirtylist); mtx_unlock(&mp->mnt_listmtx); ASSERT_VI_LOCKED(vp, "dirty iter"); - KASSERT((vp->v_iflag & VI_ACTIVE) != 0, ("Non-active vp %p", vp)); return (vp); } @@ -6262,12 +6122,10 @@ { struct vnode *vp; - *mvp = malloc(sizeof(struct vnode), M_VNODE_MARKER, M_WAITOK | M_ZERO); + *mvp = vn_alloc_marker(mp); MNT_ILOCK(mp); MNT_REF(mp); MNT_IUNLOCK(mp); - (*mvp)->v_type = VMARKER; - (*mvp)->v_mount = mp; mtx_lock(&mp->mnt_listmtx); vp = TAILQ_FIRST(&mp->mnt_dirtyvnodelist); Index: sys/sys/mount.h =================================================================== --- sys/sys/mount.h +++ sys/sys/mount.h @@ -219,10 +219,6 @@ #define mnt_endzero mnt_gjprovider char *mnt_gjprovider; /* gjournal provider name */ struct mtx mnt_listmtx; - struct vnodelst mnt_activevnodelist; /* (l) list of active vnodes */ - int mnt_activevnodelistsize;/* (l) # of active vnodes */ - struct vnodelst mnt_tmpfreevnodelist; /* (l) list of free vnodes */ - int mnt_tmpfreevnodelistsize;/* (l) # of free vnodes */ struct vnodelst mnt_dirtyvnodelist; /* (l) list of dirty vnodes */ int mnt_dirtyvnodelistsize; /* (l) # of dirty vnodes */ struct lock mnt_explock; /* vfs_export walkers lock */ @@ -255,20 +251,6 @@ mtx_assert(MNT_MTX(mp), MA_NOTOWNED); \ } while (0) -/* - * Definitions for MNT_VNODE_FOREACH_ACTIVE. - */ -struct vnode *__mnt_vnode_next_active(struct vnode **mvp, struct mount *mp); -struct vnode *__mnt_vnode_first_active(struct vnode **mvp, struct mount *mp); -void __mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *); - -#define MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) \ - for (vp = __mnt_vnode_first_active(&(mvp), (mp)); \ - (vp) != NULL; vp = __mnt_vnode_next_active(&(mvp), (mp))) - -#define MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp) \ - __mnt_vnode_markerfree_active(&(mvp), (mp)) - /* * Definitions for MNT_VNODE_FOREACH_DIRTY. */ Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -147,7 +147,7 @@ /* * The machinery of being a vnode */ - TAILQ_ENTRY(vnode) v_actfreelist; /* l vnode active/free lists */ + TAILQ_ENTRY(vnode) v_vnodelist; /* l vnode lists */ TAILQ_ENTRY(vnode) v_dirtylist; /* l vnode dirty list */ struct bufobj v_bufobj; /* * Buffer cache object */ @@ -239,8 +239,6 @@ #define VI_TEXT_REF 0x0001 /* Text ref grabbed use ref */ #define VI_MOUNT 0x0020 /* Mount in progress */ -#define VI_FREE 0x0100 /* This vnode is on the freelist */ -#define VI_ACTIVE 0x0200 /* This vnode is on the active list */ #define VI_DOINGINACT 0x0800 /* VOP_INACTIVE is in progress */ #define VI_OWEINACT 0x1000 /* Need to call inactive */ #define VI_DEFINACT 0x2000 /* deferred inactive */ @@ -260,8 +258,7 @@ #define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */ #define VV_READLINK 0x2000 /* fdescfs linux vnode */ -#define VMP_TMPMNTFREELIST 0x0001 /* Vnode is on mnt's tmp free list */ -#define VMP_DIRTYLIST 0x0002 /* Vnode is on mnt's dirty free list */ +#define VMP_DIRTYLIST 0x0001 /* Vnode is on mnt's dirty list */ /* * Vnode attributes. A field value of VNOVAL represents a field whose value Index: sys/ufs/ufs/ufs_quota.c =================================================================== --- sys/ufs/ufs/ufs_quota.c +++ sys/ufs/ufs/ufs_quota.c @@ -1083,7 +1083,7 @@ * synchronizing any modified dquot structures. */ again: - MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { if (vp->v_type == VNON) { VI_UNLOCK(vp); continue; @@ -1091,7 +1091,7 @@ error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); if (error) { if (error == ENOENT) { - MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp); + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); goto again; } continue;