diff options
author | Mateusz Guzik <mjguzik@gmail.com> | 2023-07-27 13:38:09 +0200 |
---|---|---|
committer | Christian Brauner <brauner@kernel.org> | 2023-08-04 17:57:56 +0200 |
commit | ed192c59f86910f089d061e635f6c1129bb14064 (patch) | |
tree | 11f1942619856d9622d30da633eebaab0ae52704 /fs/file.c | |
parent | fs/ecryptfs: remove kernel-doc warnings (diff) | |
download | linux-ed192c59f86910f089d061e635f6c1129bb14064.tar.xz linux-ed192c59f86910f089d061e635f6c1129bb14064.zip |
file: mostly eliminate spurious relocking in __range_close
Stock code takes a lock trip for every fd in range, but this can be
trivially avoided and real-world consumers do have plenty of already
closed cases.
Just booting Debian 12 with a debug printk shows:
(sh) min 3 max 17 closed 15 empty 0
(sh) min 19 max 63 closed 31 empty 14
(sh) min 4 max 63 closed 0 empty 60
(spawn) min 3 max 63 closed 13 empty 48
(spawn) min 3 max 63 closed 13 empty 48
(mount) min 3 max 17 closed 15 empty 0
(mount) min 19 max 63 closed 32 empty 13
and so on.
While here use more idiomatic naming.
An avoidable relock is left in place to avoid uglifying the code.
The code was not switched to bitmap traversal for the same reason.
Tested with ltp kernel/syscalls/close_range
Signed-off-by: Mateusz Guzik <mjguzik@gmail.com>
Message-Id: <20230727113809.800067-1-mjguzik@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to '')
-rw-r--r-- | fs/file.c | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/fs/file.c b/fs/file.c index 7893ea161d77..7bb2cddbd82b 100644 --- a/fs/file.c +++ b/fs/file.c @@ -693,29 +693,30 @@ static inline void __range_cloexec(struct files_struct *cur_fds, spin_unlock(&cur_fds->file_lock); } -static inline void __range_close(struct files_struct *cur_fds, unsigned int fd, +static inline void __range_close(struct files_struct *files, unsigned int fd, unsigned int max_fd) { + struct file *file; unsigned n; - rcu_read_lock(); - n = last_fd(files_fdtable(cur_fds)); - rcu_read_unlock(); + spin_lock(&files->file_lock); + n = last_fd(files_fdtable(files)); max_fd = min(max_fd, n); - while (fd <= max_fd) { - struct file *file; - - spin_lock(&cur_fds->file_lock); - file = pick_file(cur_fds, fd++); - spin_unlock(&cur_fds->file_lock); - + for (; fd <= max_fd; fd++) { + file = pick_file(files, fd); if (file) { - /* found a valid file to close */ - filp_close(file, cur_fds); + spin_unlock(&files->file_lock); + filp_close(file, files); cond_resched(); + spin_lock(&files->file_lock); + } else if (need_resched()) { + spin_unlock(&files->file_lock); + cond_resched(); + spin_lock(&files->file_lock); } } + spin_unlock(&files->file_lock); } /** |