diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-09-10 17:48:00 +0200 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-09-14 15:58:06 +0200 |
| commit | 3a70f44797b692ea09b557bee83159cd507c5a2b (patch) | |
| tree | dfa0c259f1e37c3c9d6f1982323b76b7c633b61b | |
| parent | bee7cdebd22108002a5bb5a7e5e2a804639d2e36 (diff) | |
| download | linux-next-3a70f44797b692ea09b557bee83159cd507c5a2b.tar.gz linux-next-3a70f44797b692ea09b557bee83159cd507c5a2b.zip | |
fs: add switch_files_struct()
Add switch_files_struct() to install another table on a task. It
consumes the reference to the new table and puts the old one. Convert
every place that switches a descriptor table except unshare_files().
No functional changes.
Link: https://patch.msgid.link/20260910-work-coredump-unlock-self-v4-2-a5c1800dc930@kernel.org
Reviewed-by: NeilBrown <neil@brown.name>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
| -rw-r--r-- | fs/file.c | 23 | ||||
| -rw-r--r-- | include/linux/fdtable.h | 1 | ||||
| -rw-r--r-- | kernel/fork.c | 6 |
3 files changed, 14 insertions, 16 deletions
diff --git a/fs/file.c b/fs/file.c index 59673547de90..345011dad472 100644 --- a/fs/file.c +++ b/fs/file.c @@ -515,16 +515,18 @@ void put_files_struct(struct files_struct *files) } } -void exit_files(struct task_struct *tsk) +/* Install @files on @tsk, consuming the reference, and put the old table. */ +void switch_files_struct(struct task_struct *tsk, struct files_struct *files) { - struct files_struct * files = tsk->files; + scoped_guard(task_lock, tsk) + swap(tsk->files, files); + put_files_struct(files); +} - if (files) { - task_lock(tsk); - tsk->files = NULL; - task_unlock(tsk); - put_files_struct(files); - } +void exit_files(struct task_struct *tsk) +{ + if (tsk->files) + switch_files_struct(tsk, NULL); } struct files_struct init_files = { @@ -855,10 +857,7 @@ SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd, * We're done closing the files we were supposed to. Time to install * the new file descriptor table and drop the old one. */ - task_lock(me); - me->files = cur_fds; - task_unlock(me); - put_files_struct(fds); + switch_files_struct(me, cur_fds); } return 0; diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index c45306a9f007..9614c6ecd477 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -100,6 +100,7 @@ static inline bool close_on_exec(unsigned int fd, const struct files_struct *fil struct task_struct; void put_files_struct(struct files_struct *fs); +void switch_files_struct(struct task_struct *tsk, struct files_struct *files); int unshare_files(void); struct fd_range { unsigned int from, to; diff --git a/kernel/fork.c b/kernel/fork.c index a5934a317634..f09ca97411a2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -3323,10 +3323,8 @@ int ksys_unshare(unsigned long unshare_flags) if (new_fs) new_fs = switch_fs_struct(new_fs); - if (new_fd) { - guard(task_lock)(current); - swap(current->files, new_fd); - } + if (new_fd) + switch_files_struct(current, no_free_ptr(new_fd)); if (new_cred) { /* Install the new user namespace */ |
