]> git.hungrycats.org Git - linux/commit
btrfs: stripe_alloc: hand groups full of trapped free space to the reclaim worker
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sun, 6 Sep 2026 18:23:37 +0000 (14:23 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 16 Sep 2026 21:40:05 +0000 (17:40 -0400)
commit8e4e954bce1290a384ca2ed371d96afe940c5db7
treefae9a2aa65ea2c7a560f8d14e3190d4040f22e88
parentfc7452d545a72cd6827b59c4dcc0a288ba462188
btrfs: stripe_alloc: hand groups full of trapped free space to the reclaim worker

Zoned filesystems mark a block group for reclaim as soon as its
unusable bytes reach bg_reclaim_threshold percent of its capacity, so
space that can no longer be written is recycled without an operator
running balance.  stripe_alloc had no equivalent.  The non-zoned
trigger consults the threshold only where a free drops a group's used
bytes across it, and the test hosts were already running every mount
with bg_reclaim_threshold=75 when this was measured: trapped tails
still accumulated until balance (1.86 GiB of 6.5 GiB after a few hours
of churn), while every byte-based check counted them as free, because
that predicate keys on used bytes only and fires only at the crossing
-- a group hollowed out after it was already below the threshold, or
one whose used bytes never moved while its stripes trapped, is never
queued, and a group at the same used fraction with nothing trapped is.

Mark a group for the existing reclaim worker when its trapped bytes
reach the threshold; the worker re-checks with
should_reclaim_block_group().  The predicate, factored out as
btrfs_stripe_bg_wants_reclaim(), compares the trapped bytes with the
group's free space (length minus used) rather than its length -- a
stripe_alloc group also holds claimable whole stripes, and in practice
fragmentation settles around two thirds of the group trapped with a
fifth used, nothing left worth writing into yet below any sensible
fraction of the length -- and requires room for the group's live data
in the rest of the claimable supply after the bytes already promised to
admitted writers, so a group that cannot be relocated is left alone
until space is freed instead of being retried every commit while the
read-only transitions starve writers.

The trigger runs from the cleaner, which the transaction thread wakes
every cycle whether or not a transaction exists, as well as at the
commit-time rescan: on an idle filesystem nothing rescans, and a group
already on another list (a chunk created in the running transaction is
still on trans->new_bgs) cannot be linked to the reclaim list, so the
five-minute hysteresis stamp is taken only when the mark actually
lands.  The worker re-checks whatever it takes, so a stale read costs at
most one wasted attempt.  bg_reclaim_threshold defaults to 0 on
non-zoned filesystems, so nothing changes until the sysfs knob is set;
the default is left for review.  Relocation needs inc_block_group_ro()
to succeed, hence the earlier fix.

Assisted-by: Claude:claude-fable-5
Assisted-by: Claude:claude-fable-5-1
fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/free-space-cache.c
fs/btrfs/free-space-cache.h