Skip to content

Commit e96ea5f

Browse files
boryasjfvogel
authored andcommitted
btrfs: harden block_group::bg_list against list_del() races
[ Upstream commit 7511e29cf1355b2c47d0effb39e463119913e2f6 ] As far as I can tell, these calls of list_del_init() on bg_list cannot run concurrently with btrfs_mark_bg_unused() or btrfs_mark_bg_to_reclaim(), as they are in transaction error paths and situations where the block group is readonly. However, if there is any chance at all of racing with mark_bg_unused(), or a different future user of bg_list, better to be safe than sorry. Otherwise we risk the following interleaving (bg_list refcount in parens) T1 (some random op) T2 (btrfs_mark_bg_unused) !list_empty(&bg->bg_list); (1) list_del_init(&bg->bg_list); (1) list_move_tail (1) btrfs_put_block_group (0) btrfs_delete_unused_bgs bg = list_first_entry list_del_init(&bg->bg_list); btrfs_put_block_group(bg); (-1) Ultimately, this results in a broken ref count that hits zero one deref early and the real final deref underflows the refcount, resulting in a WARNING. Reviewed-by: Qu Wenruo <[email protected]> Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Boris Burkov <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]> Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit bf089c4d1141b27332c092b1dcca5022c415a3b6) Signed-off-by: Jack Vogel <[email protected]>
1 parent 163543a commit e96ea5f

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

fs/btrfs/extent-tree.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2897,7 +2897,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
28972897
block_group->length,
28982898
&trimmed);
28992899

2900+
/*
2901+
* Not strictly necessary to lock, as the block_group should be
2902+
* read-only from btrfs_delete_unused_bgs().
2903+
*/
2904+
ASSERT(block_group->ro);
2905+
spin_lock(&fs_info->unused_bgs_lock);
29002906
list_del_init(&block_group->bg_list);
2907+
spin_unlock(&fs_info->unused_bgs_lock);
2908+
29012909
btrfs_unfreeze_block_group(block_group);
29022910
btrfs_put_block_group(block_group);
29032911

fs/btrfs/transaction.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,13 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
161161
cache = list_first_entry(&transaction->deleted_bgs,
162162
struct btrfs_block_group,
163163
bg_list);
164+
/*
165+
* Not strictly necessary to lock, as no other task will be using a
166+
* block_group on the deleted_bgs list during a transaction abort.
167+
*/
168+
spin_lock(&transaction->fs_info->unused_bgs_lock);
164169
list_del_init(&cache->bg_list);
170+
spin_unlock(&transaction->fs_info->unused_bgs_lock);
165171
btrfs_unfreeze_block_group(cache);
166172
btrfs_put_block_group(cache);
167173
}
@@ -2099,7 +2105,13 @@ static void btrfs_cleanup_pending_block_groups(struct btrfs_trans_handle *trans)
20992105

21002106
list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) {
21012107
btrfs_dec_delayed_refs_rsv_bg_inserts(fs_info);
2108+
/*
2109+
* Not strictly necessary to lock, as no other task will be using a
2110+
* block_group on the new_bgs list during a transaction abort.
2111+
*/
2112+
spin_lock(&fs_info->unused_bgs_lock);
21022113
list_del_init(&block_group->bg_list);
2114+
spin_unlock(&fs_info->unused_bgs_lock);
21032115
}
21042116
}
21052117

0 commit comments

Comments
 (0)