1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-27 11:55:06 +00:00

vfs: Add IGNOREWHITEOUT flag and adopt it in UFS/unionfs

This flag is meant to request that the VOP implementation ignore
whiteout entries when processing directory contents.

Employ this flag (initially) in UFS when determining whether a directory
is empty for the purpose of deleting it or renaming another directory
over it.  The previous UFS behavior was to always ignore whiteouts and
to therefore always allow directories containing only whiteouts to be
deleted or overwritten.  This makes sense when the directory in question
is being accessed through a unionfs view in which the whiteouts produce
a unionfs directory that is logically empty, but it makes less sense
when directly operating against the UFS directory in which case silently
discarding the whiteouts may produce unexpected behavior in a current or
future unionfs view.  IGNOREWHITEOUT is therefore treated as opt-in and
only specified by unionfs_rmdir() when invoking VOP_RMDIR() against the
upper filesystem.  IGNOREWHITEOUT is not currently used for unionfs
rename operations, as the current implementation of unionfs_rename()
simply forbids renaming over any existing upper filesystem directory in
the first place.

Differential Revision:	https://reviews.freebsd.org/D45987
Reviewed by:		olce
Tested by:		pho
This commit is contained in:
Jason A. Harmening 2024-08-05 23:12:36 -05:00
parent 44328abfb7
commit 2ed053cde5
5 changed files with 11 additions and 7 deletions

View File

@ -1732,7 +1732,7 @@ unionfs_rmdir(struct vop_rmdir_args *ap)
}
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);

View File

@ -159,7 +159,7 @@ int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
*/
#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 / */

View File

@ -59,7 +59,7 @@ int ufs_bmap_seekdata(struct vnode *, off_t *);
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 *,

View File

@ -1298,7 +1298,8 @@ ufs_dirrewrite(struct inode *dp, struct inode *oip, ino_t newinum, int newtype,
* 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 @@ ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
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)

View File

@ -1625,7 +1625,8 @@ ufs_rename(
*/
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 @@ ufs_rmdir(
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;
}