Index: sys/fs/tmpfs/tmpfs_vnops.c =================================================================== --- sys/fs/tmpfs/tmpfs_vnops.c +++ sys/fs/tmpfs/tmpfs_vnops.c @@ -1283,6 +1283,28 @@ return (0); } +static int +tmpfs_need_inactive(struct vop_need_inactive_args *ap) +{ + struct vnode *vp; + struct tmpfs_node *node; + struct vm_object *obj; + + vp = ap->a_vp; + node = VP_TO_TMPFS_NODE(vp); + if (node->tn_links == 0) + goto need; + if (vp->v_type == VREG) { + obj = vp->v_object; + if ((obj->flags & OBJ_TMPFS_DIRTY) != 0) + goto need; + } + return (0); +need: + vp->v_iflag |= VI_OWEINACT; + return (0); +} + int tmpfs_reclaim(struct vop_reclaim_args *v) { @@ -1584,6 +1606,7 @@ .vop_readdir = tmpfs_readdir, .vop_readlink = tmpfs_readlink, .vop_inactive = tmpfs_inactive, + .vop_need_inactive = tmpfs_need_inactive, .vop_reclaim = tmpfs_reclaim, .vop_print = tmpfs_print, .vop_pathconf = tmpfs_pathconf, Index: sys/kern/vfs_default.c =================================================================== --- sys/kern/vfs_default.c +++ sys/kern/vfs_default.c @@ -120,6 +120,7 @@ .vop_getpages_async = vop_stdgetpages_async, .vop_getwritemount = vop_stdgetwritemount, .vop_inactive = VOP_NULL, + .vop_need_inactive = vop_stdneed_inactive, .vop_ioctl = vop_stdioctl, .vop_kqfilter = vop_stdkqfilter, .vop_islocked = vop_stdislocked, @@ -1157,6 +1158,14 @@ return (error); } +int +vop_stdneed_inactive(struct vop_need_inactive_args *ap) +{ + + ap->a_vp->v_iflag |= VI_OWEINACT; + return (0); +} + static int vop_stdioctl(struct vop_ioctl_args *ap) { Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -2841,6 +2841,7 @@ static void vputx(struct vnode *vp, int func) { + struct vm_object *obj; int error; KASSERT(vp != NULL, ("vputx: null vp")); @@ -2879,8 +2880,6 @@ v_decr_devcount(vp); - error = 0; - if (vp->v_usecount != 0) { vn_printf(vp, "vputx: usecount not zero for vnode "); panic("vputx: usecount not zero"); @@ -2888,11 +2887,26 @@ CTR2(KTR_VFS, "%s: return vnode %p to the freelist", __func__, vp); - /* - * We must call VOP_INACTIVE with the node locked. Mark - * as VI_DOINGINACT to avoid recursion. - */ - vp->v_iflag |= VI_OWEINACT; + error = VOP_NEED_INACTIVE(vp); + if (error != 0) + panic("VOP_NEED_INACTIVE failed %d", error); + if ((vp->v_iflag & VI_OWEINACT) == 0) { + /* + * v_object association is protected by the vnode lock which we don't + * necessarily have. However, objects are type stable and this check + * is harmless if incorrect. + */ + if ((obj = vp->v_object) != NULL && (vp->v_vflag & VV_NOSYNC) == 0 && + (obj->flags & OBJ_MIGHTBEDIRTY) != 0) + vp->v_iflag |= VI_OWEINACT; + } + if ((vp->v_iflag & VI_OWEINACT) == 0) { + if (func == VPUTX_VPUT) + VOP_UNLOCK(vp, 0); + vdropl(vp); + return; + } + switch (func) { case VPUTX_VRELE: error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); @@ -4351,6 +4365,7 @@ .vop_close = sync_close, /* close */ .vop_fsync = sync_fsync, /* fsync */ .vop_inactive = sync_inactive, /* inactive */ + .vop_need_inactive = vop_stdneed_inactive, /* need_inactive */ .vop_reclaim = sync_reclaim, /* reclaim */ .vop_lock1 = vop_stdlock, /* lock */ .vop_unlock = vop_stdunlock, /* unlock */ @@ -4892,6 +4907,22 @@ if (a->a_flags & LK_INTERLOCK) ASSERT_VI_UNLOCKED(a->a_vp, "VOP_UNLOCK"); } + +void +vop_need_inactive_pre(void *ap) +{ + struct vop_need_inactive_args *a = ap; + + ASSERT_VI_LOCKED(a->a_vp, "VOP_NEED_INACTIVE"); +} + +void +vop_need_inactive_post(void *ap, int rc) +{ + struct vop_need_inactive_args *a = ap; + + ASSERT_VI_LOCKED(a->a_vp, "VOP_NEED_INACTIVE"); +} #endif void Index: sys/kern/vnode_if.src =================================================================== --- sys/kern/vnode_if.src +++ sys/kern/vnode_if.src @@ -358,6 +358,12 @@ IN struct thread *td; }; +%! need_inactive pre vop_need_inactive_pre +%! need_inactive post vop_need_inactive_post + +vop_need_inactive { + IN struct vnode *vp; +}; %% reclaim vp E E E %! reclaim post vop_reclaim_post Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -753,6 +753,7 @@ int vop_stdgetwritemount(struct vop_getwritemount_args *); int vop_stdgetpages(struct vop_getpages_args *); int vop_stdinactive(struct vop_inactive_args *); +int vop_stdneed_inactive(struct vop_need_inactive_args *); int vop_stdislocked(struct vop_islocked_args *); int vop_stdkqfilter(struct vop_kqfilter_args *); int vop_stdlock(struct vop_lock1_args *); @@ -813,12 +814,16 @@ void vop_lock_post(void *a, int rc); void vop_unlock_pre(void *a); void vop_unlock_post(void *a, int rc); +void vop_need_inactive_pre(void *a); +void vop_need_inactive_post(void *a, int rc); #else #define vop_strategy_pre(x) do { } while (0) #define vop_lock_pre(x) do { } while (0) #define vop_lock_post(x, y) do { } while (0) #define vop_unlock_pre(x) do { } while (0) #define vop_unlock_post(x, y) do { } while (0) +#define vop_need_inactive_pre(x) do { } while (0) +#define vop_need_inactive_post(x, y) do { } while (0) #endif void vop_rename_fail(struct vop_rename_args *ap);