diff options
author | Josef Bacik <jbacik@fb.com> | 2017-07-24 15:14:25 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-08-16 10:12:05 -0400 |
commit | 23b5ec74943f44378b68c0edd8e210a86318ea5e (patch) | |
tree | 07fc0067812f384350e17660072d864a0a3eec87 /fs/btrfs/file.c | |
parent | 8d8aafeea23e2d641460d7e6231361f0322ac058 (diff) |
btrfs: fix readdir deadlock with pagefault
Readdir does dir_emit while under the btree lock. dir_emit can trigger
the page fault which means we can deadlock. Fix this by allocating a
buffer on opening a directory and copying the readdir into this buffer
and doing dir_emit from outside of the tree lock.
Thread A
readdir <holding tree lock>
dir_emit
<page fault>
down_read(mmap_sem)
Thread B
mmap write
down_write(mmap_sem)
page_mkwrite
wait_ordered_extents
Process C
finish_ordered_extent
insert_reserved_file_extent
try to lock leaf <hang>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ copy the deadlock scenario to changelog ]
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 58818cf7f82d..74fd7756cff3 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1990,8 +1990,15 @@ out: | |||
1990 | 1990 | ||
1991 | int btrfs_release_file(struct inode *inode, struct file *filp) | 1991 | int btrfs_release_file(struct inode *inode, struct file *filp) |
1992 | { | 1992 | { |
1993 | if (filp->private_data) | 1993 | struct btrfs_file_private *private = filp->private_data; |
1994 | |||
1995 | if (private && private->trans) | ||
1994 | btrfs_ioctl_trans_end(filp); | 1996 | btrfs_ioctl_trans_end(filp); |
1997 | if (private && private->filldir_buf) | ||
1998 | kfree(private->filldir_buf); | ||
1999 | kfree(private); | ||
2000 | filp->private_data = NULL; | ||
2001 | |||
1995 | /* | 2002 | /* |
1996 | * ordered_data_close is set by settattr when we are about to truncate | 2003 | * ordered_data_close is set by settattr when we are about to truncate |
1997 | * a file from a non-zero size to a zero size. This tries to | 2004 | * a file from a non-zero size to a zero size. This tries to |