diff options
| author | Jeff Layton <jlayton@kernel.org> | 2025-11-11 09:12:51 -0500 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2025-11-12 09:38:36 +0100 |
| commit | c826229c6a82fe1fe7b7752692f87a881eb4b545 (patch) | |
| tree | 40147562eea7d179a17dcd98d4773318e0778132 /fs/namei.c | |
| parent | 85bbffcad7307e2ca6136be657cc21b0e1c42241 (diff) | |
vfs: make vfs_create 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 delegated_inode parameter to vfs_create. Most callers are
converted to pass in NULL, but do_mknodat() is changed to wait for a
delegation break if there is one.
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-10-52f3feebb2f2@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/fs/namei.c b/fs/namei.c index 9586c6aba6ea..b20f053374a5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3463,6 +3463,7 @@ static inline umode_t vfs_prepare_mode(struct mnt_idmap *idmap, * @idmap: idmap of the mount the inode was found from * @dentry: dentry of the child file * @mode: mode of the child file + * @di: returns parent inode, if the inode is delegated. * * Create a new file. * @@ -3472,7 +3473,8 @@ static inline umode_t vfs_prepare_mode(struct mnt_idmap *idmap, * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ -int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode) +int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode, + struct delegated_inode *di) { struct inode *dir = d_inode(dentry->d_parent); int error; @@ -3488,6 +3490,9 @@ int vfs_create(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode) error = security_inode_create(dir, dentry, mode); if (error) return error; + error = try_break_deleg(dir, di); + if (error) + return error; error = dir->i_op->create(idmap, dir, dentry, mode, true); if (!error) fsnotify_create(dir, dentry); @@ -4358,6 +4363,7 @@ 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 di = { }; struct mnt_idmap *idmap; struct dentry *dentry; struct path path; @@ -4381,7 +4387,7 @@ retry: idmap = mnt_idmap(path.mnt); switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(idmap, dentry, mode); + error = vfs_create(idmap, dentry, mode, &di); if (!error) security_path_post_mknod(idmap, dentry); break; @@ -4396,6 +4402,11 @@ retry: } out2: end_creating_path(&path, dentry); + if (is_delegated(&di)) { + error = break_deleg_wait(&di); + if (!error) + goto retry; + } if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; |
