Re: [PATCH 05/13] vfs: allow rmdir to wait for delegation break on parent

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 <dmixw6ybhw2bqfejcpd5xq6i6o77heuunhnezy3nwrgraw2fce@e7xhnz24u6yn>
On Mon 13-10-25 10:48:03, Jeff Layton wrote:
> 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" return pointer to vfs_rmdir() and populate that
> pointer with the parent inode if it's non-NULL. Most existing in-kernel
> callers pass in a NULL pointer.
> 
> Signed-off-by: Jeff Layton <[email protected]>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <[email protected]>

								Honza

> ---
>  drivers/base/devtmpfs.c  |  2 +-
>  fs/ecryptfs/inode.c      |  2 +-
>  fs/namei.c               | 22 +++++++++++++++++-----
>  fs/nfsd/nfs4recover.c    |  4 ++--
>  fs/nfsd/vfs.c            |  2 +-
>  fs/overlayfs/overlayfs.h |  2 +-
>  fs/smb/server/vfs.c      |  4 ++--
>  include/linux/fs.h       |  3 ++-
>  8 files changed, 27 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
> index 0e79621cb0f79870003b867ca384199171ded4e0..104025104ef75381984fd94dfbd50feeaa8cdd22 100644
> --- a/drivers/base/devtmpfs.c
> +++ b/drivers/base/devtmpfs.c
> @@ -261,7 +261,7 @@ static int dev_rmdir(const char *name)
>  		return PTR_ERR(dentry);
>  	if (d_inode(dentry)->i_private == &thread)
>  		err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
> -				dentry);
> +				dentry, NULL);
>  	else
>  		err = -EPERM;
>  
> diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
> index 35830b3144f8f71374a78b3e7463b864f4fc216e..88631291b32535f623a3fbe4ea9b6ed48a306ca0 100644
> --- a/fs/ecryptfs/inode.c
> +++ b/fs/ecryptfs/inode.c
> @@ -540,7 +540,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
>  		if (d_unhashed(lower_dentry))
>  			rc = -EINVAL;
>  		else
> -			rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
> +			rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
>  	}
>  	if (!rc) {
>  		clear_nlink(d_inode(dentry));
> diff --git a/fs/namei.c b/fs/namei.c
> index 86cf6eca1f485361c6732974e4103cf5ea721539..4b5a99653c558397e592715d9d4663cd4a63ef86 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -4522,9 +4522,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
>  
>  /**
>   * vfs_rmdir - remove directory
> - * @idmap:	idmap of the mount the inode was found from
> - * @dir:	inode of the parent directory
> - * @dentry:	dentry of the child directory
> + * @idmap:		idmap of the mount the inode was found from
> + * @dir:		inode of the parent directory
> + * @dentry:		dentry of the child directory
> + * @delegated_inode:	returns parent inode, if it's delegated.
>   *
>   * Remove a directory.
>   *
> @@ -4535,7 +4536,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
>   * raw inode simply pass @nop_mnt_idmap.
>   */
>  int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
> -		     struct dentry *dentry)
> +	      struct dentry *dentry, struct inode **delegated_inode)
>  {
>  	int error = may_delete(idmap, dir, dentry, 1);
>  
> @@ -4557,6 +4558,10 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
>  	if (error)
>  		goto out;
>  
> +	error = try_break_deleg(dir, delegated_inode);
> +	if (error)
> +		goto out;
> +
>  	error = dir->i_op->rmdir(dir, dentry);
>  	if (error)
>  		goto out;
> @@ -4583,6 +4588,7 @@ int do_rmdir(int dfd, struct filename *name)
>  	struct qstr last;
>  	int type;
>  	unsigned int lookup_flags = 0;
> +	struct inode *delegated_inode = NULL;
>  retry:
>  	error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
>  	if (error)
> @@ -4612,7 +4618,8 @@ int do_rmdir(int dfd, struct filename *name)
>  	error = security_path_rmdir(&path, dentry);
>  	if (error)
>  		goto exit4;
> -	error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry);
> +	error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode,
> +			  dentry, &delegated_inode);
>  exit4:
>  	dput(dentry);
>  exit3:
> @@ -4620,6 +4627,11 @@ int do_rmdir(int dfd, struct filename *name)
>  	mnt_drop_write(path.mnt);
>  exit2:
>  	path_put(&path);
> +	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/nfs4recover.c b/fs/nfsd/nfs4recover.c
> index 3dfbb85c9a1166b56e56eb9f1d6bfd140584730b..ad3acbb956d90cac88f74e5f598719af6f1f8328 100644
> --- a/fs/nfsd/nfs4recover.c
> +++ b/fs/nfsd/nfs4recover.c
> @@ -275,7 +275,7 @@ nfsd4_unlink_clid_dir(char *name, struct nfsd_net *nn)
>  	status = -ENOENT;
>  	if (d_really_is_negative(dentry))
>  		goto out;
> -	status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry);
> +	status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry, NULL);
>  out:
>  	dput(dentry);
>  out_unlock:
> @@ -367,7 +367,7 @@ purge_old(struct dentry *parent, char *cname, struct nfsd_net *nn)
>  	inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
>  	child = lookup_one(&nop_mnt_idmap, &QSTR(cname), parent);
>  	if (!IS_ERR(child)) {
> -		status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child);
> +		status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child, NULL);
>  		if (status)
>  			printk("failed to remove client recovery directory %pd\n",
>  			       child);
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 447f5ab8e0b92288c9f220060ab15f32f2a84de9..7d8cd2595f197be9741ee6320d43ed6651896647 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -2194,7 +2194,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
>  				break;
>  		}
>  	} else {
> -		host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry);
> +		host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry, NULL);
>  	}
>  	fh_fill_post_attrs(fhp);
>  
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index 0f65f9a5d54d4786b39e4f4f30f416d5b9016e70..d215d7349489686b66bb66e939b27046f7d836f6 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -206,7 +206,7 @@ static inline int ovl_do_notify_change(struct ovl_fs *ofs,
>  static inline int ovl_do_rmdir(struct ovl_fs *ofs,
>  			       struct inode *dir, struct dentry *dentry)
>  {
> -	int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry);
> +	int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry, NULL);
>  
>  	pr_debug("rmdir(%pd2) = %i\n", dentry, err);
>  	return err;
> diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
> index 3d2190f26623b23ea79c63410905a3c3ad684048..c5f0f3170d586cb2dc4d416b80948c642797fb82 100644
> --- a/fs/smb/server/vfs.c
> +++ b/fs/smb/server/vfs.c
> @@ -609,7 +609,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
>  
>  	idmap = mnt_idmap(path->mnt);
>  	if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
> -		err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
> +		err = vfs_rmdir(idmap, d_inode(parent), path->dentry, NULL);
>  		if (err && err != -ENOTEMPTY)
>  			ksmbd_debug(VFS, "rmdir failed, err %d\n", err);
>  	} else {
> @@ -1090,7 +1090,7 @@ int ksmbd_vfs_unlink(struct file *filp)
>  	dget(dentry);
>  
>  	if (S_ISDIR(d_inode(dentry)->i_mode))
> -		err = vfs_rmdir(idmap, d_inode(dir), dentry);
> +		err = vfs_rmdir(idmap, d_inode(dir), dentry, NULL);
>  	else
>  		err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);
>  
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 1040df3792794cd353b86558b41618294e25b8a6..d8bdaf7c87502ff17775602f5391d375738b4ed8 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2120,7 +2120,8 @@ int vfs_symlink(struct mnt_idmap *, struct inode *,
>  		struct dentry *, const char *);
>  int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
>  	     struct dentry *, struct inode **);
> -int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *);
> +int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,
> +	      struct inode **);
>  int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
>  	       struct inode **);
>  
> 
> -- 
> 2.51.0
> 
-- 
Jan Kara <[email protected]>
SUSE Labs, CR
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.