From 30d49d536b0f274cdb8e198602bd1a76ea0a78ed Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Thu, 1 Aug 2019 14:40:37 +0000 Subject: [PATCH] Try to decrease the number of bugs in unionfs after the VV_TEXT flag removal. - Provide unionfs_add_writecount() which passes the writecount to the lower or upper vnode as appropriate. - In unionfs VOP_RECLAIM() implementation, annulate unionfs writecounts from upper or lower vnode. It is not clear that it is always correct to remove the all references from either lower or upper vnode, but we currently do not track which vnode get how many refs anyway. Reported and tested by: t_uemura@macome.co.jp MFC after: 1 week Sponsored by: The FreeBSD Foundation --- sys/fs/unionfs/union_subr.c | 7 +++++++ sys/fs/unionfs/union_vnops.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index f3b5e4840050..faa95ea49041 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -349,6 +349,13 @@ unionfs_noderem(struct vnode *vp, struct thread *td) vp->v_vnlock = &(vp->v_lock); vp->v_data = NULL; vp->v_object = NULL; + if (vp->v_writecount > 0) { + if (uvp != NULL) + VOP_ADD_WRITECOUNT(uvp, -vp->v_writecount); + else if (lvp != NULL) + VOP_ADD_WRITECOUNT(lvp, -vp->v_writecount); + } else if (vp->v_writecount < 0) + vp->v_writecount = 0; VI_UNLOCK(vp); if (lvp != NULLVP) diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index b4082771d1c4..ff77e5068314 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -2511,6 +2511,33 @@ unionfs_vptofh(struct vop_vptofh_args *ap) return (EOPNOTSUPP); } +static int +unionfs_add_writecount(struct vop_add_writecount_args *ap) +{ + struct vnode *tvp, *vp; + struct unionfs_node *unp; + int error; + + vp = ap->a_vp; + unp = VTOUNIONFS(vp); + tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp; + VI_LOCK(vp); + /* text refs are bypassed to lowervp */ + VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount")); + VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp, + ("wrong writecount inc %d", ap->a_inc)); + if (tvp != NULL) + error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc); + else if (vp->v_writecount < 0) + error = ETXTBSY; + else + error = 0; + if (error == 0) + vp->v_writecount += ap->a_inc; + VI_UNLOCK(vp); + return (error); +} + struct vop_vector unionfs_vnodeops = { .vop_default = &default_vnodeops, @@ -2559,4 +2586,5 @@ struct vop_vector unionfs_vnodeops = { .vop_whiteout = unionfs_whiteout, .vop_write = unionfs_write, .vop_vptofh = unionfs_vptofh, + .vop_add_writecount = unionfs_add_writecount, };