Re: [PATCH v4 10/17] vfs: make vfs_create break delegations on parent directory
NeilBrown <[email protected]>
| Newsgroups | org.kernel.vger.ecryptfs,dev.linux.lists.netfs,org.kernel.vger.linux-cifs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On Mon, 03 Nov 2025, Jeff Layton wrote: > 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 parameter to struct createdata. Most callers just > leave that as a NULL pointer, but do_mknodat() is changed to wait for a > delegation break if there is one. > > Signed-off-by: Jeff Layton <[email protected]> > --- > fs/namei.c | 26 +++++++++++++++++--------- > include/linux/fs.h | 2 +- > 2 files changed, 18 insertions(+), 10 deletions(-) > > diff --git a/fs/namei.c b/fs/namei.c > index fdf4e78cd041de8c564b7d1d89a46ba2aaf79d53..e8973000a312fb05ebb63a0d9bd83b9a5f8f805d 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -3487,6 +3487,9 @@ int vfs_create(struct createdata *args) > > mode = vfs_prepare_mode(idmap, dir, mode, S_IALLUGO, S_IFREG); > error = security_inode_create(dir, dentry, mode); > + if (error) > + return error; > + error = try_break_deleg(dir, args->delegated_inode); > if (error) > return error; > error = dir->i_op->create(idmap, dir, dentry, mode, args->excl); > @@ -4359,6 +4362,8 @@ static int may_mknod(umode_t mode) > static int do_mknodat(int dfd, struct filename *name, umode_t mode, > unsigned int dev) > { > + struct delegated_inode delegated_inode = { }; > + struct createdata cargs = { }; If we must have 'createdata', can it have a 'struct delegated_inode' rather than a pointer to it? NeilBrown > struct mnt_idmap *idmap; > struct dentry *dentry; > struct path path; > @@ -4383,18 +4388,16 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode, > switch (mode & S_IFMT) { > case 0: > case S_IFREG: > - { > - struct createdata args = { .idmap = idmap, > - .dir = path.dentry->d_inode, > - .dentry = dentry, > - .mode = mode, > - .excl = true }; > - > - error = vfs_create(&args); > + cargs.idmap = idmap, > + cargs.dir = path.dentry->d_inode, > + cargs.dentry = dentry, > + cargs.delegated_inode = &delegated_inode; > + cargs.mode = mode, > + cargs.excl = true, > + error = vfs_create(&cargs); > if (!error) > security_path_post_mknod(idmap, dentry); > break; > - } > case S_IFCHR: case S_IFBLK: > error = vfs_mknod(idmap, path.dentry->d_inode, > dentry, mode, new_decode_dev(dev)); > @@ -4406,6 +4409,11 @@ static int do_mknodat(int dfd, struct filename *name, umode_t mode, > } > out2: > 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; > diff --git a/include/linux/fs.h b/include/linux/fs.h > index b61873767b37591aecadd147623d7dfc866bef82..cfcb20a7c4ce4b6dcec98b3eccbdb5ec8bab6fa9 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2116,12 +2116,12 @@ struct createdata { > struct mnt_idmap *idmap; // idmap of the mount the inode was found from > struct inode *dir; // inode of parent directory > struct dentry *dentry; // dentry of the child file > + struct delegated_inode *delegated_inode; // returns parent inode, if delegated > umode_t mode; // mode of the child file > bool excl; // whether the file must not yet exist > }; > > int vfs_create(struct createdata *); > - > 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 *, > > -- > 2.51.1 > >