When the last reference to a descriptor table is dropped close_files() closes every file but punts the actual work to task work. For an exiting task that task work only runs in exit_task_work(). Before commit 4a9d4b024a31 ("switch fput to task_work_add") fput() was synchronous everywhere and exit released its files in exit_files(). The deferral made fput() safe from any context. And exit_files() offloaded to task work as a side-effect. And that has downsides. Oleg and Neil noticed that some time ago. A task that exits with a big descriptor table ends up queueing a very large number of files on task work. That walks the task work list under ->pi_lock. Note, today closing the files runs after exit_fs(), disassociate_ctty() and exit_task_namespaces(). So ->flush() and ->release() get a task that has already lost its fs, its namespaces and its controlling terminal even though the files were closed long before that. So let close_files() close right away. No locks are held, the path already sleeps, close() does the same thing already. Kernel threads can just keep deferring. ->flush() and ->release() now run before exit_fs() and disassociate_ctty(). Signed-off-by: Christian Brauner (Amutable) --- fs/file.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/file.c b/fs/file.c index 628ca07dc4b1..e2d4b72c2e26 100644 --- a/fs/file.c +++ b/fs/file.c @@ -480,6 +480,11 @@ static struct fdtable *close_files(struct files_struct * files) */ struct fdtable *fdt = rcu_dereference_raw(files->fdt); unsigned int i, j = 0; + /* + * A kernel thread that might be needed to make progress on some + * umount must not run __fput() itself, see __fput_sync(). + */ + bool sync = !(current->flags & PF_KTHREAD); for (;;) { unsigned long set; @@ -491,7 +496,10 @@ static struct fdtable *close_files(struct files_struct * files) if (set & 1) { struct file *file = fdt->fd[i]; if (file) { - filp_close(file, files); + if (sync) + filp_close_sync(file, files); + else + filp_close(file, files); cond_resched(); } } -- 2.53.0