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>
This commit is contained in:
Josef Bacik
2017-07-24 15:14:25 -04:00
committed by David Sterba
parent 8d8aafeea2
commit 23b5ec7494
4 changed files with 110 additions and 34 deletions

View File

@@ -1264,6 +1264,11 @@ struct btrfs_root {
atomic64_t qgroup_meta_rsv;
};
struct btrfs_file_private {
struct btrfs_trans_handle *trans;
void *filldir_buf;
};
static inline u32 btrfs_inode_sectorsize(const struct inode *inode)
{
return btrfs_sb(inode->i_sb)->sectorsize;