mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
vfs: make vfs_mknod break delegations on parent directory
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 pointer to vfs_mknod() and have the appropriate callers wait when there is an outstanding delegation. All other callers just set the pointer to NULL. 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-11-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
committed by
Christian Brauner
parent
c826229c6a
commit
e8960c1b2e
@@ -231,7 +231,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
err = vfs_mknod(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode,
|
||||
dev->devt);
|
||||
dev->devt, NULL);
|
||||
if (!err) {
|
||||
struct iattr newattrs;
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ ecryptfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
|
||||
if (!rc)
|
||||
rc = vfs_mknod(&nop_mnt_idmap, lower_dir,
|
||||
lower_dentry, mode, dev);
|
||||
lower_dentry, mode, dev, NULL);
|
||||
if (rc || d_really_is_negative(lower_dentry))
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
|
||||
|
||||
@@ -157,7 +157,7 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
|
||||
error = security_path_mknod(&path, dentry, mode, dev);
|
||||
if (!error)
|
||||
error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode, new_decode_dev(dev));
|
||||
dentry, mode, new_decode_dev(dev), NULL);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
23
fs/namei.c
23
fs/namei.c
@@ -4295,13 +4295,15 @@ inline struct dentry *start_creating_user_path(
|
||||
}
|
||||
EXPORT_SYMBOL(start_creating_user_path);
|
||||
|
||||
|
||||
/**
|
||||
* vfs_mknod - create device node or file
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
* @dir: inode of the parent directory
|
||||
* @dentry: dentry of the child device node
|
||||
* @mode: mode of the child device node
|
||||
* @dev: device number of device to create
|
||||
* @idmap: idmap of the mount the inode was found from
|
||||
* @dir: inode of the parent directory
|
||||
* @dentry: dentry of the child device node
|
||||
* @mode: mode of the child device node
|
||||
* @dev: device number of device to create
|
||||
* @delegated_inode: returns parent inode, if the inode is delegated.
|
||||
*
|
||||
* Create a device node or file.
|
||||
*
|
||||
@@ -4312,7 +4314,8 @@ EXPORT_SYMBOL(start_creating_user_path);
|
||||
* raw inode simply pass @nop_mnt_idmap.
|
||||
*/
|
||||
int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t dev)
|
||||
struct dentry *dentry, umode_t mode, dev_t dev,
|
||||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
|
||||
int error = may_create(idmap, dir, dentry);
|
||||
@@ -4336,6 +4339,10 @@ int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = try_break_deleg(dir, delegated_inode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = dir->i_op->mknod(idmap, dir, dentry, mode, dev);
|
||||
if (!error)
|
||||
fsnotify_create(dir, dentry);
|
||||
@@ -4393,11 +4400,11 @@ retry:
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
error = vfs_mknod(idmap, path.dentry->d_inode,
|
||||
dentry, mode, new_decode_dev(dev));
|
||||
dentry, mode, new_decode_dev(dev), &di);
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
error = vfs_mknod(idmap, path.dentry->d_inode,
|
||||
dentry, mode, 0);
|
||||
dentry, mode, 0, &di);
|
||||
break;
|
||||
}
|
||||
out2:
|
||||
|
||||
@@ -1573,7 +1573,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
host_err = vfs_mknod(&nop_mnt_idmap, dirp, dchild,
|
||||
iap->ia_mode, rdev);
|
||||
iap->ia_mode, rdev, NULL);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
|
||||
|
||||
@@ -257,7 +257,7 @@ static inline int ovl_do_mknod(struct ovl_fs *ofs,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, dev_t dev)
|
||||
{
|
||||
int err = vfs_mknod(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, dev);
|
||||
int err = vfs_mknod(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, dev, NULL);
|
||||
|
||||
pr_debug("mknod(%pd2, 0%o, 0%o) = %i\n", dentry, mode, dev, err);
|
||||
return err;
|
||||
|
||||
@@ -2116,7 +2116,7 @@ int vfs_create(struct mnt_idmap *, struct dentry *, umode_t,
|
||||
struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, umode_t, struct delegated_inode *);
|
||||
int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||
umode_t, dev_t);
|
||||
umode_t, dev_t, struct delegated_inode *);
|
||||
int vfs_symlink(struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, const char *);
|
||||
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
||||
@@ -2152,7 +2152,7 @@ static inline int vfs_whiteout(struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
return vfs_mknod(idmap, dir, dentry, S_IFCHR | WHITEOUT_MODE,
|
||||
WHITEOUT_DEV);
|
||||
WHITEOUT_DEV, NULL);
|
||||
}
|
||||
|
||||
struct file *kernel_tmpfile_open(struct mnt_idmap *idmap,
|
||||
|
||||
@@ -1399,7 +1399,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
|
||||
idmap = mnt_idmap(parent.mnt);
|
||||
err = security_path_mknod(&parent, dentry, mode, 0);
|
||||
if (!err)
|
||||
err = vfs_mknod(idmap, d_inode(parent.dentry), dentry, mode, 0);
|
||||
err = vfs_mknod(idmap, d_inode(parent.dentry), dentry, mode, 0, NULL);
|
||||
if (err)
|
||||
goto out_path;
|
||||
err = mutex_lock_interruptible(&u->bindlock);
|
||||
|
||||
Reference in New Issue
Block a user