]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: delay sysctl_nr_open check in expand_files()
authorMateusz Guzik <mjguzik@gmail.com>
Sat, 16 Nov 2024 06:41:28 +0000 (07:41 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 2 Dec 2024 10:24:49 +0000 (11:24 +0100)
Suppose a thread sharing the table started a resize, while
sysctl_nr_open got lowered to a value which prohibits it. This is still
going to go through with and without the patch, which is fine.

Further suppose another thread shows up to do a matching expansion while
resize_in_progress == true. It is going to error out since it performs
the sysctl_nr_open check *before* finding out if there is an expansion
in progress. But the aformentioned thread is going to succeded, so the
error is spurious (and it would not happen if the thread showed up a
little bit later).

Checking the sysctl *after* we know there are no pending updates sorts
it out.

While here annotate the thing as unlikely.

Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Link: https://lore.kernel.org/r/20241116064128.280870-1-mjguzik@gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/file.c

index fb1011cf6b4a69451fe90430c5eacebbe845849c..019fb9acf91b2a7ca6621959333d325ab4f73d4f 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -278,10 +278,6 @@ repeat:
        if (nr < fdt->max_fds)
                return 0;
 
-       /* Can we expand? */
-       if (nr >= sysctl_nr_open)
-               return -EMFILE;
-
        if (unlikely(files->resize_in_progress)) {
                spin_unlock(&files->file_lock);
                wait_event(files->resize_wait, !files->resize_in_progress);
@@ -289,6 +285,10 @@ repeat:
                goto repeat;
        }
 
+       /* Can we expand? */
+       if (unlikely(nr >= sysctl_nr_open))
+               return -EMFILE;
+
        /* All good, so we try */
        files->resize_in_progress = true;
        error = expand_fdtable(files, nr);