aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2017-07-24 15:14:25 -0400
committerDavid Sterba <dsterba@suse.com>2017-08-16 10:12:05 -0400
commit23b5ec74943f44378b68c0edd8e210a86318ea5e (patch)
tree07fc0067812f384350e17660072d864a0a3eec87 /fs/btrfs/file.c
parent8d8aafeea23e2d641460d7e6231361f0322ac058 (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.c9
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
1991int btrfs_release_file(struct inode *inode, struct file *filp) 1991int 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