Unverified Commit 4fa76319 authored by Jeff Layton's avatar Jeff Layton Committed by Christian Brauner
Browse files

vfs: allow rmdir to wait for delegation break on parent



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 struct 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.

Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarNeilBrown <neil@brown.name>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-7-52f3feebb2f2@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent e12d203b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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));
+17 −5
Original line number Diff line number Diff line
@@ -4525,6 +4525,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
 * @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 delegated_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 delegated_inode delegated_inode = { };
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 (is_delegated(&delegated_inode)) {
		error = break_deleg_wait(&delegated_inode);
		if (!error)
			goto retry;
	}
	if (retry_estale(error, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
		goto retry;
+2 −2
Original line number Diff line number Diff line
@@ -337,7 +337,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:
@@ -427,7 +427,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
	if (nfs4_has_reclaimed_state(name, nn))
		goto out_free;

	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);
+1 −1
Original line number Diff line number Diff line
@@ -2108,7 +2108,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);

Loading