Re: [PATCH v3 08/13] vfs: make vfs_symlink break delegations on parent dir
Jan Kara <[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 | <od3ovbtjf3hc3htk6wxhb4t7wpq3he53dm3l23d456o4yjbe4t@tooasyi3jer4> |
On Tue 21-10-25 11:25:43, Jeff Layton wrote: > 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. > > Signed-off-by: Jeff Layton <[email protected]> Looks good. Feel free to add: Reviewed-by: Jan Kara <[email protected]> Honza > --- > fs/ecryptfs/inode.c | 2 +- > fs/init.c | 2 +- > fs/namei.c | 16 ++++++++++++++-- > fs/nfsd/vfs.c | 2 +- > fs/overlayfs/overlayfs.h | 2 +- > include/linux/fs.h | 2 +- > 6 files changed, 19 insertions(+), 7 deletions(-) > > diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c > index 639ae42bcd56890d04592f7269e4ffc099b44f09..d430ec5a63094ea4cd42828e7d44f0f8d918fcec 100644 > --- a/fs/ecryptfs/inode.c > +++ b/fs/ecryptfs/inode.c > @@ -480,7 +480,7 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap, > if (rc) > goto out_lock; > rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry, > - encoded_symname); > + encoded_symname, NULL); > kfree(encoded_symname); > if (rc || d_really_is_negative(lower_dentry)) > goto out_lock; > diff --git a/fs/init.c b/fs/init.c > index 4f02260dd65b0dfcbfbf5812d2ec6a33444a3b1f..e0f5429c0a49d046bd3f231a260954ed0f90ef44 100644 > --- a/fs/init.c > +++ b/fs/init.c > @@ -209,7 +209,7 @@ int __init init_symlink(const char *oldname, const char *newname) > error = security_path_symlink(&path, dentry, oldname); > if (!error) > error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode, > - dentry, oldname); > + dentry, oldname, NULL); > end_creating_path(&path, dentry); > return error; > } > diff --git a/fs/namei.c b/fs/namei.c > index 7e400cbdbc6af1c72eb684f051d0571e944a27d7..71af256cdd941e200389570538f64a3f795e6c83 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -4851,6 +4851,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) > * @dir: inode of the parent directory > * @dentry: dentry of the child symlink file > * @oldname: name of the file to link to > + * @delegated_inode: returns victim inode, if the inode is delegated. > * > * Create a symlink. > * > @@ -4861,7 +4862,8 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname) > * raw inode simply pass @nop_mnt_idmap. > */ > int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir, > - struct dentry *dentry, const char *oldname) > + struct dentry *dentry, const char *oldname, > + struct inode **delegated_inode) > { > int error; > > @@ -4876,6 +4878,10 @@ int vfs_symlink(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->symlink(idmap, dir, dentry, oldname); > if (!error) > fsnotify_create(dir, dentry); > @@ -4889,6 +4895,7 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to) > struct dentry *dentry; > struct path path; > unsigned int lookup_flags = 0; > + struct inode *delegated_inode = NULL; > > if (IS_ERR(from)) { > error = PTR_ERR(from); > @@ -4903,8 +4910,13 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to) > error = security_path_symlink(&path, dentry, from->name); > if (!error) > error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode, > - dentry, from->name); > + dentry, from->name, &delegated_inode); > end_creating_path(&path, dentry); > + if (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/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > index 44debf3d0be450ddc245e2fa4f57fe076e1454a2..386f454badce7ed448399ef93e9c8edafbcc4d79 100644 > --- a/fs/nfsd/vfs.c > +++ b/fs/nfsd/vfs.c > @@ -1829,7 +1829,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, > err = fh_fill_pre_attrs(fhp); > if (err != nfs_ok) > goto out_unlock; > - host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path); > + host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path, NULL); > err = nfserrno(host_err); > cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); > if (!err) > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index 87b82dada7ec1b8429299c68078cda24176c5607..94bb4540f7ae2e0571b3b88393c180bd73c3c09c 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -267,7 +267,7 @@ static inline int ovl_do_symlink(struct ovl_fs *ofs, > struct inode *dir, struct dentry *dentry, > const char *oldname) > { > - int err = vfs_symlink(ovl_upper_mnt_idmap(ofs), dir, dentry, oldname); > + int err = vfs_symlink(ovl_upper_mnt_idmap(ofs), dir, dentry, oldname, NULL); > > pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err); > return err; > diff --git a/include/linux/fs.h b/include/linux/fs.h > index a1e1afe39e01a46bf0a81e241b92690947402851..d8c7245da3bf3200b435c7ea6cafcf7903ebf293 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2117,7 +2117,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *, > int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *, > umode_t, dev_t, struct inode **); > int vfs_symlink(struct mnt_idmap *, struct inode *, > - struct dentry *, const char *); > + struct dentry *, const char *, struct inode **); > int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *, > struct dentry *, struct inode **); > int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *, > > -- > 2.51.0 > -- Jan Kara <[email protected]> SUSE Labs, CR