aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMateusz Guzik <mguzik@redhat.com>2017-10-03 06:58:15 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-11-05 18:58:07 -0500
commitc02b1a9b41c2e728289f96850580a3651e0a8b5f (patch)
tree15497a5e1c48c022858bf4f050225dd70c8d894d
parent5297908270549b734c7c2556745e2385b6d4941d (diff)
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>
-rw-r--r--Documentation/filesystems/porting4
-rw-r--r--fs/file.c11
2 files changed, 7 insertions, 8 deletions
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 93e0a2404532..17bb4dc28fae 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -502,10 +502,6 @@ in your dentry operations instead.
502 store it as cookie. 502 store it as cookie.
503-- 503--
504[mandatory] 504[mandatory]
505 __fd_install() & fd_install() can now sleep. Callers should not
506 hold a spinlock or other resources that do not allow a schedule.
507--
508[mandatory]
509 any symlink that might use page_follow_link_light/page_put_link() must 505 any symlink that might use page_follow_link_light/page_put_link() must
510 have inode_nohighmem(inode) called before anything might start playing with 506 have inode_nohighmem(inode) called before anything might start playing with
511 its pagecache. No highmem pages should end up in the pagecache of such 507 its pagecache. No highmem pages should end up in the pagecache of such
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,
592{ 592{
593 struct fdtable *fdt; 593 struct fdtable *fdt;
594 594
595 might_sleep();
596 rcu_read_lock_sched(); 595 rcu_read_lock_sched();
597 596
598 while (unlikely(files->resize_in_progress)) { 597 if (unlikely(files->resize_in_progress)) {
599 rcu_read_unlock_sched(); 598 rcu_read_unlock_sched();
600 wait_event(files->resize_wait, !files->resize_in_progress); 599 spin_lock(&files->file_lock);
601 rcu_read_lock_sched(); 600 fdt = files_fdtable(files);
601 BUG_ON(fdt->fd[fd] != NULL);
602 rcu_assign_pointer(fdt->fd[fd], file);
603 spin_unlock(&files->file_lock);
604 return;
602 } 605 }
603 /* coupled with smp_wmb() in expand_fdtable() */ 606 /* coupled with smp_wmb() in expand_fdtable() */
604 smp_rmb(); 607 smp_rmb();