Index: sys/fs/unionfs/union_subr.c =================================================================== --- sys/fs/unionfs/union_subr.c +++ sys/fs/unionfs/union_subr.c @@ -126,7 +126,7 @@ vp = UNIONFSTOV(unp); VI_LOCK_FLAGS(vp, MTX_DUPOK); VI_UNLOCK(dvp); - vp->v_iflag &= ~VI_OWEINACT; + vp->v_irflag &= ~VIRF_OWEINACT; if (VN_IS_DOOMED(vp) || ((vp->v_iflag & VI_DOINGINACT) != 0)) { VI_UNLOCK(vp); @@ -163,7 +163,7 @@ if (!strcmp(unp->un_path, path)) { vp = UNIONFSTOV(unp); VI_LOCK_FLAGS(vp, MTX_DUPOK); - vp->v_iflag &= ~VI_OWEINACT; + vp->v_irflag &= ~VIRF_OWEINACT; if (VN_IS_DOOMED(vp) || ((vp->v_iflag & VI_DOINGINACT) != 0)) { LIST_INSERT_HEAD(hd, uncp, un_hash); Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -1868,7 +1868,7 @@ if ((revlock = unionfs_get_llt_revlock(vp, flags)) == 0) panic("unknown lock type: 0x%x", flags & LK_TYPE_MASK); - if ((vp->v_iflag & VI_OWEINACT) != 0) + if ((vp->v_irflag & VIRF_OWEINACT) != 0) flags |= LK_NOWAIT; /* Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -2819,6 +2819,58 @@ } } +/* + * Try to perform inactive processing. + * + * We are called with hold count on the vnode. + * + * This can race with vref which will bump v_usecount without locking the vnode. + * There is no way to lock it out, making this best effort. + */ +static int __noinline +vget_inactive(struct vnode *vp, int flags) +{ + bool upgraded; + + ASSERT_VOP_LOCKED(vp, __func__); + /* + * There is nothing we can do if we raced with vref. + */ + if (vp->v_usecount > 0) + return (0); + + if (flags & LK_NOWAIT) { + VOP_UNLOCK(vp); + vdrop(vp); + return (EAGAIN); + } + + upgraded = false; + if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { + VOP_LOCK(vp, LK_UPGRADE); + if (VN_IS_DOOMED(vp)) { + VOP_UNLOCK(vp); + vdrop(vp); + return (ENOENT); + } + upgraded = true; + } + + /* + * By the time we get here v_usecount may be > 0 because of vref + * or some other vget caller managed to call vinactive. The first + * condition is a race which affects vputx anyway and the latter + * is harmless. + */ + VI_LOCK(vp); + vinactive(vp); + VI_UNLOCK(vp); + + if (upgraded) + VOP_LOCK(vp, LK_DOWNGRADE); + return (0); +} + /* * Grab a particular vnode from the free list, increment its * reference count and lock it. VIRF_DOOMED is set if the vnode @@ -2921,10 +2973,20 @@ return (error); } + /* + * There is no way to assert VIRF_OWEINACT is not set since may be + * acquired because of vref. + */ if (vs == VGET_USECOUNT) { return (0); } + if (__predict_false(vp->v_irflag & VIRF_OWEINACT)) { + error = vget_inactive(vp, flags); + if (error != 0) + return (error); + } + if (__predict_false(vp->v_type == VCHR)) return (vget_finish_vchr(vp)); @@ -3105,7 +3167,7 @@ return; } if (vp->v_usecount > 0) { - vp->v_iflag &= ~VI_OWEINACT; + vp->v_irflag &= ~VIRF_OWEINACT; vdropl(vp); return; } @@ -3120,7 +3182,7 @@ { VI_LOCK(vp); - if ((vp->v_iflag & VI_OWEINACT) == 0) { + if ((vp->v_irflag & VIRF_OWEINACT) == 0) { vdropl(vp); return; } @@ -3191,7 +3253,7 @@ * We must call VOP_INACTIVE with the node locked. Mark * as VI_DOINGINACT to avoid recursion. */ - vp->v_iflag |= VI_OWEINACT; + vp->v_irflag |= VIRF_OWEINACT; switch (func) { case VPUTX_VRELE: error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); @@ -3425,8 +3487,8 @@ ("vdrop: returning doomed vnode")); VNASSERT(vp->v_op != NULL, vp, ("vdrop: vnode already reclaimed.")); - VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, - ("vnode with VI_OWEINACT set")); + VNASSERT((vp->v_irflag & VIRF_OWEINACT) == 0, vp, + ("vnode with VIRF_OWEINACT set")); VNASSERT((vp->v_iflag & VI_DEFINACT) == 0, vp, ("vnode with VI_DEFINACT set")); if (vp->v_mflag & VMP_LAZYLIST) { @@ -3493,7 +3555,7 @@ ("vinactive: recursed on VI_DOINGINACT")); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); vp->v_iflag |= VI_DOINGINACT; - vp->v_iflag &= ~VI_OWEINACT; + vp->v_irflag &= ~VIRF_OWEINACT; VI_UNLOCK(vp); /* * Before moving off the active list, we must be sure that any @@ -3526,12 +3588,12 @@ ASSERT_VI_LOCKED(vp, "vinactive"); CTR2(KTR_VFS, "%s: vp %p", __func__, vp); - if ((vp->v_iflag & VI_OWEINACT) == 0) + if ((vp->v_irflag & VIRF_OWEINACT) == 0) return; if (vp->v_iflag & VI_DOINGINACT) return; if (vp->v_usecount > 0) { - vp->v_iflag &= ~VI_OWEINACT; + vp->v_irflag &= ~VIRF_OWEINACT; return; } vinactivef(vp); @@ -3813,9 +3875,9 @@ * VOP_CLOSE() and VOP_INACTIVE(). */ active = vp->v_usecount > 0; - oweinact = (vp->v_iflag & VI_OWEINACT) != 0; + oweinact = (vp->v_irflag & VIRF_OWEINACT) != 0; /* - * If we need to do inactive VI_OWEINACT will be set. + * If we need to do inactive VIRF_OWEINACT will be set. */ if (vp->v_iflag & VI_DEFINACT) { VNASSERT(vp->v_holdcnt > 1, vp, ("lost hold count")); @@ -3965,7 +4027,9 @@ buf[1] = '\0'; if (vp->v_irflag & VIRF_DOOMED) strlcat(buf, "|VIRF_DOOMED", sizeof(buf)); - flags = vp->v_irflag & ~(VIRF_DOOMED); + if (vp->v_irflag & VIRF_OWEINACT) + strlcat(buf, "|VIRF_OWEINACT", sizeof(buf)); + flags = vp->v_irflag & ~(VIRF_DOOMED | VIRF_OWEINACT); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VIRF(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); @@ -4011,12 +4075,10 @@ strlcat(buf, "|VI_MOUNT", 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_DOINGINACT | - VI_OWEINACT | VI_DEFINACT); + VI_DEFINACT); if (flags != 0) { snprintf(buf2, sizeof(buf2), "|VI(0x%lx)", flags); strlcat(buf, buf2, sizeof(buf)); @@ -4579,7 +4641,7 @@ ASSERT_VI_LOCKED(vp, __func__); VNASSERT((vp->v_iflag & VI_DEFINACT) == 0, vp, ("VI_DEFINACT still set")); - if ((vp->v_iflag & VI_OWEINACT) == 0) { + if ((vp->v_irflag & VIRF_OWEINACT) == 0) { vdropl(vp); return; } Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -237,11 +237,11 @@ * are required for writing but the status may be checked with either. */ #define VIRF_DOOMED 0x0001 /* This vnode is being recycled */ +#define VIRF_OWEINACT 0x0002 /* Need to call inactive */ #define VI_TEXT_REF 0x0001 /* Text ref grabbed use ref */ #define VI_MOUNT 0x0020 /* Mount in progress */ #define VI_DOINGINACT 0x0800 /* VOP_INACTIVE is in progress */ -#define VI_OWEINACT 0x1000 /* Need to call inactive */ #define VI_DEFINACT 0x2000 /* deferred inactive */ #define VV_ROOT 0x0001 /* root of its filesystem */ Index: sys/ufs/ffs/ffs_snapshot.c =================================================================== --- sys/ufs/ffs/ffs_snapshot.c +++ sys/ufs/ffs/ffs_snapshot.c @@ -535,7 +535,8 @@ loop: MNT_VNODE_FOREACH_ALL(xvp, mp, mvp) { if ((xvp->v_usecount == 0 && - (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) || + ((xvp->v_irflag & VIRF_OWEINACT) == 0 && + (xvp->v_iflag & VI_DOINGINACT) == 0)) || xvp->v_type == VNON || IS_SNAPSHOT(VTOI(xvp))) { VI_UNLOCK(xvp); @@ -557,7 +558,8 @@ } VI_LOCK(xvp); if (xvp->v_usecount == 0 && - (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) { + ((xvp->v_irflag & VIRF_OWEINACT) == 0 && + (xvp->v_iflag & VI_DOINGINACT) == 0)) { VI_UNLOCK(xvp); VOP_UNLOCK(xvp); vdrop(xvp); @@ -2564,7 +2566,7 @@ */ if (vp->v_type == VNON || ((VTOI(vp)->i_flag & IN_LAZYACCESS) == 0 && - ((vp->v_iflag & VI_OWEINACT) == 0 || vp->v_usecount > 0))) { + ((vp->v_irflag & VIRF_OWEINACT) == 0 || vp->v_usecount > 0))) { VI_UNLOCK(vp); continue; } Index: sys/ufs/ffs/ffs_vfsops.c =================================================================== --- sys/ufs/ffs/ffs_vfsops.c +++ sys/ufs/ffs/ffs_vfsops.c @@ -1458,7 +1458,7 @@ if (vp->v_type == VNON) return (false); ip = VTOI(vp); - if (!sync_doupdate(ip) && (vp->v_iflag & VI_OWEINACT) == 0) + if (!sync_doupdate(ip) && (vp->v_irflag & VIRF_OWEINACT) == 0) return (false); return (true); } @@ -1500,7 +1500,7 @@ * Test also all the other timestamp flags too, to pick up * any other cases that could be missed. */ - if (!sync_doupdate(ip) && (vp->v_iflag & VI_OWEINACT) == 0) { + if (!sync_doupdate(ip) && (vp->v_irflag & VIRF_OWEINACT) == 0) { VI_UNLOCK(vp); continue; } Index: sys/ufs/ufs/ufs_inode.c =================================================================== --- sys/ufs/ufs/ufs_inode.c +++ sys/ufs/ufs/ufs_inode.c @@ -153,7 +153,7 @@ * it has resumed the file system. */ VI_LOCK(vp); - vp->v_iflag |= VI_OWEINACT; + vp->v_irflag |= VIRF_OWEINACT; VI_UNLOCK(vp); MNT_IUNLOCK(mp); return (0);