[PATCH v4 10/17] vfs: make vfs_create break delegations on parent directory
From: Jeff Layton <jlayton@kernel.org>
Date: 2025-11-03 12:53:25
Also in:
linux-cifs, linux-fsdevel, linux-nfs, linux-unionfs, linux-xfs, lkml, netfs
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
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 <jlayton@kernel.org> --- 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 = { }; 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