From: Zygo Blaxell Date: Sun, 6 Sep 2026 04:10:38 +0000 (-0400) Subject: btrfs: stripe_alloc: let a data write fall back to the relocation group rather than... X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc7452d545a72cd6827b59c4dcc0a288ba462188;p=linux btrfs: stripe_alloc: let a data write fall back to the relocation group rather than drop Dedicating a group to relocation takes its claimable stripes away from every other writer at once. Admission stops counting them from then on, but a write admitted a moment earlier against exactly those stripes still has to be placed, and with the group hard-excluded it was not: ten milliseconds after "relocating block group 2976120832" a 16K writeback allocation returned ENOSPC and its data was dropped, the one drop left in a fill-to-the-edge run under reclaim. The read-only transition has a guard for this; the dedication had none. Keep the exclusion for the allocator's first passes and lift it once the search reaches the chunk-allocation loop, i.e. only when no other group can serve the write. The class tag on the stripe runs already guarantees the two sides never share a stripe, so the fallback costs relocation a few stripes, not its correctness. Zoned's hard exclusion follows from append-only zones, which do not apply here. Assisted-by: Claude:claude-fable-5 --- diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b64863ca066ac..5c8421b122448 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4119,8 +4119,23 @@ static int do_allocation_stripe(struct btrfs_block_group *block_group, } if (fs_info->data_reloc_bg && (ffe_ctl->for_data_reloc != - (block_group->start == fs_info->data_reloc_bg))) - skip = true; + (block_group->start == fs_info->data_reloc_bg))) { + /* + * Relocation stays in its group. Everyone else stays out of + * it only while the other groups can serve them: the + * dedication can land after a write was admitted against + * this group's stripes (the read-only guard covers that + * transition, not this one), and refusing the write here + * drops its data at writeback. The class tag on the runs + * keeps the two sides from ever sharing a stripe, so a + * last-resort allocation in the relocation group is safe, + * merely unhelpful to relocation. Zoned's hard exclusion + * follows from append-only zones, which do not apply here. + */ + if (ffe_ctl->for_data_reloc || + ffe_ctl->loop < LOOP_ALLOC_CHUNK) + skip = true; + } spin_unlock(&fs_info->relocation_bg_lock); if (dedicated_now && block_group->space_info) { /* its claimable stripes now belong to relocation alone */