summary refs log tree commit diff
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2016-10-10 13:43:31 -0700
committerChris Mason <clm@fb.com>2016-10-10 13:43:31 -0700
commit19c4d2f994788a954af1aa7e53b0fdb46fd7925a (patch)
tree1c2a40e3866668a68b4bfc4ff774295f3f660bc5 /fs/btrfs/volumes.c
parent196e02490c934398f894e5cb0ee1ac8ad13ca576 (diff)
downloadlinux-19c4d2f994788a954af1aa7e53b0fdb46fd7925a.tar.gz
Revert "btrfs: let btrfs_delete_unused_bgs() to clean relocated bgs"
This reverts commit 5d8eb6fe517583f9c6d5b94faf2254a0207a45c9.

When we remove devices, we free the device structures.  Delaying
btfs_remove_chunk() ends up hitting a use-after-free on them.

Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index b4048c1b3d9b..71a60cc01451 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2906,8 +2906,8 @@ out:
 static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
 {
 	struct btrfs_root *extent_root;
+	struct btrfs_trans_handle *trans;
 	int ret;
-	struct btrfs_block_group_cache *block_group;
 
 	root = root->fs_info->chunk_root;
 	extent_root = root->fs_info->extent_root;
@@ -2937,17 +2937,21 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
 	if (ret)
 		return ret;
 
+	trans = btrfs_start_trans_remove_block_group(root->fs_info,
+						     chunk_offset);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		btrfs_handle_fs_error(root->fs_info, ret, NULL);
+		return ret;
+	}
+
 	/*
-	 * step two, flag the chunk as removed and let
-	 * btrfs_delete_unused_bgs() remove it.
+	 * step two, delete the device extents and the
+	 * chunk tree entries
 	 */
-	block_group = btrfs_lookup_block_group(root->fs_info, chunk_offset);
-	spin_lock(&block_group->lock);
-	block_group->removed = 1;
-	spin_unlock(&block_group->lock);
-	btrfs_put_block_group(block_group);
-
-	return 0;
+	ret = btrfs_remove_chunk(trans, root, chunk_offset);
+	btrfs_end_transaction(trans, extent_root);
+	return ret;
 }
 
 static int btrfs_relocate_sys_chunks(struct btrfs_root *root)