Yafang Shao reports that he has seen loads that generate billions of negative dentries in a directory, which then when the directory is removed causes excessive latencies for other users because the dentry shrinking is done under the directory inode lock. There seems to be no actual reason for holding the inode lock any more by the time we get rid of the now uninteresting negative dentries, and it's an effect of just code layout (the shared error path). Reorganize the code trivially to just have a separate success path, which simplifies the code (since 'd_delete_notify()' is only called in the success path anyway) and makes it trivial to just move the dentry shrinking outside the inode lock. Reported-by: Yafang Shao <laoar.shao@xxxxxxxxx> Link: https://lore.kernel.org/all/20240511022729.35144-1-laoar.shao@xxxxxxxxx/ Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Christian Brauner <brauner@xxxxxxxxxx> Cc: Jan Kara <jack@xxxxxxx> Cc: Waiman Long <longman@xxxxxxxxxx> Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> --- Ok, this is the same patch, just with a commit message. And I actually am running a kernel with that patch, so it compiles and boots. Very limited testing: I created a directory with ten million negative dentries, and then did a "rmdir" in one terminal window while doing a "ls" inside that directory in another to kind of reproduce (on a smaller scale) what Yafang was reporting. The "ls" was not affected at all. But honestly, this was *ONE* single trivial test, so it's almost completely worthless. fs/namei.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 28e62238346e..474b1ee3266d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4217,16 +4217,19 @@ int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, if (error) goto out; - shrink_dcache_parent(dentry); dentry->d_inode->i_flags |= S_DEAD; dont_mount(dentry); detach_mounts(dentry); + inode_unlock(dentry->d_inode); + + shrink_dcache_parent(dentry); + dput(dentry); + d_delete_notify(dir, dentry); + return 0; out: inode_unlock(dentry->d_inode); dput(dentry); - if (!error) - d_delete_notify(dir, dentry); return error; } EXPORT_SYMBOL(vfs_rmdir); -- 2.44.0.330.g4d18c88175