mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 23:52:08 +02:00
Merge patch series "btrfs: stop duplicating VFS code for subvolume/snapshot dentry"
Filipe Manana <fdmanana@suse.com> says: Currently btrfs has copies of two unexported functions from fs/namei.c used in the snapshot/subvolume creation and deletion. This patchset exports those functions and makes btrfs use them, to avoid duplication and the burden of keeping the copies up to date. * patches from https://patch.msgid.link/cover.1768307858.git.fdmanana@suse.com: btrfs: use may_create_dentry() in btrfs_mksubvol() btrfs: use may_delete_dentry() in btrfs_ioctl_snap_destroy() fs: export may_create() as may_create_dentry() fs: export may_delete() as may_delete_dentry() Link: https://patch.msgid.link/cover.1768307858.git.fdmanana@suse.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
commit
f97f020075
|
|
@ -815,75 +815,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
|||
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)
|
||||
{
|
||||
if (d_really_is_positive(child))
|
||||
return -EEXIST;
|
||||
if (IS_DEADDIR(dir))
|
||||
return -ENOENT;
|
||||
if (!fsuidgid_has_mapping(dir->i_sb, idmap))
|
||||
return -EOVERFLOW;
|
||||
return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new subvolume below @parent. This is largely modeled after
|
||||
* sys_mkdirat and vfs_mkdir, but we only do a single component lookup
|
||||
|
|
@ -905,7 +836,7 @@ static noinline int btrfs_mksubvol(struct dentry *parent,
|
|||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
ret = btrfs_may_create(idmap, dir, dentry);
|
||||
ret = may_create_dentry(idmap, dir, dentry);
|
||||
if (ret)
|
||||
goto out_dput;
|
||||
|
||||
|
|
@ -2420,7 +2351,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;
|
||||
|
||||
|
|
|
|||
36
fs/namei.c
36
fs/namei.c
|
|
@ -3604,7 +3604,7 @@ EXPORT_SYMBOL(__check_sticky);
|
|||
* 11. We don't allow removal of NFS sillyrenamed files; it's handled by
|
||||
* nfs_async_unlink().
|
||||
*/
|
||||
static int may_delete(struct mnt_idmap *idmap, struct inode *dir,
|
||||
int may_delete_dentry(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *victim, bool isdir)
|
||||
{
|
||||
struct inode *inode = d_backing_inode(victim);
|
||||
|
|
@ -3646,6 +3646,7 @@ static int may_delete(struct mnt_idmap *idmap, struct inode *dir,
|
|||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(may_delete_dentry);
|
||||
|
||||
/* Check whether we can create an object with dentry child in directory
|
||||
* dir.
|
||||
|
|
@ -3656,8 +3657,8 @@ static int may_delete(struct mnt_idmap *idmap, struct inode *dir,
|
|||
* 4. We should have write and exec permissions on dir
|
||||
* 5. We can't do it if dir is immutable (done in permission())
|
||||
*/
|
||||
static inline int may_create(struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *child)
|
||||
int may_create_dentry(struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *child)
|
||||
{
|
||||
audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
|
||||
if (child->d_inode)
|
||||
|
|
@ -3669,6 +3670,7 @@ static inline int may_create(struct mnt_idmap *idmap,
|
|||
|
||||
return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
EXPORT_SYMBOL(may_create_dentry);
|
||||
|
||||
// p1 != p2, both are on the same filesystem, ->s_vfs_rename_mutex is held
|
||||
static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
|
||||
|
|
@ -4115,7 +4117,7 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode,
|
|||
struct inode *dir = d_inode(dentry->d_parent);
|
||||
int error;
|
||||
|
||||
error = may_create(idmap, dir, dentry);
|
||||
error = may_create_dentry(idmap, dir, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -4141,7 +4143,7 @@ int vfs_mkobj(struct dentry *dentry, umode_t mode,
|
|||
void *arg)
|
||||
{
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
int error = may_create(&nop_mnt_idmap, dir, dentry);
|
||||
int error = may_create_dentry(&nop_mnt_idmap, dir, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -4960,7 +4962,7 @@ int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
|||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
|
||||
int error = may_create(idmap, dir, dentry);
|
||||
int error = may_create_dentry(idmap, dir, dentry);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -5106,7 +5108,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
|||
unsigned max_links = dir->i_sb->s_max_links;
|
||||
struct dentry *de;
|
||||
|
||||
error = may_create(idmap, dir, dentry);
|
||||
error = may_create_dentry(idmap, dir, dentry);
|
||||
if (error)
|
||||
goto err;
|
||||
|
||||
|
|
@ -5209,7 +5211,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|
|||
int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, struct delegated_inode *delegated_inode)
|
||||
{
|
||||
int error = may_delete(idmap, dir, dentry, 1);
|
||||
int error = may_delete_dentry(idmap, dir, dentry, true);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -5344,7 +5346,7 @@ int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
struct dentry *dentry, struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *target = dentry->d_inode;
|
||||
int error = may_delete(idmap, dir, dentry, 0);
|
||||
int error = may_delete_dentry(idmap, dir, dentry, false);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -5496,7 +5498,7 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
{
|
||||
int error;
|
||||
|
||||
error = may_create(idmap, dir, dentry);
|
||||
error = may_create_dentry(idmap, dir, dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -5604,7 +5606,7 @@ int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
|
|||
if (!inode)
|
||||
return -ENOENT;
|
||||
|
||||
error = may_create(idmap, dir, new_dentry);
|
||||
error = may_create_dentry(idmap, dir, new_dentry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -5816,21 +5818,21 @@ int vfs_rename(struct renamedata *rd)
|
|||
if (source == target)
|
||||
return 0;
|
||||
|
||||
error = may_delete(rd->mnt_idmap, old_dir, old_dentry, is_dir);
|
||||
error = may_delete_dentry(rd->mnt_idmap, old_dir, old_dentry, is_dir);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!target) {
|
||||
error = may_create(rd->mnt_idmap, new_dir, new_dentry);
|
||||
error = may_create_dentry(rd->mnt_idmap, new_dir, new_dentry);
|
||||
} else {
|
||||
new_is_dir = d_is_dir(new_dentry);
|
||||
|
||||
if (!(flags & RENAME_EXCHANGE))
|
||||
error = may_delete(rd->mnt_idmap, new_dir,
|
||||
new_dentry, is_dir);
|
||||
error = may_delete_dentry(rd->mnt_idmap, new_dir,
|
||||
new_dentry, is_dir);
|
||||
else
|
||||
error = may_delete(rd->mnt_idmap, new_dir,
|
||||
new_dentry, new_is_dir);
|
||||
error = may_delete_dentry(rd->mnt_idmap, new_dir,
|
||||
new_dentry, new_is_dir);
|
||||
}
|
||||
if (error)
|
||||
return error;
|
||||
|
|
|
|||
|
|
@ -2657,6 +2657,11 @@ static inline int path_permission(const struct path *path, int mask)
|
|||
int __check_sticky(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct inode *inode);
|
||||
|
||||
int may_delete_dentry(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *victim, bool isdir);
|
||||
int may_create_dentry(struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *child);
|
||||
|
||||
static inline bool execute_ok(struct inode *inode)
|
||||
{
|
||||
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user