mirror of https://github.com/torvalds/linux.git
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>
This commit is contained in:
parent
e8960c1b2e
commit
92bf53577f
|
|
@ -479,7 +479,7 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap,
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
|
rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
|
||||||
encoded_symname);
|
encoded_symname, NULL);
|
||||||
kfree(encoded_symname);
|
kfree(encoded_symname);
|
||||||
if (rc || d_really_is_negative(lower_dentry))
|
if (rc || d_really_is_negative(lower_dentry))
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ int __init init_symlink(const char *oldname, const char *newname)
|
||||||
error = security_path_symlink(&path, dentry, oldname);
|
error = security_path_symlink(&path, dentry, oldname);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||||
dentry, oldname);
|
dentry, oldname, NULL);
|
||||||
end_creating_path(&path, dentry);
|
end_creating_path(&path, dentry);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
fs/namei.c
16
fs/namei.c
|
|
@ -4845,6 +4845,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
|
||||||
* @dir: inode of the parent directory
|
* @dir: inode of the parent directory
|
||||||
* @dentry: dentry of the child symlink file
|
* @dentry: dentry of the child symlink file
|
||||||
* @oldname: name of the file to link to
|
* @oldname: name of the file to link to
|
||||||
|
* @delegated_inode: returns victim inode, if the inode is delegated.
|
||||||
*
|
*
|
||||||
* Create a symlink.
|
* Create a symlink.
|
||||||
*
|
*
|
||||||
|
|
@ -4855,7 +4856,8 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
|
||||||
* raw inode simply pass @nop_mnt_idmap.
|
* raw inode simply pass @nop_mnt_idmap.
|
||||||
*/
|
*/
|
||||||
int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
struct dentry *dentry, const char *oldname)
|
struct dentry *dentry, const char *oldname,
|
||||||
|
struct delegated_inode *delegated_inode)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
@ -4870,6 +4872,10 @@ int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
error = try_break_deleg(dir, delegated_inode);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
error = dir->i_op->symlink(idmap, dir, dentry, oldname);
|
error = dir->i_op->symlink(idmap, dir, dentry, oldname);
|
||||||
if (!error)
|
if (!error)
|
||||||
fsnotify_create(dir, dentry);
|
fsnotify_create(dir, dentry);
|
||||||
|
|
@ -4883,6 +4889,7 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct path path;
|
struct path path;
|
||||||
unsigned int lookup_flags = 0;
|
unsigned int lookup_flags = 0;
|
||||||
|
struct delegated_inode delegated_inode = { };
|
||||||
|
|
||||||
if (IS_ERR(from)) {
|
if (IS_ERR(from)) {
|
||||||
error = PTR_ERR(from);
|
error = PTR_ERR(from);
|
||||||
|
|
@ -4897,8 +4904,13 @@ int do_symlinkat(struct filename *from, int newdfd, struct filename *to)
|
||||||
error = security_path_symlink(&path, dentry, from->name);
|
error = security_path_symlink(&path, dentry, from->name);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||||
dentry, from->name);
|
dentry, from->name, &delegated_inode);
|
||||||
end_creating_path(&path, dentry);
|
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)) {
|
if (retry_estale(error, lookup_flags)) {
|
||||||
lookup_flags |= LOOKUP_REVAL;
|
lookup_flags |= LOOKUP_REVAL;
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
|
||||||
|
|
@ -1742,7 +1742,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
err = fh_fill_pre_attrs(fhp);
|
err = fh_fill_pre_attrs(fhp);
|
||||||
if (err != nfs_ok)
|
if (err != nfs_ok)
|
||||||
goto out_unlock;
|
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);
|
err = nfserrno(host_err);
|
||||||
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
|
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
|
||||||
if (!err)
|
if (!err)
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ static inline int ovl_do_symlink(struct ovl_fs *ofs,
|
||||||
struct inode *dir, struct dentry *dentry,
|
struct inode *dir, struct dentry *dentry,
|
||||||
const char *oldname)
|
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);
|
pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
||||||
|
|
@ -2118,7 +2118,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *, struct inode *,
|
||||||
int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
|
int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||||
umode_t, dev_t, struct delegated_inode *);
|
umode_t, dev_t, struct delegated_inode *);
|
||||||
int vfs_symlink(struct mnt_idmap *, struct inode *,
|
int vfs_symlink(struct mnt_idmap *, struct inode *,
|
||||||
struct dentry *, const char *);
|
struct dentry *, const char *, struct delegated_inode *);
|
||||||
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
||||||
struct dentry *, struct delegated_inode *);
|
struct dentry *, struct delegated_inode *);
|
||||||
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,
|
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue