Commit adbb0eba authored by Mark Harmstone's avatar Mark Harmstone Committed by David Sterba
Browse files

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: default avatarChris Mason <clm@fb.com>
Link: https://lore.kernel.org/linux-btrfs/20260125120717.1578828-1-clm@meta.com/


Fixes: 81e5a455 ("btrfs: allow balancing remap tree")
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarMark Harmstone <mark@harmstone.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 057495cc
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -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);
				btrfs_mark_bg_unused(bg);

			if (rci->made_ro)
			btrfs_dec_block_group_ro(rci->bg);
				btrfs_dec_block_group_ro(bg);

		btrfs_put_block_group(rci->bg);
			btrfs_put_block_group(bg);
		}

		list_del(&rci->list);
		kfree(rci);