]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
kernfs: Don't re-lock kernfs_root::kernfs_rwsem in kernfs_fop_readdir().
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Thu, 13 Feb 2025 14:50:21 +0000 (15:50 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 15 Feb 2025 16:46:32 +0000 (17:46 +0100)
The readdir operation iterates over all entries and invokes dir_emit()
for every entry passing kernfs_node::name as argument.
Since the name argument can change, and become invalid, the
kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames
during the operation.

The lock drop around dir_emit() has been initially introduced in commit
   1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2")

to avoid holding a global lock during a page fault. The lock drop is
wrong since the support of renames and not a big burden since the lock
is no longer global.

Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the
userpace buffer.

Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/kernfs/dir.c

index 5f0f8b95f44c0caef3397010b21637e0fbfa1a38..43fbada678381af16b8698f63dd2c054db095c61 100644 (file)
@@ -1869,10 +1869,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
                file->private_data = pos;
                kernfs_get(pos);
 
-               up_read(&root->kernfs_rwsem);
-               if (!dir_emit(ctx, name, len, ino, type))
+               if (!dir_emit(ctx, name, len, ino, type)) {
+                       up_read(&root->kernfs_rwsem);
                        return 0;
-               down_read(&root->kernfs_rwsem);
+               }
        }
        up_read(&root->kernfs_rwsem);
        file->private_data = NULL;