]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: move fd_install() slowpath into a dedicated routine and provide commentary
authorMateusz Guzik <mjguzik@gmail.com>
Mon, 10 Nov 2025 09:56:34 +0000 (10:56 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 12 Nov 2025 11:19:09 +0000 (12:19 +0100)
On stock kernel gcc 14 emits avoidable register spillage:
endbr64
call   ffffffff81374630 <__fentry__>
push   %r13
push   %r12
push   %rbx
sub    $0x8,%rsp
[snip]

Total fast path is 99 bytes.

Moving the slowpath out avoids it and shortens the fast path to 74
bytes.

Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Link: https://patch.msgid.link/20251110095634.1433061-1-mjguzik@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/file.c

index 28743b742e3cf65b36227033d4e3ecd643108bd3..3f56890068aa2c63af1b0956fdfc0bad1b1d79b0 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -641,6 +641,34 @@ void put_unused_fd(unsigned int fd)
 
 EXPORT_SYMBOL(put_unused_fd);
 
+/*
+ * Install a file pointer in the fd array while it is being resized.
+ *
+ * We need to make sure our update to the array does not get lost as the resizing
+ * thread can be copying the content as we modify it.
+ *
+ * We have two ways to do it:
+ * - go off CPU waiting for resize_in_progress to clear
+ * - take the spin lock
+ *
+ * The latter is trivial to implement and saves us from having to might_sleep()
+ * for debugging purposes.
+ *
+ * This is moved out of line from fd_install() to convince gcc to optimize that
+ * routine better.
+ */
+static void noinline fd_install_slowpath(unsigned int fd, struct file *file)
+{
+       struct files_struct *files = current->files;
+       struct fdtable *fdt;
+
+       spin_lock(&files->file_lock);
+       fdt = files_fdtable(files);
+       VFS_BUG_ON(rcu_access_pointer(fdt->fd[fd]) != NULL);
+       rcu_assign_pointer(fdt->fd[fd], file);
+       spin_unlock(&files->file_lock);
+}
+
 /**
  * fd_install - install a file pointer in the fd array
  * @fd: file descriptor to install the file in
@@ -658,14 +686,9 @@ void fd_install(unsigned int fd, struct file *file)
                return;
 
        rcu_read_lock_sched();
-
        if (unlikely(files->resize_in_progress)) {
                rcu_read_unlock_sched();
-               spin_lock(&files->file_lock);
-               fdt = files_fdtable(files);
-               VFS_BUG_ON(rcu_access_pointer(fdt->fd[fd]) != NULL);
-               rcu_assign_pointer(fdt->fd[fd], file);
-               spin_unlock(&files->file_lock);
+               fd_install_slowpath(fd, file);
                return;
        }
        /* coupled with smp_wmb() in expand_fdtable() */