summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2017-11-16 00:20:52 +0300
committerDavid Sterba <dsterba@suse.com>2017-11-27 17:50:07 +0300
commitb77000ed558daa3bef0899d29bf171b8c9b5e6a8 (patch)
treedf4e2531b11c7a3ea309c9ee991d43090f2be4b5
parent8e138e0d92c6c9d3d481674fb14e3439b495be37 (diff)
downloadlinux-b77000ed558daa3bef0899d29bf171b8c9b5e6a8.tar.xz
btrfs: fix deadlock when writing out space cache
If we fail to prepare our pages for whatever reason (out of memory in our case) we need to make sure to drop the block_group->data_rwsem, otherwise hilarity ensues. Signed-off-by: Josef Bacik <jbacik@fb.com> Reviewed-by: Omar Sandoval <osandov@fb.com> Reviewed-by: Liu Bo <bo.li.liu@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> [ add label and use existing unlocking code ] Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/free-space-cache.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index cdc9f4015ec3..4426d1c73e50 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1264,7 +1264,7 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
/* Lock all pages first so we can lock the extent safely. */
ret = io_ctl_prepare_pages(io_ctl, inode, 0);
if (ret)
- goto out;
+ goto out_unlock;
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
&cached_state);
@@ -1358,6 +1358,7 @@ out_nospc_locked:
out_nospc:
cleanup_write_cache_enospc(inode, io_ctl, &cached_state);
+out_unlock:
if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
up_write(&block_group->data_rwsem);