aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2014-12-02 13:07:49 -0500
committerChris Mason <clm@fb.com>2014-12-02 21:35:10 -0500
commit8dbcd10f6978ca3ccee2f43288d16b7b9da2fb2b (patch)
tree88a5485643a8487ca6e3358d65a0a6fb21fa88dc /fs/btrfs
parent495e64f4fe0363bc79fa0dfb41c271787e01b5c3 (diff)
Btrfs: fix unprotected deletion from pending_chunks list
On block group remove if the corresponding extent map was on the transaction->pending_chunks list, we were deleting the extent map from that list, through remove_extent_mapping(), without any synchronization with chunk allocation (which iterates that list and adds new elements to it). Fix this by ensure that this is done while the chunk mutex is held, since that's the mutex that protects the list in the chunk allocation code path. This applies on top (depends on) of my previous patch titled: "Btrfs: fix race between fs trimming and block group remove/allocation" But the issue in fact was already present before that change, it only became easier to hit after Josef's 3.18 patch that added automatic removal of empty block groups. Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent-tree.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index ba7042e2390b..17b052ae4653 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -9514,19 +9514,25 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
9514 list_move_tail(&em->list, &root->fs_info->pinned_chunks); 9514 list_move_tail(&em->list, &root->fs_info->pinned_chunks);
9515 } 9515 }
9516 spin_unlock(&block_group->lock); 9516 spin_unlock(&block_group->lock);
9517 unlock_chunks(root);
9518 9517
9519 if (remove_em) { 9518 if (remove_em) {
9520 struct extent_map_tree *em_tree; 9519 struct extent_map_tree *em_tree;
9521 9520
9522 em_tree = &root->fs_info->mapping_tree.map_tree; 9521 em_tree = &root->fs_info->mapping_tree.map_tree;
9523 write_lock(&em_tree->lock); 9522 write_lock(&em_tree->lock);
9523 /*
9524 * The em might be in the pending_chunks list, so make sure the
9525 * chunk mutex is locked, since remove_extent_mapping() will
9526 * delete us from that list.
9527 */
9524 remove_extent_mapping(em_tree, em); 9528 remove_extent_mapping(em_tree, em);
9525 write_unlock(&em_tree->lock); 9529 write_unlock(&em_tree->lock);
9526 /* once for the tree */ 9530 /* once for the tree */
9527 free_extent_map(em); 9531 free_extent_map(em);
9528 } 9532 }
9529 9533
9534 unlock_chunks(root);
9535
9530 btrfs_put_block_group(block_group); 9536 btrfs_put_block_group(block_group);
9531 btrfs_put_block_group(block_group); 9537 btrfs_put_block_group(block_group);
9532 9538