summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Harmstone <mark@harmstone.com>2026-02-19 19:19:00 +0000
committerDavid Sterba <dsterba@suse.com>2026-03-17 11:43:08 +0100
commitadbb0ebacc3223a2dc2e58ef3d4c10f5e9653f09 (patch)
tree2a6a89d83f781932ae2bbaecc65a37fd2f7aa90d
parent057495ccc0ad381015b45d3edf995c2b6b982474 (diff)
btrfs: check block group before marking it unused in balance_remap_chunks()
Fix a potential segfault in balance_remap_chunks(): if we quit early because btrfs_inc_block_group_ro() fails, all the remaining items in the chunks list will still have their bg value set to NULL. It's thus not safe to dereference this pointer without checking first. Reported-by: Chris Mason <clm@fb.com> Link: https://lore.kernel.org/linux-btrfs/20260125120717.1578828-1-clm@meta.com/ Fixes: 81e5a4551c32 ("btrfs: allow balancing remap tree") Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Mark Harmstone <mark@harmstone.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/volumes.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 7efc2f7a9bb2..8fbd736aad9f 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4277,20 +4277,29 @@ static int balance_remap_chunks(struct btrfs_fs_info *fs_info, struct btrfs_path
end:
while (!list_empty(chunks)) {
bool is_unused;
+ struct btrfs_block_group *bg;
rci = list_first_entry(chunks, struct remap_chunk_info, list);
- spin_lock(&rci->bg->lock);
- is_unused = !btrfs_is_block_group_used(rci->bg);
- spin_unlock(&rci->bg->lock);
+ bg = rci->bg;
+ if (bg) {
+ /*
+ * This is a bit racy and the 'used' status can change
+ * but this is not a problem as later functions will
+ * verify it again.
+ */
+ spin_lock(&bg->lock);
+ is_unused = !btrfs_is_block_group_used(bg);
+ spin_unlock(&bg->lock);
- if (is_unused)
- btrfs_mark_bg_unused(rci->bg);
+ if (is_unused)
+ btrfs_mark_bg_unused(bg);
- if (rci->made_ro)
- btrfs_dec_block_group_ro(rci->bg);
+ if (rci->made_ro)
+ btrfs_dec_block_group_ro(bg);
- btrfs_put_block_group(rci->bg);
+ btrfs_put_block_group(bg);
+ }
list_del(&rci->list);
kfree(rci);