diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -1732,7 +1732,7 @@ } ump = MOUNTTOUNIONFSMOUNT(ap->a_vp->v_mount); if (ump->um_whitemode == UNIONFS_WHITE_ALWAYS || lvp != NULLVP) - cnp->cn_flags |= DOWHITEOUT; + cnp->cn_flags |= (DOWHITEOUT | IGNOREWHITEOUT); int udvp_lkflags, uvp_lkflags; unionfs_forward_vop_start_pair(udvp, &udvp_lkflags, uvp, &uvp_lkflags); diff --git a/sys/sys/namei.h b/sys/sys/namei.h --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -159,7 +159,7 @@ */ #define RDONLY 0x00000200 /* lookup with read-only semantics */ #define ISRESTARTED 0x00000400 /* restarted namei */ -/* UNUSED 0x00000800 */ +#define IGNOREWHITEOUT 0x00000800 /* ignore whiteouts, e.g. when checking if a dir is empty */ #define ISWHITEOUT 0x00001000 /* found whiteout */ #define DOWHITEOUT 0x00002000 /* do whiteouts */ #define WILLBEDIR 0x00004000 /* new files will be dirs; allow trailing / */ diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h --- a/sys/ufs/ufs/ufs_extern.h +++ b/sys/ufs/ufs/ufs_extern.h @@ -59,7 +59,7 @@ int ufs_checkpath(ino_t, ino_t, struct inode *, struct ucred *, ino_t *); void ufs_dirbad(struct inode *, doff_t, char *); int ufs_dirbadentry(struct vnode *, struct direct *, int); -int ufs_dirempty(struct inode *, ino_t, struct ucred *); +int ufs_dirempty(struct inode *, ino_t, struct ucred *, int); int ufs_extread(struct vop_read_args *); int ufs_extwrite(struct vop_write_args *); void ufs_makedirentry(struct inode *, struct componentname *, diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -1298,7 +1298,8 @@ * NB: does not handle corrupted directories. */ int -ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred) +ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred, + int skipwhiteout) { doff_t off; struct dirtemplate dbuf; @@ -1321,7 +1322,8 @@ if (dp->d_reclen == 0) return (0); /* skip empty entries */ - if (dp->d_ino == 0 || dp->d_ino == UFS_WINO) + if (dp->d_ino == 0 || + (skipwhiteout != 0 && dp->d_ino == UFS_WINO)) continue; /* accept only "." and ".." */ # if (BYTE_ORDER == LITTLE_ENDIAN) diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -1625,7 +1625,8 @@ */ if ((tip->i_mode & IFMT) == IFDIR) { if ((tip->i_effnlink > 2) || - !ufs_dirempty(tip, tdp->i_number, tcnp->cn_cred)) { + !ufs_dirempty(tip, tdp->i_number, tcnp->cn_cred, + (tcnp->cn_flags & IGNOREWHITEOUT) != 0)) { error = ENOTEMPTY; goto bad; } @@ -2281,7 +2282,8 @@ error = EINVAL; goto out; } - if (!ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { + if (!ufs_dirempty(ip, dp->i_number, cnp->cn_cred, + (cnp->cn_flags & IGNOREWHITEOUT) != 0)) { error = ENOTEMPTY; goto out; }