]> git.hungrycats.org Git - linux/commit
btrfs: stripe_alloc: never let relocation wait on the whole-stripe gate
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sat, 5 Sep 2026 16:16:00 +0000 (12:16 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Fri, 18 Sep 2026 21:36:25 +0000 (17:36 -0400)
commit57cf2488b8bc813b5e78544e548e5fb65c0127e5
treefd5e89c97e2f39100627c0e50304a386ad42eb12
parent0ce8a7297983709a4a84ecead3c92d38c8f09d1f
btrfs: stripe_alloc: never let relocation wait on the whole-stripe gate

The data admission gate refuses reservations that would not fit in the
whole-stripe supply, and a refused reservation waits as a flush ticket
for space to appear.  Relocation reserves its prealloc clusters through
the same path, so at the fill edge the reclaim worker sat for half an
hour in

  btrfs_reclaim_bgs_work -> btrfs_relocate_chunk -> relocate_block_group
    -> relocate_file_extent_cluster -> prealloc_file_extent_cluster
    -> btrfs_alloc_data_chunk_ondemand -> __reserve_bytes

holding the exclusive operation and the group it was emptying, while the
gate waited for exactly the stripes that relocation was supposed to
free.  User writers queued behind that head ticket and unmount hung on
their writeback.

Exempting relocation from the gate altogether is wrong too: it then
takes whole stripes that admitted writers were promised, and their
writebacks are dropped at the edge.  Give relocation its own flush type,
BTRFS_RESERVE_FLUSH_DATA_RELOC, that is subject to the same bound but
never waits: if the reservation does not fit beyond the bytes already
promised it fails at once, the relocation is abandoned cleanly and is
retried when the trigger next finds room.  Zoned relocation already
has a flush type of its own for the same reason.

Assisted-by: Claude:claude-fable-5
fs/btrfs/delalloc-space.c
fs/btrfs/space-info.c
fs/btrfs/space-info.h