Index: sys/fs/nullfs/null_vnops.c =================================================================== --- sys/fs/nullfs/null_vnops.c +++ sys/fs/nullfs/null_vnops.c @@ -924,6 +924,7 @@ .vop_getattr = null_getattr, .vop_getwritemount = null_getwritemount, .vop_inactive = null_inactive, + .vop_vputx = vop_stdvputx, .vop_islocked = vop_stdislocked, .vop_lock1 = null_lock, .vop_lookup = null_lookup, Index: sys/fs/tmpfs/tmpfs_vnops.c =================================================================== --- sys/fs/tmpfs/tmpfs_vnops.c +++ sys/fs/tmpfs/tmpfs_vnops.c @@ -1283,6 +1283,32 @@ return (0); } +static int +tmpfs_vputx(struct vop_vputx_args *ap) +{ + struct vnode *vp; + struct tmpfs_node *node; + struct vm_object *obj; + int func; + + vp = ap->a_vp; + func = ap->a_type; + node = VP_TO_TMPFS_NODE(vp); + if (node->tn_links == 0) + goto need_vput; + if (vp->v_type == VREG) { + obj = vp->v_object; + if ((obj->flags & OBJ_TMPFS_DIRTY) != 0) + goto need_vput; + } + if (func == VPUTX_VPUT) + VOP_UNLOCK(vp, 0); + vdropl(vp); + return (0); +need_vput: + return (vop_stdvputx(ap)); +} + int tmpfs_reclaim(struct vop_reclaim_args *v) { @@ -1584,6 +1610,7 @@ .vop_readdir = tmpfs_readdir, .vop_readlink = tmpfs_readlink, .vop_inactive = tmpfs_inactive, + .vop_vputx = tmpfs_vputx, .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_vputx = vop_stdvputx, .vop_ioctl = vop_stdioctl, .vop_kqfilter = vop_stdkqfilter, .vop_islocked = vop_stdislocked, @@ -1379,3 +1380,49 @@ sigallowstop(prev_stops); return (rc); } + +int +vop_stdvputx(struct vop_vputx_args *ap) +{ + struct vnode *vp; + int func, error; + + vp = ap->a_vp; + func = ap->a_type; + error = 0; + + /* + * We must call VOP_INACTIVE with the node locked. Mark + * as VI_DOINGINACT to avoid recursion. + */ + vp->v_iflag |= VI_OWEINACT; + switch (func) { + case VPUTX_VRELE: + error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); + VI_LOCK(vp); + break; + case VPUTX_VPUT: + if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { + error = VOP_LOCK(vp, LK_UPGRADE | LK_INTERLOCK | + LK_NOWAIT); + VI_LOCK(vp); + } + break; + case VPUTX_VUNREF: + if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { + error = VOP_LOCK(vp, LK_TRYUPGRADE | LK_INTERLOCK); + VI_LOCK(vp); + } + break; + } + VNASSERT(vp->v_usecount == 0 || (vp->v_iflag & VI_OWEINACT) == 0, vp, + ("vnode with usecount and VI_OWEINACT set")); + if (error == 0) { + if (vp->v_iflag & VI_OWEINACT) + vinactive(vp, curthread); + if (func != VPUTX_VUNREF) + VOP_UNLOCK(vp, 0); + } + vdropl(vp); + return (0); +} Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -2829,10 +2829,6 @@ return (vp->v_usecount); } -#define VPUTX_VRELE 1 -#define VPUTX_VPUT 2 -#define VPUTX_VUNREF 3 - /* * Decrement the use and hold counts for a vnode. * @@ -2841,7 +2837,6 @@ static void vputx(struct vnode *vp, int func) { - int error; KASSERT(vp != NULL, ("vputx: null vp")); if (func == VPUTX_VUNREF) @@ -2879,8 +2874,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,39 +2881,7 @@ 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; - switch (func) { - case VPUTX_VRELE: - error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); - VI_LOCK(vp); - break; - case VPUTX_VPUT: - if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { - error = VOP_LOCK(vp, LK_UPGRADE | LK_INTERLOCK | - LK_NOWAIT); - VI_LOCK(vp); - } - break; - case VPUTX_VUNREF: - if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { - error = VOP_LOCK(vp, LK_TRYUPGRADE | LK_INTERLOCK); - VI_LOCK(vp); - } - break; - } - VNASSERT(vp->v_usecount == 0 || (vp->v_iflag & VI_OWEINACT) == 0, vp, - ("vnode with usecount and VI_OWEINACT set")); - if (error == 0) { - if (vp->v_iflag & VI_OWEINACT) - vinactive(vp, curthread); - if (func != VPUTX_VUNREF) - VOP_UNLOCK(vp, 0); - } - vdropl(vp); + VOP_VPUTX(vp, func); } /* Index: sys/kern/vnode_if.src =================================================================== --- sys/kern/vnode_if.src +++ sys/kern/vnode_if.src @@ -359,6 +359,14 @@ }; +%% vputx vp - - - + +vop_vputx { + IN struct vnode *vp; + IN int type; +}; + + %% reclaim vp E E E %! reclaim post vop_reclaim_post Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -58,6 +58,8 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD, VMARKER }; +enum vputop { VPUTX_VRELE, VPUTX_VPUT, VPUTX_VUNREF }; + /* * Each underlying filesystem allocates its own private area and hangs * it from v_data. If non-null, this area is freed in getnewvnode(). @@ -760,6 +762,7 @@ int vop_nopoll(struct vop_poll_args *); int vop_stdaccess(struct vop_access_args *ap); int vop_stdaccessx(struct vop_accessx_args *ap); +int vop_stdvputx(struct vop_vputx_args *); int vop_stdadvise(struct vop_advise_args *ap); int vop_stdadvlock(struct vop_advlock_args *ap); int vop_stdadvlockasync(struct vop_advlockasync_args *ap);