Page MenuHomeFreeBSD

patch_dropwhiteout

Authored By
jah
Aug 2 2024, 2:07 AM
Size
5 KB
Referenced Files
None
Subscribers
None

patch_dropwhiteout

diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index 8436dc3bc48c..c492f003c97d 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -1078,7 +1078,9 @@ tmpfs_rename(struct vop_rename_args *v)
}
if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
- if (tnode->tn_size > tnode->tn_dir.tn_wht_size) {
+ if ((tnode->tn_size != 0 &&
+ (tcnp->cn_flags & DROPWHITEOUT) == 0) ||
+ tnode->tn_size > tnode->tn_dir.tn_wht_size) {
error = ENOTEMPTY;
goto out_locked;
}
@@ -1312,6 +1314,7 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
{
struct vnode *dvp = v->a_dvp;
struct vnode *vp = v->a_vp;
+ struct componentname *cnp = v->a_cnp;
int error;
struct tmpfs_dirent *de;
@@ -1327,7 +1330,9 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
* Directories with more than two non-whiteout entries ('.' and '..')
* cannot be removed.
*/
- if (node->tn_size > node->tn_dir.tn_wht_size) {
+ if ((node->tn_size != 0 &&
+ (cnp->cn_flags & DROPWHITEOUT) == 0) ||
+ node->tn_size > node->tn_dir.tn_wht_size) {
error = ENOTEMPTY;
goto out;
}
@@ -1344,10 +1349,10 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
/* Get the directory entry associated with node (vp). This was
* filled by tmpfs_lookup while looking up the entry. */
- de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
+ de = tmpfs_dir_lookup(dnode, node, cnp);
MPASS(TMPFS_DIRENT_MATCHES(de,
- v->a_cnp->cn_nameptr,
- v->a_cnp->cn_namelen));
+ cnp->cn_nameptr,
+ cnp->cn_namelen));
/* Check flags to see if we are allowed to remove the directory. */
if ((dnode->tn_flags & APPEND) != 0 ||
@@ -1362,8 +1367,8 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
if (node->tn_size > 0)
tmpfs_dir_clear(vp);
- if (v->a_cnp->cn_flags & DOWHITEOUT)
- tmpfs_dir_whiteout_add(dvp, v->a_cnp);
+ if (cnp->cn_flags & DOWHITEOUT)
+ tmpfs_dir_whiteout_add(dvp, cnp);
/* No vnode should be allocated for this entry from this point */
TMPFS_NODE_LOCK(node);
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
index 3f39352ea5c0..60baa4aeb6b9 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 | DROPWHITEOUT);
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..5745e13ebab5 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 DROPWHITEOUT 0x00000800 /* discard whiteouts on removing otherwise-empty dir */
#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..a09b893a4d8d 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -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 & DROPWHITEOUT) != 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 & DROPWHITEOUT) != 0)) {
error = ENOTEMPTY;
goto out;
}

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10703587
Default Alt Text
patch_dropwhiteout (5 KB)

Event Timeline