summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2026-01-13 15:39:52 +0300
committerChristian Brauner <brauner@kernel.org>2026-01-14 19:17:47 +0300
commit5f84a1092dee7b2687804d71c0dd50edd6f2d32a (patch)
treeafaaede508da16b102b7657b3658d2a3a50a7f2b
parent26aab3a485d500cb89ef7340797982bd066f63a5 (diff)
downloadlinux-5f84a1092dee7b2687804d71c0dd50edd6f2d32a.tar.xz
btrfs: use may_delete_dentry() in btrfs_ioctl_snap_destroy()
There is no longer the need to use btrfs_may_delete(), which was a copy of the VFS private function may_delete(), since now that functionality is exported by the VFS as a function named may_delete_dentry(). In fact our local copy of may_delete() lacks an update that happened to that function which is point number 7 in that function's comment: "7. If the victim has an unknown uid or gid we can't change the inode." which corresponds to this code: /* Inode writeback is not safe when the uid or gid are invalid. */ if (!vfsuid_valid(i_uid_into_vfsuid(idmap, inode)) || !vfsgid_valid(i_gid_into_vfsgid(idmap, inode))) return -EOVERFLOW; As long as we keep a separate copy, duplicating code, we are also prone to updates to the VFS being missed in our local copy. So change btrfs_ioctl_snap_destroy() to use the VFS function and remove btrfs_may_delete(). Signed-off-by: Filipe Manana <fdmanana@suse.com> Link: https://patch.msgid.link/46b13dc5c957deb72a7f085916757a20878a8e73.1768307858.git.fdmanana@suse.com Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/btrfs/ioctl.c58
1 files changed, 1 insertions, 57 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index acb484546b1d..2d0b2619309d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -815,62 +815,6 @@ free_pending:
return ret;
}
-/* copy of may_delete in fs/namei.c()
- * Check whether we can remove a link victim from directory dir, check
- * whether the type of victim is right.
- * 1. We can't do it if dir is read-only (done in permission())
- * 2. We should have write and exec permissions on dir
- * 3. We can't remove anything from append-only dir
- * 4. We can't do anything with immutable dir (done in permission())
- * 5. If the sticky bit on dir is set we should either
- * a. be owner of dir, or
- * b. be owner of victim, or
- * c. have CAP_FOWNER capability
- * 6. If the victim is append-only or immutable we can't do anything with
- * links pointing to it.
- * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR.
- * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR.
- * 9. We can't remove a root or mountpoint.
- * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
- * nfs_async_unlink().
- */
-
-static int btrfs_may_delete(struct mnt_idmap *idmap,
- struct inode *dir, struct dentry *victim, int isdir)
-{
- int ret;
-
- if (d_really_is_negative(victim))
- return -ENOENT;
-
- /* The @victim is not inside @dir. */
- if (d_inode(victim->d_parent) != dir)
- return -EINVAL;
- audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
-
- ret = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
- if (ret)
- return ret;
- if (IS_APPEND(dir))
- return -EPERM;
- if (check_sticky(idmap, dir, d_inode(victim)) ||
- IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim)) ||
- IS_SWAPFILE(d_inode(victim)))
- return -EPERM;
- if (isdir) {
- if (!d_is_dir(victim))
- return -ENOTDIR;
- if (IS_ROOT(victim))
- return -EBUSY;
- } else if (d_is_dir(victim))
- return -EISDIR;
- if (IS_DEADDIR(dir))
- return -ENOENT;
- if (victim->d_flags & DCACHE_NFSFS_RENAMED)
- return -EBUSY;
- return 0;
-}
-
/* copy of may_create in fs/namei.c() */
static inline int btrfs_may_create(struct mnt_idmap *idmap,
struct inode *dir, const struct dentry *child)
@@ -2420,7 +2364,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
}
/* check if subvolume may be deleted by a user */
- ret = btrfs_may_delete(idmap, dir, dentry, 1);
+ ret = may_delete_dentry(idmap, dir, dentry, true);
if (ret)
goto out_end_removing;