Skip to content

Commit 92bf535

Browse files
jtlaytonbrauner
authored andcommitted
vfs: make vfs_symlink break delegations on parent dir
In order to add directory delegation support, we must break delegations on the parent on any change to the directory. Add a delegated_inode parameter to vfs_symlink() and have it break the delegation. do_symlinkat() can then wait on the delegation break before proceeding. 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-12-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent e8960c1 commit 92bf535

6 files changed

Lines changed: 19 additions & 7 deletions

File tree

fs/ecryptfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap,
479479
if (rc)
480480
goto out_lock;
481481
rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
482-
encoded_symname);
482+
encoded_symname, NULL);
483483
kfree(encoded_symname);
484484
if (rc || d_really_is_negative(lower_dentry))
485485
goto out_lock;

fs/init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ int __init init_symlink(const char *oldname, const char *newname)
209209
error = security_path_symlink(&path, dentry, oldname);
210210
if (!error)
211211
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
212-
dentry, oldname);
212+
dentry, oldname, NULL);
213213
end_creating_path(&path, dentry);
214214
return error;
215215
}

fs/namei.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,6 +4845,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
48454845
* @dir: inode of the parent directory
48464846
* @dentry: dentry of the child symlink file
48474847
* @oldname: name of the file to link to
4848+
* @delegated_inode: returns victim inode, if the inode is delegated.
48484849
*
48494850
* Create a symlink.
48504851
*
@@ -4855,7 +4856,8 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
48554856
* raw inode simply pass @nop_mnt_idmap.
48564857
*/
48574858
int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
4858-
struct dentry *dentry, const char *oldname)
4859+
struct dentry *dentry, const char *oldname,
4860+
struct delegated_inode *delegated_inode)
48594861
{
48604862
int error;
48614863

@@ -4870,6 +4872,10 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
48704872
if (error)
48714873
return error;
48724874

4875+
error = try_break_deleg(dir, delegated_inode);
4876+
if (error)
4877+
return error;
4878+
48734879
error = dir->i_op->symlink(idmap, dir, dentry, oldname);
48744880
if (!error)
48754881
fsnotify_create(dir, dentry);
@@ -4883,6 +4889,7 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
48834889
struct dentry *dentry;
48844890
struct path path;
48854891
unsigned int lookup_flags = 0;
4892+
struct delegated_inode delegated_inode = { };
48864893

48874894
if (IS_ERR(from)) {
48884895
error = PTR_ERR(from);
@@ -4897,8 +4904,13 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
48974904
error = security_path_symlink(&path, dentry, from->name);
48984905
if (!error)
48994906
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
4900-
dentry, from->name);
4907+
dentry, from->name, &delegated_inode);
49014908
end_creating_path(&path, dentry);
4909+
if (is_delegated(&delegated_inode)) {
4910+
error = break_deleg_wait(&delegated_inode);
4911+
if (!error)
4912+
goto retry;
4913+
}
49024914
if (retry_estale(error, lookup_flags)) {
49034915
lookup_flags |= LOOKUP_REVAL;
49044916
goto retry;

fs/nfsd/vfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
17421742
err = fh_fill_pre_attrs(fhp);
17431743
if (err != nfs_ok)
17441744
goto out_unlock;
1745-
host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path);
1745+
host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path, NULL);
17461746
err = nfserrno(host_err);
17471747
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
17481748
if (!err)

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ static inline int ovl_do_symlink(struct ovl_fs *ofs,
267267
struct inode *dir, struct dentry *dentry,
268268
const char *oldname)
269269
{
270-
int err = vfs_symlink(ovl_upper_mnt_idmap(ofs), dir, dentry, oldname);
270+
int err = vfs_symlink(ovl_upper_mnt_idmap(ofs), dir, dentry, oldname, NULL);
271271

272272
pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err);
273273
return err;

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2118,7 +2118,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *,
21182118
int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
21192119
umode_t, dev_t, struct delegated_inode *);
21202120
int vfs_symlink(struct mnt_idmap *, struct inode *,
2121-
struct dentry *, const char *);
2121+
struct dentry *, const char *, struct delegated_inode *);
21222122
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
21232123
struct dentry *, struct delegated_inode *);
21242124
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,

0 commit comments

Comments
 (0)