mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
vfs: allow mkdir 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 new delegated_inode parameter to vfs_mkdir. All of the existing callers set that to NULL for now, except for do_mkdirat which will properly block until the lease is gone. 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-6-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
committed by
Christian Brauner
parent
b46ebf9a76
commit
e12d203b8c
@@ -180,7 +180,7 @@ static int dev_mkdir(const char *name, umode_t mode)
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
|
||||
dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode, NULL);
|
||||
if (!IS_ERR(dentry))
|
||||
/* mark as kernel-created inode */
|
||||
d_inode(dentry)->i_private = &thread;
|
||||
|
||||
@@ -130,7 +130,7 @@ retry:
|
||||
goto mkdir_error;
|
||||
ret = cachefiles_inject_write_error();
|
||||
if (ret == 0)
|
||||
subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700);
|
||||
subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700, NULL);
|
||||
else
|
||||
subdir = ERR_PTR(ret);
|
||||
if (IS_ERR(subdir)) {
|
||||
|
||||
@@ -508,7 +508,7 @@ static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
goto out;
|
||||
|
||||
lower_dentry = vfs_mkdir(&nop_mnt_idmap, lower_dir,
|
||||
lower_dentry, mode);
|
||||
lower_dentry, mode, NULL);
|
||||
rc = PTR_ERR(lower_dentry);
|
||||
if (IS_ERR(lower_dentry))
|
||||
goto out;
|
||||
|
||||
@@ -233,7 +233,7 @@ int __init init_mkdir(const char *pathname, umode_t mode)
|
||||
error = security_path_mkdir(&path, dentry, mode);
|
||||
if (!error) {
|
||||
dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode);
|
||||
dentry, mode, NULL);
|
||||
if (IS_ERR(dentry))
|
||||
error = PTR_ERR(dentry);
|
||||
}
|
||||
|
||||
24
fs/namei.c
24
fs/namei.c
@@ -4407,10 +4407,11 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
|
||||
|
||||
/**
|
||||
* vfs_mkdir - create directory returning correct dentry if possible
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
* @dir: inode of the parent directory
|
||||
* @dentry: dentry of the child directory
|
||||
* @mode: mode of the child directory
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
* @dir: inode of the parent directory
|
||||
* @dentry: dentry of the child directory
|
||||
* @mode: mode of the child directory
|
||||
* @delegated_inode: returns parent inode, if the inode is delegated.
|
||||
*
|
||||
* Create a directory.
|
||||
*
|
||||
@@ -4427,7 +4428,8 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
|
||||
* In case of an error the dentry is dput() and an ERR_PTR() is returned.
|
||||
*/
|
||||
struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
struct dentry *dentry, umode_t mode,
|
||||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
int error;
|
||||
unsigned max_links = dir->i_sb->s_max_links;
|
||||
@@ -4450,6 +4452,10 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
if (max_links && dir->i_nlink >= max_links)
|
||||
goto err;
|
||||
|
||||
error = try_break_deleg(dir, delegated_inode);
|
||||
if (error)
|
||||
goto err;
|
||||
|
||||
de = dir->i_op->mkdir(idmap, dir, dentry, mode);
|
||||
error = PTR_ERR(de);
|
||||
if (IS_ERR(de))
|
||||
@@ -4473,6 +4479,7 @@ int do_mkdirat(int dfd, struct filename *name, umode_t mode)
|
||||
struct path path;
|
||||
int error;
|
||||
unsigned int lookup_flags = LOOKUP_DIRECTORY;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
|
||||
retry:
|
||||
dentry = filename_create(dfd, name, &path, lookup_flags);
|
||||
@@ -4484,11 +4491,16 @@ retry:
|
||||
mode_strip_umask(path.dentry->d_inode, mode));
|
||||
if (!error) {
|
||||
dentry = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode);
|
||||
dentry, mode, &delegated_inode);
|
||||
if (IS_ERR(dentry))
|
||||
error = PTR_ERR(dentry);
|
||||
}
|
||||
end_creating_path(&path, dentry);
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry;
|
||||
}
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
|
||||
@@ -213,7 +213,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
|
||||
* as well be forgiving and just succeed silently.
|
||||
*/
|
||||
goto out_put;
|
||||
dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU);
|
||||
dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, 0700, NULL);
|
||||
if (IS_ERR(dentry))
|
||||
status = PTR_ERR(dentry);
|
||||
out_put:
|
||||
|
||||
@@ -1558,7 +1558,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
nfsd_check_ignore_resizing(iap);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
dchild = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode);
|
||||
dchild = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode, NULL);
|
||||
if (IS_ERR(dchild)) {
|
||||
host_err = PTR_ERR(dchild);
|
||||
} else if (d_is_negative(dchild)) {
|
||||
|
||||
@@ -248,7 +248,7 @@ static inline struct dentry *ovl_do_mkdir(struct ovl_fs *ofs,
|
||||
{
|
||||
struct dentry *ret;
|
||||
|
||||
ret = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode);
|
||||
ret = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, NULL);
|
||||
pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, PTR_ERR_OR_ZERO(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
idmap = mnt_idmap(path.mnt);
|
||||
mode |= S_IFDIR;
|
||||
d = dentry;
|
||||
dentry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
|
||||
dentry = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode, NULL);
|
||||
if (IS_ERR(dentry))
|
||||
err = PTR_ERR(dentry);
|
||||
else if (d_is_negative(dentry))
|
||||
|
||||
@@ -167,7 +167,7 @@ xrep_orphanage_create(
|
||||
*/
|
||||
if (d_really_is_negative(orphanage_dentry)) {
|
||||
orphanage_dentry = vfs_mkdir(&nop_mnt_idmap, root_inode,
|
||||
orphanage_dentry, 0750);
|
||||
orphanage_dentry, 0750, NULL);
|
||||
error = PTR_ERR(orphanage_dentry);
|
||||
if (IS_ERR(orphanage_dentry))
|
||||
goto out_unlock_root;
|
||||
|
||||
@@ -2114,7 +2114,7 @@ bool inode_owner_or_capable(struct mnt_idmap *idmap,
|
||||
int vfs_create(struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, umode_t, bool);
|
||||
struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, umode_t);
|
||||
struct dentry *, umode_t, struct delegated_inode *);
|
||||
int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||
umode_t, dev_t);
|
||||
int vfs_symlink(struct mnt_idmap *, struct inode *,
|
||||
|
||||
Reference in New Issue
Block a user