summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>2026-02-10 14:04:22 +0300
committerDavid Sterba <dsterba@suse.com>2026-04-07 19:55:55 +0300
commit258e46a6385c57a3caef3fb1dc888e2efcfe5b18 (patch)
treee2aec2d6ef33947f48578cf09d973cbbe450b3f2
parent7bcb04de982ff0718870112ad9f38c35cbca528b (diff)
downloadlinux-258e46a6385c57a3caef3fb1dc888e2efcfe5b18.tar.xz
btrfs: zoned: move partially zone_unusable block groups to reclaim list
On zoned block devices, block groups accumulate zone_unusable space (space between the write pointer and zone end that cannot be allocated until the zone is reset). When a block group becomes mostly zone_unusable but still contains some valid data and it gets added to the unused_bgs list it can never be deleted because it's not actually empty. The deletion code (btrfs_delete_unused_bgs) skips these block groups due to the btrfs_is_block_group_used() check, leaving them on the unused_bgs list indefinitely. This causes two problems: 1. The block groups are never reclaimed, permanently wasting space 2. Eventually leads to ENOSPC even though reclaimable space exists Fix by detecting block groups where zone_unusable exceeds 50% of the block group size. Move these to the reclaim_bgs list instead of skipping them. This triggers btrfs_reclaim_bgs_work() which: 1. Marks the block group read-only 2. Relocates the remaining valid data via btrfs_relocate_chunk() 3. Removes the emptied block group 4. Resets the zones, converting zone_unusable back to usable space The 50% threshold ensures we only reclaim block groups where most space is unusable, making relocation worthwhile. Block groups with less zone_unusable are left on unused_bgs to potentially become fully empty through normal deletion. Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/block-group.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index a021a6dab8f9..d0d7051d4417 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -1613,6 +1613,24 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
spin_lock(&space_info->lock);
spin_lock(&block_group->lock);
+
+ if (btrfs_is_zoned(fs_info) && btrfs_is_block_group_used(block_group) &&
+ block_group->zone_unusable >= div_u64(block_group->length, 2)) {
+ /*
+ * If the block group has data left, but at least half
+ * of the block group is zone_unusable, mark it as
+ * reclaimable before continuing with the next block group.
+ */
+
+ spin_unlock(&block_group->lock);
+ spin_unlock(&space_info->lock);
+ up_write(&space_info->groups_sem);
+
+ btrfs_mark_bg_to_reclaim(block_group);
+
+ goto next;
+ }
+
if (btrfs_is_block_group_used(block_group) ||
(block_group->ro && !(block_group->flags & BTRFS_BLOCK_GROUP_REMAPPED)) ||
list_is_singular(&block_group->list) ||