Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jeff Layton and committed by
Christian Brauner
4fa76319 e12d203b

+27 -14
+1 -1
drivers/base/devtmpfs.c
··· 261 261 return PTR_ERR(dentry); 262 262 if (d_inode(dentry)->i_private == &thread) 263 263 err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry), 264 - dentry); 264 + dentry, NULL); 265 265 else 266 266 err = -EPERM; 267 267
+1 -1
fs/ecryptfs/inode.c
··· 540 540 if (d_unhashed(lower_dentry)) 541 541 rc = -EINVAL; 542 542 else 543 - rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry); 543 + rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); 544 544 } 545 545 if (!rc) { 546 546 clear_nlink(d_inode(dentry));
+17 -5
fs/namei.c
··· 4522 4522 4523 4523 /** 4524 4524 * 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. 4528 4529 * 4529 4530 * Remove a directory. 4530 4531 * ··· 4536 4535 * raw inode simply pass @nop_mnt_idmap. 4537 4536 */ 4538 4537 int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, 4539 - struct dentry *dentry) 4538 + struct dentry *dentry, struct delegated_inode *delegated_inode) 4540 4539 { 4541 4540 int error = may_delete(idmap, dir, dentry, 1); 4542 4541 ··· 4555 4554 goto out; 4556 4555 4557 4556 error = security_inode_rmdir(dir, dentry); 4557 + if (error) 4558 + goto out; 4559 + 4560 + error = try_break_deleg(dir, delegated_inode); 4558 4561 if (error) 4559 4562 goto out; 4560 4563 ··· 4588 4583 struct qstr last; 4589 4584 int type; 4590 4585 unsigned int lookup_flags = 0; 4586 + struct delegated_inode delegated_inode = { }; 4591 4587 retry: 4592 4588 error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); 4593 4589 if (error) ··· 4618 4612 error = security_path_rmdir(&path, dentry); 4619 4613 if (error) 4620 4614 goto exit4; 4621 - error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry); 4615 + error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, 4616 + dentry, &delegated_inode); 4622 4617 exit4: 4623 4618 dput(dentry); 4624 4619 exit3: ··· 4627 4620 mnt_drop_write(path.mnt); 4628 4621 exit2: 4629 4622 path_put(&path); 4623 + if (is_delegated(&delegated_inode)) { 4624 + error = break_deleg_wait(&delegated_inode); 4625 + if (!error) 4626 + goto retry; 4627 + } 4630 4628 if (retry_estale(error, lookup_flags)) { 4631 4629 lookup_flags |= LOOKUP_REVAL; 4632 4630 goto retry;
+2 -2
fs/nfsd/nfs4recover.c
··· 337 337 status = -ENOENT; 338 338 if (d_really_is_negative(dentry)) 339 339 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); 341 341 out: 342 342 dput(dentry); 343 343 out_unlock: ··· 427 427 if (nfs4_has_reclaimed_state(name, nn)) 428 428 goto out_free; 429 429 430 - status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child); 430 + status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child, NULL); 431 431 if (status) 432 432 printk("failed to remove client recovery directory %pd\n", 433 433 child);
+1 -1
fs/nfsd/vfs.c
··· 2108 2108 break; 2109 2109 } 2110 2110 } else { 2111 - host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry); 2111 + host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry, NULL); 2112 2112 } 2113 2113 fh_fill_post_attrs(fhp); 2114 2114
+1 -1
fs/overlayfs/overlayfs.h
··· 206 206 static inline int ovl_do_rmdir(struct ovl_fs *ofs, 207 207 struct inode *dir, struct dentry *dentry) 208 208 { 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); 210 210 211 211 pr_debug("rmdir(%pd2) = %i\n", dentry, err); 212 212 return err;
+2 -2
fs/smb/server/vfs.c
··· 609 609 610 610 idmap = mnt_idmap(path->mnt); 611 611 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); 613 613 if (err && err != -ENOTEMPTY) 614 614 ksmbd_debug(VFS, "rmdir failed, err %d\n", err); 615 615 } else { ··· 1090 1090 dget(dentry); 1091 1091 1092 1092 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); 1094 1094 else 1095 1095 err = vfs_unlink(idmap, d_inode(dir), dentry, NULL); 1096 1096
+2 -1
include/linux/fs.h
··· 2121 2121 struct dentry *, const char *); 2122 2122 int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *, 2123 2123 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 *); 2125 2126 int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *, 2126 2127 struct delegated_inode *); 2127 2128