summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/mount_unionfs/mount_unionfs.84
-rw-r--r--sys/fs/unionfs/union.h7
-rw-r--r--sys/fs/unionfs/union_vfsops.c17
-rw-r--r--sys/fs/unionfs/union_vnops.c10
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)
OpenPOWER on IntegriCloud