The branch main has been updated by jah:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2ed053cde55869d3440377d479deb00f42ba1cf8

commit 2ed053cde55869d3440377d479deb00f42ba1cf8
Author:     Jason A. Harmening <j...@freebsd.org>
AuthorDate: 2024-08-06 04:12:36 +0000
Commit:     Jason A. Harmening <j...@freebsd.org>
CommitDate: 2024-09-08 23:34:14 +0000

    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
---
 sys/fs/unionfs/union_vnops.c | 2 +-
 sys/sys/namei.h              | 2 +-
 sys/ufs/ufs/ufs_extern.h     | 2 +-
 sys/ufs/ufs/ufs_lookup.c     | 6 ++++--
 sys/ufs/ufs/ufs_vnops.c      | 6 ++++--
 5 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 3f39352ea5c0..e1048e4ba7ab 100644
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -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);
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index 2ea4f502e8fd..1416ff983f32 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -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 / */
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index b1d55ed1f180..ccd9046a5fa8 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -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 *,
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 2d6c79970c96..eaf37c58756b 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -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)
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index c62583afaab6..0bca40199071 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1625,7 +1625,8 @@ relock:
                 */
                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;
        }

Reply via email to