mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
vfs: allow rmdir to wait for delegation break on parent
In order to add directory delegation support, we need to break delegations on the parent whenever there is going to be a change in the directory. Add a delegated_inode struct to vfs_rmdir() and populate that pointer with the parent inode if it's non-NULL. Most existing in-kernel callers pass in a NULL pointer. Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-7-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
e12d203b8c
commit
4fa76319cd
|
|
@ -261,7 +261,7 @@ static int dev_rmdir(const char *name)
|
||||||
return PTR_ERR(dentry);
|
return PTR_ERR(dentry);
|
||||||
if (d_inode(dentry)->i_private == &thread)
|
if (d_inode(dentry)->i_private == &thread)
|
||||||
err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
|
err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
|
||||||
dentry);
|
dentry, NULL);
|
||||||
else
|
else
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||||
if (d_unhashed(lower_dentry))
|
if (d_unhashed(lower_dentry))
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
else
|
else
|
||||||
rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
|
rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
|
||||||
}
|
}
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
clear_nlink(d_inode(dentry));
|
clear_nlink(d_inode(dentry));
|
||||||
|
|
|
||||||
22
fs/namei.c
22
fs/namei.c
|
|
@ -4522,9 +4522,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vfs_rmdir - remove directory
|
* vfs_rmdir - remove directory
|
||||||
* @idmap: idmap of the mount the inode was found from
|
* @idmap: idmap of the mount the inode was found from
|
||||||
* @dir: inode of the parent directory
|
* @dir: inode of the parent directory
|
||||||
* @dentry: dentry of the child directory
|
* @dentry: dentry of the child directory
|
||||||
|
* @delegated_inode: returns parent inode, if it's delegated.
|
||||||
*
|
*
|
||||||
* Remove a directory.
|
* Remove a directory.
|
||||||
*
|
*
|
||||||
|
|
@ -4535,7 +4536,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
|
||||||
* raw inode simply pass @nop_mnt_idmap.
|
* raw inode simply pass @nop_mnt_idmap.
|
||||||
*/
|
*/
|
||||||
int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
|
int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
struct dentry *dentry)
|
struct dentry *dentry, struct delegated_inode *delegated_inode)
|
||||||
{
|
{
|
||||||
int error = may_delete(idmap, dir, dentry, 1);
|
int error = may_delete(idmap, dir, dentry, 1);
|
||||||
|
|
||||||
|
|
@ -4557,6 +4558,10 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
error = try_break_deleg(dir, delegated_inode);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
error = dir->i_op->rmdir(dir, dentry);
|
error = dir->i_op->rmdir(dir, dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -4583,6 +4588,7 @@ int do_rmdir(int dfd, struct filename *name)
|
||||||
struct qstr last;
|
struct qstr last;
|
||||||
int type;
|
int type;
|
||||||
unsigned int lookup_flags = 0;
|
unsigned int lookup_flags = 0;
|
||||||
|
struct delegated_inode delegated_inode = { };
|
||||||
retry:
|
retry:
|
||||||
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
|
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
@ -4612,7 +4618,8 @@ int do_rmdir(int dfd, struct filename *name)
|
||||||
error = security_path_rmdir(&path, dentry);
|
error = security_path_rmdir(&path, dentry);
|
||||||
if (error)
|
if (error)
|
||||||
goto exit4;
|
goto exit4;
|
||||||
error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry);
|
error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||||
|
dentry, &delegated_inode);
|
||||||
exit4:
|
exit4:
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
exit3:
|
exit3:
|
||||||
|
|
@ -4620,6 +4627,11 @@ int do_rmdir(int dfd, struct filename *name)
|
||||||
mnt_drop_write(path.mnt);
|
mnt_drop_write(path.mnt);
|
||||||
exit2:
|
exit2:
|
||||||
path_put(&path);
|
path_put(&path);
|
||||||
|
if (is_delegated(&delegated_inode)) {
|
||||||
|
error = break_deleg_wait(&delegated_inode);
|
||||||
|
if (!error)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
if (retry_estale(error, lookup_flags)) {
|
if (retry_estale(error, lookup_flags)) {
|
||||||
lookup_flags |= LOOKUP_REVAL;
|
lookup_flags |= LOOKUP_REVAL;
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ nfsd4_unlink_clid_dir(char *name, struct nfsd_net *nn)
|
||||||
status = -ENOENT;
|
status = -ENOENT;
|
||||||
if (d_really_is_negative(dentry))
|
if (d_really_is_negative(dentry))
|
||||||
goto out;
|
goto out;
|
||||||
status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry);
|
status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry, NULL);
|
||||||
out:
|
out:
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
|
@ -427,7 +427,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
|
||||||
if (nfs4_has_reclaimed_state(name, nn))
|
if (nfs4_has_reclaimed_state(name, nn))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child);
|
status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child, NULL);
|
||||||
if (status)
|
if (status)
|
||||||
printk("failed to remove client recovery directory %pd\n",
|
printk("failed to remove client recovery directory %pd\n",
|
||||||
child);
|
child);
|
||||||
|
|
|
||||||
|
|
@ -2108,7 +2108,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry);
|
host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry, NULL);
|
||||||
}
|
}
|
||||||
fh_fill_post_attrs(fhp);
|
fh_fill_post_attrs(fhp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ static inline int ovl_do_notify_change(struct ovl_fs *ofs,
|
||||||
static inline int ovl_do_rmdir(struct ovl_fs *ofs,
|
static inline int ovl_do_rmdir(struct ovl_fs *ofs,
|
||||||
struct inode *dir, struct dentry *dentry)
|
struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry);
|
int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry, NULL);
|
||||||
|
|
||||||
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
|
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -609,7 +609,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
|
||||||
|
|
||||||
idmap = mnt_idmap(path->mnt);
|
idmap = mnt_idmap(path->mnt);
|
||||||
if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
|
if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
|
||||||
err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
|
err = vfs_rmdir(idmap, d_inode(parent), path->dentry, NULL);
|
||||||
if (err && err != -ENOTEMPTY)
|
if (err && err != -ENOTEMPTY)
|
||||||
ksmbd_debug(VFS, "rmdir failed, err %d\n", err);
|
ksmbd_debug(VFS, "rmdir failed, err %d\n", err);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1090,7 +1090,7 @@ int ksmbd_vfs_unlink(struct file *filp)
|
||||||
dget(dentry);
|
dget(dentry);
|
||||||
|
|
||||||
if (S_ISDIR(d_inode(dentry)->i_mode))
|
if (S_ISDIR(d_inode(dentry)->i_mode))
|
||||||
err = vfs_rmdir(idmap, d_inode(dir), dentry);
|
err = vfs_rmdir(idmap, d_inode(dir), dentry, NULL);
|
||||||
else
|
else
|
||||||
err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);
|
err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2121,7 +2121,8 @@ int vfs_symlink(struct mnt_idmap *, struct inode *,
|
||||||
struct dentry *, const char *);
|
struct dentry *, const char *);
|
||||||
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
||||||
struct dentry *, struct delegated_inode *);
|
struct dentry *, struct delegated_inode *);
|
||||||
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *);
|
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||||
|
struct delegated_inode *);
|
||||||
int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
|
int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||||
struct delegated_inode *);
|
struct delegated_inode *);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user