diff options
-rw-r--r-- | sbin/mount_unionfs/mount_unionfs.8 | 4 | ||||
-rw-r--r-- | sys/fs/unionfs/union.h | 7 | ||||
-rw-r--r-- | sys/fs/unionfs/union_vfsops.c | 17 | ||||
-rw-r--r-- | sys/fs/unionfs/union_vnops.c | 10 |
4 files changed, 36 insertions, 2 deletions
diff --git a/sbin/mount_unionfs/mount_unionfs.8 b/sbin/mount_unionfs/mount_unionfs.8 index d574491..4f661b8 100644 --- a/sbin/mount_unionfs/mount_unionfs.8 +++ b/sbin/mount_unionfs/mount_unionfs.8 @@ -98,6 +98,10 @@ For behavior of the mode, see .Sx MASQUERADE MODE below. +.It Sm Cm whiteout No = Cm always | whenneeded Sm +Specifies whether whiteouts should always be made in the upper layer +when removing a file or directory or only when it already exists in the +lower layer. .It Cm udir Ns = Ns Ar mode Specifies directory mode bits in octal for .Cm masquerade diff --git a/sys/fs/unionfs/union.h b/sys/fs/unionfs/union.h index 302b384..e97936d 100644 --- a/sys/fs/unionfs/union.h +++ b/sys/fs/unionfs/union.h @@ -45,11 +45,18 @@ typedef enum _unionfs_copymode { UNIONFS_MASQUERADE } unionfs_copymode; +/* whiteout policy of upper layer */ +typedef enum _unionfs_whitemode { + UNIONFS_WHITE_ALWAYS = 0, + UNIONFS_WHITE_WHENNEEDED +} unionfs_whitemode; + struct unionfs_mount { struct vnode *um_lowervp; /* VREFed once */ struct vnode *um_uppervp; /* VREFed once */ struct vnode *um_rootvp; /* ROOT vnode */ unionfs_copymode um_copymode; + unionfs_whitemode um_whitemode; uid_t um_uid; gid_t um_gid; u_short um_udir; diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c index ea09895..3125f59 100644 --- a/sys/fs/unionfs/union_vfsops.c +++ b/sys/fs/unionfs/union_vfsops.c @@ -123,6 +123,7 @@ unionfs_domount(struct mount *mp, struct thread *td) u_short udir; u_short ufile; unionfs_copymode copymode; + unionfs_whitemode whitemode; struct componentname fakecn; struct nameidata nd, *ndp; struct vattr va; @@ -136,6 +137,7 @@ unionfs_domount(struct mount *mp, struct thread *td) udir = 0; ufile = 0; copymode = UNIONFS_TRANSPARENT; /* default */ + whitemode = UNIONFS_WHITE_ALWAYS; ndp = &nd; if (mp->mnt_flag & MNT_ROOTFS) { @@ -237,6 +239,20 @@ unionfs_domount(struct mount *mp, struct thread *td) return (EINVAL); } } + if (vfs_getopt(mp->mnt_optnew, "whiteout", (void **)&tmp, + NULL) == 0) { + if (tmp == NULL) { + vfs_mount_error(mp, "Invalid whiteout mode"); + return (EINVAL); + } else if (strcasecmp(tmp, "always") == 0) + whitemode = UNIONFS_WHITE_ALWAYS; + else if (strcasecmp(tmp, "whenneeded") == 0) + whitemode = UNIONFS_WHITE_WHENNEEDED; + else { + vfs_mount_error(mp, "Invalid whiteout mode"); + return (EINVAL); + } + } } /* If copymode is UNIONFS_TRADITIONAL, uid/gid is mounted user. */ if (copymode == UNIONFS_TRADITIONAL) { @@ -286,6 +302,7 @@ unionfs_domount(struct mount *mp, struct thread *td) ump->um_udir = udir; ump->um_ufile = ufile; ump->um_copymode = copymode; + ump->um_whitemode = whitemode; MNT_ILOCK(mp); if ((lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE) && diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index 0437fe2..7a0cb60 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -939,6 +939,7 @@ unionfs_remove(struct vop_remove_args *ap) int error; struct unionfs_node *dunp; struct unionfs_node *unp; + struct unionfs_mount *ump; struct vnode *udvp; struct vnode *uvp; struct vnode *lvp; @@ -960,7 +961,9 @@ unionfs_remove(struct vop_remove_args *ap) return (EROFS); if (uvp != NULLVP) { - cnp->cn_flags |= DOWHITEOUT; + ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); + if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) + cnp->cn_flags |= DOWHITEOUT; error = VOP_REMOVE(udvp, uvp, cnp); } else if (lvp != NULLVP) error = unionfs_mkwhiteout(udvp, cnp, td, unp->un_path); @@ -1290,6 +1293,7 @@ unionfs_rmdir(struct vop_rmdir_args *ap) int error; struct unionfs_node *dunp; struct unionfs_node *unp; + struct unionfs_mount *ump; struct componentname *cnp; struct thread *td; struct vnode *udvp; @@ -1319,7 +1323,9 @@ unionfs_rmdir(struct vop_rmdir_args *ap) if (error != 0) return (error); } - cnp->cn_flags |= DOWHITEOUT; + ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); + if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) + cnp->cn_flags |= DOWHITEOUT; error = VOP_RMDIR(udvp, uvp, cnp); } else if (lvp != NULLVP) |