Skip to content

Commit 4fa7631

Browse files
jtlaytonbrauner
authored andcommitted
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: 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-7-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent e12d203 commit 4fa7631

8 files changed

Lines changed: 27 additions & 14 deletions

File tree

drivers/base/devtmpfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ static int dev_rmdir(const char *name)
261261
return PTR_ERR(dentry);
262262
if (d_inode(dentry)->i_private == &thread)
263263
err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
264-
dentry);
264+
dentry, NULL);
265265
else
266266
err = -EPERM;
267267

fs/ecryptfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
540540
if (d_unhashed(lower_dentry))
541541
rc = -EINVAL;
542542
else
543-
rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
543+
rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
544544
}
545545
if (!rc) {
546546
clear_nlink(d_inode(dentry));

fs/namei.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4522,9 +4522,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
45224522

45234523
/**
45244524
* vfs_rmdir - remove directory
4525-
* @idmap: idmap of the mount the inode was found from
4526-
* @dir: inode of the parent directory
4527-
* @dentry: dentry of the child directory
4525+
* @idmap: idmap of the mount the inode was found from
4526+
* @dir: inode of the parent directory
4527+
* @dentry: dentry of the child directory
4528+
* @delegated_inode: returns parent inode, if it's delegated.
45284529
*
45294530
* Remove a directory.
45304531
*
@@ -4535,7 +4536,7 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
45354536
* raw inode simply pass @nop_mnt_idmap.
45364537
*/
45374538
int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
4538-
struct dentry *dentry)
4539+
struct dentry *dentry, struct delegated_inode *delegated_inode)
45394540
{
45404541
int error = may_delete(idmap, dir, dentry, 1);
45414542

@@ -4557,6 +4558,10 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
45574558
if (error)
45584559
goto out;
45594560

4561+
error = try_break_deleg(dir, delegated_inode);
4562+
if (error)
4563+
goto out;
4564+
45604565
error = dir->i_op->rmdir(dir, dentry);
45614566
if (error)
45624567
goto out;
@@ -4583,6 +4588,7 @@ int do_rmdir(int dfd, struct filename *name)
45834588
struct qstr last;
45844589
int type;
45854590
unsigned int lookup_flags = 0;
4591+
struct delegated_inode delegated_inode = { };
45864592
retry:
45874593
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
45884594
if (error)
@@ -4612,14 +4618,20 @@ int do_rmdir(int dfd, struct filename *name)
46124618
error = security_path_rmdir(&path, dentry);
46134619
if (error)
46144620
goto exit4;
4615-
error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry);
4621+
error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode,
4622+
dentry, &delegated_inode);
46164623
exit4:
46174624
dput(dentry);
46184625
exit3:
46194626
inode_unlock(path.dentry->d_inode);
46204627
mnt_drop_write(path.mnt);
46214628
exit2:
46224629
path_put(&path);
4630+
if (is_delegated(&delegated_inode)) {
4631+
error = break_deleg_wait(&delegated_inode);
4632+
if (!error)
4633+
goto retry;
4634+
}
46234635
if (retry_estale(error, lookup_flags)) {
46244636
lookup_flags |= LOOKUP_REVAL;
46254637
goto retry;

fs/nfsd/nfs4recover.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ nfsd4_unlink_clid_dir(char *name, struct nfsd_net *nn)
337337
status = -ENOENT;
338338
if (d_really_is_negative(dentry))
339339
goto out;
340-
status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry);
340+
status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry, NULL);
341341
out:
342342
dput(dentry);
343343
out_unlock:
@@ -427,7 +427,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
427427
if (nfs4_has_reclaimed_state(name, nn))
428428
goto out_free;
429429

430-
status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child);
430+
status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child, NULL);
431431
if (status)
432432
printk("failed to remove client recovery directory %pd\n",
433433
child);

fs/nfsd/vfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2108,7 +2108,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
21082108
break;
21092109
}
21102110
} else {
2111-
host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry);
2111+
host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry, NULL);
21122112
}
21132113
fh_fill_post_attrs(fhp);
21142114

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ static inline int ovl_do_notify_change(struct ovl_fs *ofs,
206206
static inline int ovl_do_rmdir(struct ovl_fs *ofs,
207207
struct inode *dir, struct dentry *dentry)
208208
{
209-
int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry);
209+
int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry, NULL);
210210

211211
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
212212
return err;

fs/smb/server/vfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
609609

610610
idmap = mnt_idmap(path->mnt);
611611
if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
612-
err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
612+
err = vfs_rmdir(idmap, d_inode(parent), path->dentry, NULL);
613613
if (err && err != -ENOTEMPTY)
614614
ksmbd_debug(VFS, "rmdir failed, err %d\n", err);
615615
} else {
@@ -1090,7 +1090,7 @@ int ksmbd_vfs_unlink(struct file *filp)
10901090
dget(dentry);
10911091

10921092
if (S_ISDIR(d_inode(dentry)->i_mode))
1093-
err = vfs_rmdir(idmap, d_inode(dir), dentry);
1093+
err = vfs_rmdir(idmap, d_inode(dir), dentry, NULL);
10941094
else
10951095
err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);
10961096

include/linux/fs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,8 @@ int vfs_symlink(struct mnt_idmap *, struct inode *,
21212121
struct dentry *, const char *);
21222122
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
21232123
struct dentry *, struct delegated_inode *);
2124-
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *);
2124+
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *,
2125+
struct delegated_inode *);
21252126
int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
21262127
struct delegated_inode *);
21272128

0 commit comments

Comments
 (0)