summaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
authorMateusz Guzik <mguzik@redhat.com>2017-10-03 12:58:15 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2017-11-06 00:58:07 +0100
commitc02b1a9b41c2e728289f96850580a3651e0a8b5f (patch)
tree15497a5e1c48c022858bf4f050225dd70c8d894d /fs/file.c
parentvfs: stop clearing close on exec when closing a fd (diff)
downloadlinux-c02b1a9b41c2e728289f96850580a3651e0a8b5f.tar.xz
linux-c02b1a9b41c2e728289f96850580a3651e0a8b5f.zip
vfs: grab the lock instead of blocking in __fd_install during resizing
Explicit locking in the fallback case provides a safe state of the table. Getting rid of blocking semantics makes __fd_install usable again in non-sleepable contexts, which easies backporting efforts. There is a side effect of slightly nicer assembly for the common case as might_sleep can now be removed. Signed-off-by: Mateusz Guzik <mguzik@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/fs/file.c b/fs/file.c
index 9d047bd046b0..4115503bb575 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -592,13 +592,16 @@ void __fd_install(struct files_struct *files, unsigned int fd,
{
struct fdtable *fdt;
- might_sleep();
rcu_read_lock_sched();
- while (unlikely(files->resize_in_progress)) {
+ if (unlikely(files->resize_in_progress)) {
rcu_read_unlock_sched();
- wait_event(files->resize_wait, !files->resize_in_progress);
- rcu_read_lock_sched();
+ spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
+ BUG_ON(fdt->fd[fd] != NULL);
+ rcu_assign_pointer(fdt->fd[fd], file);
+ spin_unlock(&files->file_lock);
+ return;
}
/* coupled with smp_wmb() in expand_fdtable() */
smp_rmb();