]> git.hungrycats.org Git - linux/log
linux
3 days agobtrfs: stripe_alloc: hold a stripe of margin across a preallocation
Zygo Blaxell [Sat, 12 Sep 2026 00:27:55 +0000 (20:27 -0400)]
btrfs: stripe_alloc: hold a stripe of margin across a preallocation

Admission now charges a preallocation the roundup of its bytes to whole
stripes, but that charge lives only for the check: between the
reservation and the allocation only the raw bytes sit in bytes_may_use.
fallocate() is quick, but eight fsstress processes preallocating at the
fill edge were quick together, and each in-flight preallocation short of
a stripe still took a stripe the gate had counted for someone else: the
failure-time dump kept showing admitted writes with the supply gone.

Do for preallocation what the delalloc margin does per outstanding
extent: hold one stripe in bytes_stripe_margin from the successful data
reservation until the caller's allocations are done, at the four users
of btrfs_alloc_data_chunk_ondemand() -- fallocate's range loop, the
zero-range preallocation, relocation's cluster preallocation and the
encoded write's extent reservation.  Released as soon as the claims have
landed, so the hold costs nothing beyond that window.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: admit data reservations by whole stripes
Zygo Blaxell [Fri, 11 Sep 2026 22:25:09 +0000 (18:25 -0400)]
btrfs: stripe_alloc: admit data reservations by whole stripes

An allocation of N bytes that has to open a stripe run claims
round_up(N, full stripe) whole stripes.  A delalloc write is admitted
with a full-stripe margin per outstanding extent, which covers that
roundup for itself, and relocation is admitted for round_up(N) + 1
stripe.  A preallocation was admitted for N alone: fallocate() has no
outstanding extent and holds no margin, so each one short of a stripe
took up to a stripe more from the whole-stripe supply than the gate had
charged.  The supply behind writes admitted earlier shrank by that much
and at the fill edge their claims found nothing.

With the stranded-stripe accounting and the relocation margin in place,
the failure-time dump on a degraded fsstress fill showed exactly this:
every failed write had bytes_stripe_claimable 0, bytes_may_use equal to
its own size, one stripe of margin per outstanding extent, nothing
stranded, no group read-only and no relocation group dedicated -- the
gate's arithmetic was consistent and still the stripes were gone, with
a preallocation's reservation in flight in the dump.

Charge every non-relocation admission the roundup to whole stripes.  The
excess is not held past admission (a preallocation allocates in the same
call), so a concurrent admission in that window can still overrun by a
stripe; holding it would need the reservation to carry the roundup until
the allocation lands, a later refinement.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: charge the held stripe margin against every admission
Zygo Blaxell [Fri, 11 Sep 2026 16:36:25 +0000 (12:36 -0400)]
btrfs: stripe_alloc: charge the held stripe margin against every admission

The data admission gate is meant to refuse a write at reservation time
when the whole-stripe supply cannot cover it, so that write() returns
ENOSPC instead of writeback finding no stripe later.  It compared
bytes_may_use + bytes against bytes_stripe_claimable and left out
bytes_stripe_margin, the whole-stripe collateral every outstanding data
extent holds against the commit that closes its open run and traps the
tail.  The margin is charged against total_bytes through
btrfs_space_info_used(), but not against the supply the admitted bytes
actually draw on.

Each commit shrinks that supply by the trapped tails, with nothing
holding it, so at the fill edge a write that passed admission reached
find_free_extent() and failed: "data writeback allocation of 4096 bytes
returned ENOSPC despite reservation margin; buffered data in this range
will be dropped", followed by the cow_file_range() failures 35 seconds
later in the same fill.  Relocation was admitted the same way, against
supply the margin was reserving, and at the fill edge of a degraded
acceptance run it consumed the whole stripes that small writes' claims
then needed: about fifty 4-32 KiB writes per run failed at writeback in
bursts that tracked the block group relocations to the minute.

The margin is owed to writers already admitted, so every later
admission must respect it: add the held margin to the admitted bytes on
both the ordinary and the relocation path.  This over-refuses by the
margin, which the commit rescan raising bytes_stripe_claimable and the
FLUSH_DATA ticket retry heal, and stays within phase 1's pessimistic
contract; relocation that cannot be covered waits on its ticket like
anyone else, and the margin returns as the writes complete.

Assisted-by: Claude:claude-fable-5
Assisted-by: Claude:claude-fable-5-1
3 days agobtrfs: stripe_alloc: count nocow run lifecycles and stranded stripes in sysfs
Zygo Blaxell [Fri, 11 Sep 2026 13:27:32 +0000 (09:27 -0400)]
btrfs: stripe_alloc: count nocow run lifecycles and stranded stripes in sysfs

Add a stripe_run_stats file beside stripe_park_stats with lifetime
counters for the paths the previous two patches touched, so a test can
show that it exercised them rather than merely passed: private NOCOW
runs opened, claim candidates refused for overlapping a live run, bytes
of whole stripes the scans found stranded behind live runs, and rescans
requested by a freed run to credit its stripes back.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: give nocow extents a private run only while they may be written...
Zygo Blaxell [Fri, 11 Sep 2026 13:23:47 +0000 (09:23 -0400)]
btrfs: stripe_alloc: give nocow extents a private run only while they may be written in place

Preallocated extents and a nodatacow inode's extents are steered into a
per-inode NOCOW-class stripe run, so that their stripes never hold any
other file's data and an in-place write can be confined to the file that
waived COW protection.  Such a run survives transaction commits, so a
slowly appended nocow file does not burn a stripe per commit.

Both the steering and the survival were unconditional, but whether a
nocow extent can be written in place at all is decided by the
stripe_alloc_allow_rmw policy, and with nothing waived (the default)
btrfs_stripe_nocow_writable() forces COW for every such write.  The
private runs then hold only ordinary COWed extents and unwritten
preallocation, never in-place data, and their survival protects nothing:
it only keeps the run object alive until the inode is evicted, and every
whole stripe freed inside the run's range meanwhile -- a prealloc extent
overwritten by a COWed one, or unlinked -- is stranded, counted free but
refused to every claim.  An fsstress run on a filesystem filled to
ENOSPC left 387 and 976 such runs in single block groups, holding 99% of
the group's free whole stripes.

Steer into a NOCOW run only when the policy lets that kind of extent
(prealloc or nodatacow) be written in place, and let a NOCOW run outlive
commits only when the policy allowed in-place writes when the run was
opened.  The verdict is recorded in the run at open time so the commit's
close and settle predicates cannot disagree with each other when the
policy changes underneath them: a run opened under one policy keeps its
lifecycle until it is closed by filling up, by the inode's eviction or
by a forced quiesce.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: count whole stripes stranded behind live runs as trapped
Zygo Blaxell [Fri, 11 Sep 2026 12:59:09 +0000 (08:59 -0400)]
btrfs: stripe_alloc: count whole stripes stranded behind live runs as trapped

The data admission gate admits a reservation while the whole-stripe
supply, bytes_stripe_claimable, covers it, and the per-commit scan
measures that supply as the block group's wholly free full stripes.
But a wholly free stripe inside a live stripe run's range cannot be
claimed: btrfs_stripe_run_range_usable() rejects any claim overlapping
a run object, because a second run over the same range would make the
range-to-run lookups ambiguous.  The run was claimed over the stripe,
the extents allocated there were freed again, and the run has not been
freed yet.  For a COW run that window closes at the next commit; a
nodatacow inode's private run deliberately survives commits and lives
until the inode is evicted.

On a raid56 filesystem filled to ENOSPC by fsstress (thousands of
fallocated files, so thousands of cached inodes each holding a private
NOCOW run) a live walk of the free space cache showed the accounting
exact -- the wholly free stripes summed to bytes_stripe_claimable to the
byte -- and 99% of them inside the ranges of open NOCOW runs with no
inflight IO: 22.8 MiB of 22.8 MiB behind 387 runs in one group, 73.4 MiB
of 73.4 MiB behind 976 runs in another.  Every claim failed in O(1) on
the "no claimable run" verdict, every write() admitted against the 99 MiB
of phantom supply failed at writeback, and the data was dropped ("data
writeback allocation ... returned ENOSPC despite reservation margin"),
about 100,000 delalloc ranges per run of the degraded acceptance suite
where the stock allocator drops none.

Have the scan take such stripes out of the claimable supply: count them
in stripe_unusable, which btrfs_space_info_used() already charges so the
gate cannot admit against them, and record them separately as
stripe_stranded so that btrfs_stripe_bg_wants_reclaim() does not ask
relocation to recover space that comes back by itself.  When a run is
freed, mark its group for rescan so the next commit credits the stripes
back.  The space_info total is exposed as bytes_stripe_stranded in sysfs
and in the space info dump.

This makes the gate honest -- write() gets the ENOSPC instead of
writeback dropping the data -- but does not return the stranded space
while the runs live; that is the run lifecycle's business.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: do not read an inline backref off a keyed-ref extent item
Zygo Blaxell [Thu, 10 Sep 2026 14:53:38 +0000 (10:53 -0400)]
btrfs: stripe_alloc: do not read an inline backref off a keyed-ref extent item

stripe_extents_owned_by() decides whether every extent in a stripe range
belongs to one inode by reading the single inline backref of each data
extent item.  A data extent's only backref is keyed rather than inline
when the leaf had no room to grow the item: insert_inline_extent_backref()
returns -EAGAIN and insert_extent_backref() adds a separate
EXTENT_DATA_REF item.  Such an extent item ends right after the header,
so the walk read the next item's bytes as an inline ref and
btrfs_get_extent_inline_ref_type() warned:

  BTRFS error (device dm-22): eb 81657856 iref 0x3a5c invalid extent inline ref type 1
  WARNING: CPU: 6 PID: 199813 at fs/btrfs/extent-tree.c:380 btrfs_get_extent_inline_ref_type+0xe0/0x190
   stripe_extents_owned_by+0x270/0x310
   btrfs_alloc_from_inode_stripe_run+0x48e/0x6a0
   find_free_extent+0xf9b/0x1870
   btrfs_reserve_extent+0x214/0x890
   __btrfs_prealloc_file_range+0xf1/0x470
   btrfs_fallocate+0xa99/0x10f0

The answer was already the conservative "not owned" (the garbage type is
not EXTENT_DATA_REF_KEY), so only the warning and the taint were wrong.
Check the item size before reading the inline ref and treat a keyed-ref
extent as not owned.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: tell a dead tree block from a live one in the metadata RMW audit
Zygo Blaxell [Sun, 6 Sep 2026 13:01:40 +0000 (09:01 -0400)]
btrfs: stripe_alloc: tell a dead tree block from a live one in the metadata RMW audit

The audit reports any older-generation header under a read-modify-write
as a write hole, and counted over six hundred per metadata fill test.
Since runs close at every transaction and freed stripes are reclaimed
whole, most such headers belong to blocks that died with their stripe:
the stripe was claimed fully free, the dead blocks kept their headers,
and a torn parity write over them damages nothing a reader can reach.

Ask the committed extent tree, the witness a degraded read after a
crash would consult, whether the block is still referenced.  Count and
report a live one as before (now with its bytenr and reference count),
and count a dead one as meta_rmw_ghost without a warning.

A sector the run has already re-allocated in the current transaction
carries an extent item of the current generation for the new block
while the old header is still on disk (the new write has not landed):
that is not a live block either, so the item generation must match the
header generation.  Without that check every single-stripe run of the
current transaction reported its dead predecessors as holes (90 of 135
warnings in one fill test; the other 45 were the raid5 system chunk).

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: show per-group trapped bytes in the space info dump
Zygo Blaxell [Sat, 5 Sep 2026 09:50:30 +0000 (05:50 -0400)]
btrfs: stripe_alloc: show per-group trapped bytes in the space info dump

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: let a group go read-only for relocation against the reserve
Zygo Blaxell [Sun, 6 Sep 2026 13:54:37 +0000 (09:54 -0400)]
btrfs: stripe_meta: let a group go read-only for relocation against the reserve

The read-only guard keeps admitted bytes placeable by refusing to take a
group's usable free space out of the supply when the space_info could
not absorb it.  With the whole-stripe reserve counted as used, that
refusal comes by the width of the reserve at the fill edge: two
eligible metadata groups sat marked for reclaim through a 300 second
wait and the worker dropped each on inc_block_group_ro() -- the
space_info was 7 MiB short of the check with 376 MiB of whole stripes
claimable, 352 MiB of them the reserve that exists for this move.

Going read-only is the first step of relocation, so let the guard draw
on the reserve the way relocation's own reservations do.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: let the transaction machinery's own reservations draw on the...
Zygo Blaxell [Sun, 6 Sep 2026 11:44:45 +0000 (07:44 -0400)]
btrfs: stripe_meta: let the transaction machinery's own reservations draw on the reserve

With the whole-stripe reserve counted as used for everyone but the
relocation task, a committing transaction whose handle reserve runs dry
mid-COW gets ENOSPC from btrfs_use_block_rsv(): its NO_FLUSH fallback
reservation is refused as soon as the claimable supply is below the
reserve, and the global reserve behind it has been refilled by fiat
against stripes that do not exist.  Seen on the delete phase of the
metadata fill test with relocation running: claimable 163 MiB, reserve
352 MiB, delayed refs freeing the deleted leaves, and the extent tree
COW that freeing needs aborted the transaction with ENOSPC while
163 MiB of whole stripes sat unused (no allocator canary: the allocator
was never asked).

The reserve exists to hold back user operations so relocation and the
commit that follows it have room; it must not hold back the commit.
Let NO_FLUSH, FLUSH_LIMIT (delayed refs, delayed inodes) and EMERGENCY
reservations draw on it like relocation does.  They are bounded and
kernel-internal; user reservations (FLUSH_ALL, ALL_STEAL, EVICT, DATA)
still stop at the reserve.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: do not steal from the global reserve below the relocation reserve
Zygo Blaxell [Sun, 6 Sep 2026 05:14:43 +0000 (01:14 -0400)]
btrfs: stripe_meta: do not steal from the global reserve below the relocation reserve

With the whole-stripe reserve in place the fill stopped cleanly at the
edge: 374 MiB claimable, the reserve plus margin plus the outstanding
reservations, no canary, no abort.  Then the test deleted half of its
tiny files, and every unlink that the gate refused came back through
the global reserve steal, which does not look at stripes.  Deleting an
inline file is pure COW churn under stripe_meta: it frees no stripe,
since the leaf it lived in stays, and each transaction of unlinks takes
fresh stripes.  Metadata used did not move by a megabyte while the
claimable supply went from 374 MiB to zero, and the next commit aborted
with the canary ("claimable 0 open 1490944 trapped 1506082816").

Refuse the steal once the claimable supply is down to the relocation
reserve plus the claim margin.  The unlink fails with ENOSPC, which is
recoverable, instead of the abort, which is not, and the reserve stays
with the background relocation that is the only thing that turns
trapped space back into whole stripes.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: hold back whole stripes so tree blocks always land and trapped...
Zygo Blaxell [Sun, 6 Sep 2026 02:58:50 +0000 (22:58 -0400)]
btrfs: stripe_meta: hold back whole stripes so tree blocks always land and trapped groups can be reclaimed

Two failures at the metadata fill edge under stripe_meta, both seen
with the tiny-file fill test on raid5 metadata.

The first is a transaction abort.  A tree block is reserved in bytes
and admitted while claimable whole stripes cover the outstanding
reservations, but it is placed in whole stripes: the open run it would
have joined is closed at the transaction boundary, so every group
claims at least one fresh full stripe per transaction.  The last few
megabytes of claimable supply go to those claims, made for reservations
admitted earlier, and the next admitted tree block finds no stripe at
all ("stripe_meta: tree block allocation of 16384 bytes returned
ENOSPC: claimable 0 open 1622016 trapped 1614266368"), which aborts the
transaction.  Pre-pay two transactions' worth of claims -- twice the
number of writable groups times the widest full stripe -- in the
space_info's stripe margin, recomputed at each commit scan.  Best-fit
run selection opens a fresh run only when a group's runs are full, so
this is a few megabytes, not a fraction of the space_info.

The second is a filesystem that quietly runs out at half capacity.
COW frees trap stripes rather than free them: a stripe is claimable
again only once every tree block in it is dead, which random deaths in
a sixteen-block stripe essentially never achieve, so the METADATA
space_info settles around half used, half trapped and no claimable
stripe left (3.04 GiB metadata, 49% used, fs not writable, deletes
included).  Only relocation packs live tree blocks back into whole
stripes, and it needs the moved group's live bytes claimable elsewhere
before it starts -- by the time the trigger fires there is nothing
left.  Hold back a reserve of whole stripes -- the largest writable
group's length, capped at a quarter of the space_info, nothing with a
single group -- from every metadata reservation except those made by
the relocation task, identified by a task pointer that reloc_ctl
already implies.  Reservations admitted against the reserve reach the
same tickets, so the flag travels with the ticket.  The reserve is an
accounting hold-back, not a partition: a committing transaction still
allocates from those stripes when it must, and the next scan restates
the reserve from what remains.  Both counters are cleared when
stripe_alloc is turned off, since the scan that maintains them stops
with it.

The reserve is reported through sysfs as bytes_stripe_reserve and in
the space_info dump, whose stripe_claimable and stripe_margin values
were printed under each other's label.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: back the global reserve with usable stripes, and say when a tree...
Zygo Blaxell [Sat, 5 Sep 2026 09:59:56 +0000 (05:59 -0400)]
btrfs: stripe_meta: back the global reserve with usable stripes, and say when a tree block finds none

With trapped and open-run bytes counted as used in the METADATA
space_info, the overcommit check already admits tree block reservations
only against whole free stripes plus unallocated space, so no separate
metadata gate is needed.  Two loose ends remain.

btrfs_update_global_block_rsv() forces a chunk allocation when the
global reserve is at least the space_info's total, but under stripe_meta
the reserve can only be spent in whole stripes: compare it against the
capacity minus the trapped bytes so a metadata chunk is allocated while
unallocated space still exists, instead of the reserve running dry at
the fill edge.

And when a raid56 stripe_meta tree block allocation does fail with
ENOSPC -- which aborts the transaction -- print the stripe counters,
the metadata twin of the data-side "returned ENOSPC despite reservation
margin" warning, so an accounting hole is identifiable from the log.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_meta: maintain trapped free space for metadata groups like data
Zygo Blaxell [Sat, 5 Sep 2026 09:50:29 +0000 (05:50 -0400)]
btrfs: stripe_meta: maintain trapped free space for metadata groups like data

btrfs_block_group_init_stripe_unusable() arms stripe_meta groups and adds
their trapped bytes to the METADATA space_info, but the disarm, rescan
and commit-time scan only accept btrfs_is_stripe_alloc_bg() (DATA), so
a metadata group's contribution was frozen at its first value: never
updated as tree blocks were freed inside stripes, never dropped when the
group went read-only or was removed.  Tree blocks can only be placed in
fully free stripes, so the trapped bytes are as unusable as for data and
need the same maintenance.

Accept stripe_meta groups on the three maintenance paths, let the commit
scan sum METADATA space_infos, and apply the read-only subtraction to
the metadata branch of inc_block_group_ro() as well.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: relocate a queued stripe group even while it has reserved or...
Zygo Blaxell [Sun, 6 Sep 2026 05:14:31 +0000 (01:14 -0400)]
btrfs: stripe_alloc: relocate a queued stripe group even while it has reserved or pinned bytes

The reclaim worker defers any group that has bytes reserved or pinned,
on the theory that it was queued for falling below the used threshold
and may be about to go empty on its own.  A stripe_alloc or stripe_meta
group is queued for the opposite reason -- free space trapped in
partially used stripes, which no amount of waiting frees -- and under
COW churn a metadata group has blocks reserved or pinned at every
moment, so the worker skipped every one of seven queued metadata
groups for the whole of a fill-to-the-edge test and relocated none.
Relocation already waits for in-flight allocations and writers on its
own; take the group.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: hand groups full of trapped free space to the reclaim worker
Zygo Blaxell [Sun, 6 Sep 2026 18:23:37 +0000 (14:23 -0400)]
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
3 days agobtrfs: stripe_alloc: let a data write fall back to the relocation group rather than...
Zygo Blaxell [Sun, 6 Sep 2026 04:10:38 +0000 (00:10 -0400)]
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
3 days agobtrfs: stripe_alloc: keep the relocation group's stripes out of the admission supply
Zygo Blaxell [Sun, 6 Sep 2026 03:40:50 +0000 (23:40 -0400)]
btrfs: stripe_alloc: keep the relocation group's stripes out of the admission supply

do_allocation_stripe() dedicates one block group to data relocation
(fs_info->data_reloc_bg, as the zoned allocator does): while a
relocation runs, its allocations go only there and everyone else's skip
it, until the relocation finishes or the group fills.  The admission
gate did not know: it counted that group's claimable stripes in the
supply for ordinary writes.  At the fill edge with background reclaim
running, the dedicated group was the only one with claimable stripes
left, ordinary writes were admitted against them, and their writebacks
were dropped:

  stripe_alloc DROP DUMP: sinfo may_use 3837952 claimable 561053696 ...
    bg 7048265728 ... claimable 561053696 ... runs open   <- data_reloc_bg
    every other group: claimable 0

Track the dedicated group's claimable bytes in the space_info
(bytes_stripe_claimable_reloc: set when a group is dedicated, cleared
when the dedication is released or the group is removed, followed by
the per-group claimable deltas and re-summed by the commit rescan) and
admit ordinary reservations against the supply minus that amount.

Relocation itself is admitted against the whole supply, dedicated group
included.  Confining it to the dedicated group's bytes was tried first
and refused relocation as soon as that group -- the first one the
allocator visits, often holding only a couple of free stripes -- ran
short of a reservation's whole stripes plus one, while hundreds of
megabytes of whole stripes sat in other groups: the allocator would
have dropped the dedication and moved on had it been asked, but the
gate failed each queued group with ENOSPC within fifteen milliseconds
and the reclaim worker retried every thirty seconds, with no relocation
ever completing.  bytes_may_use is one counter for both sides, so the
sum admitted still fits in the supply.

Assisted-by: Claude:claude-fable-5
Assisted-by: Claude:claude-fable-5-1
3 days agobtrfs: stripe_alloc: charge relocation a margin per reservation, not per extent
Zygo Blaxell [Sat, 5 Sep 2026 18:50:03 +0000 (14:50 -0400)]
btrfs: stripe_alloc: charge relocation a margin per reservation, not per extent

The stripe margin is one full stripe per outstanding extent, collateral
for the tails a commit traps under delalloc that has not been placed
yet.  The data relocation inode charged it too, for extents that are
already allocated: relocating a group of 16-48K files inflated
bytes_stripe_margin to 150 MB, more than the claimable supply, so the
next cluster reservation failed at once and the reclaim trigger retried
the same six groups 130 times in 15 minutes while the margin swung
between zero and 150 MB with nothing dirty.

Do not charge the per-extent margin for the data relocation root.
Instead, when a relocation reservation is checked against the
whole-stripe supply, round it up to whole stripes and add one stripe of
collateral, which is what relocation's own open runs can lose at the
next commit.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: give a queued stripe group a chunk to relocate into when the...
Zygo Blaxell [Mon, 7 Sep 2026 11:33:59 +0000 (07:33 -0400)]
btrfs: stripe_alloc: give a queued stripe group a chunk to relocate into when the supply is short

A relocation data reservation never takes a ticket, so the flush state
machine never runs for it, and with it goes the chunk allocation every
other data reservation gets when its space_info is full.  That did not
show while other groups still had whole stripes.  Once the reclaim
worker had emptied and removed five of seven data groups, the two left
were the trapped ones it was queued to move next, their claimable
supply was under a megabyte, and every relocation failed with ENOSPC
while 2.6 GiB of the devices sat unallocated.

Have the reclaim worker allocate one chunk before it relocates a stripe
group whose live bytes exceed the claimable supply of the other groups.
An earlier version did this from the reservation path instead, for any
refused relocation reservation; that let a live device shrink -- which
relocates into space it does not have and is meant to fail cleanly at
that reservation -- grow the data space_info chunk by chunk until the
raid1 metadata had nowhere to go and the relocation aborted the
transaction in merge_reloc_roots() (6.18 acceptance suite T6).  The
worker is the one caller that should be making room.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: never let relocation wait on the whole-stripe gate
Zygo Blaxell [Sat, 5 Sep 2026 16:16:00 +0000 (12:16 -0400)]
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
3 days agobtrfs: stripe_alloc: keep the admitted bytes placeable when a group goes read-only
Zygo Blaxell [Sat, 5 Sep 2026 12:17:26 +0000 (08:17 -0400)]
btrfs: stripe_alloc: keep the admitted bytes placeable when a group goes read-only

inc_block_group_ro() checks that the rest of the space_info can absorb
the group's free space in bytes.  Under stripe_alloc the data admission
gate promised writers whole stripes: bytes_may_use plus the held margin
against bytes_stripe_claimable.  Making a group read-only removes its
claimable stripes from that supply after the promise was made, so with
the reclaim worker relocating a group at the fill edge, admitted
writebacks found no stripe and were dropped:

  allocation failed flags 129, wanted 8192 ...
  space_info DATA has 450560 free, is full ... block group ... [readonly]

Refuse the read-only transition while the admitted bytes would no
longer fit in the claimable supply without this group.  Scrub, balance
and reclaim retry later; this is the fail-early direction and only bites
transiently at the edge, since bytes_may_use drains as writeback
completes.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: do not count trapped free space twice when making a block group...
Zygo Blaxell [Fri, 4 Sep 2026 23:13:05 +0000 (19:13 -0400)]
btrfs: stripe_alloc: do not count trapped free space twice when making a block group read-only

inc_block_group_ro() refuses to make a data block group read-only
unless the other groups of the space_info have at least as much free
space as this group is withdrawing: a read-only group's free space
leaves the pool writers allocate from, data never overcommits, and the
check (sinfo_used + num_bytes <= total_bytes) keeps concurrent writers
from failing allocations they could otherwise have been placed in while
the group is read-only.  Scrub takes the same path as balance, since
the space is demanded for those writers, not for moving data.

With stripe_alloc, the part of this group's free space that is trapped
in partially used stripes is already counted in btrfs_space_info_used()
through bytes_stripe_unusable, and it is also part of num_bytes, so the
check demands room elsewhere for those bytes twice -- although once the
group is read-only its trapped bytes leave the aggregate anyway, and
writers never had them to begin with.  A fragmented raid56 data group
could therefore never be made read-only.

RAID56 groups must be read-only for scrub: scrub keeps its own copy of
the stripe, which a concurrent read-modify-write would corrupt, so
unlike other profiles it cannot proceed without the flag.  On a
filesystem whose data groups had been churned (2.98 GiB group, 51%
used, 1.47 GiB of the remainder trapped) every device's scrub failed
with

  BTRFS warning: scrub: failed setting block group ro: -28

while the same filesystem without stripe_alloc scrubbed at 100% used.
Device replace takes the same path.  Freeing space made scrub work
again.

Subtract the group's own trapped bytes from the space it needs to find
elsewhere.  The counter may lag the space_info total between commits;
the check is a buffer heuristic, and the bound by num_bytes keeps it
from going negative.

Assisted-by: Claude:claude-fable-5
Assisted-by: Claude:claude-fable-5-1
3 days agobtrfs: stripe_alloc: drain the legacy allocator's writes before arming the write...
Zygo Blaxell [Sat, 12 Sep 2026 21:22:55 +0000 (17:22 -0400)]
btrfs: stripe_alloc: drain the legacy allocator's writes before arming the write-hole check at a runtime enable

Enabling stripe_alloc on a live filesystem (the btrfs.stripe_alloc property)
flips the mount option while the legacy allocator may still have writes in
flight.  Those extents sit in partly used stripes that no stripe run covers,
so the first of them to reach rmw_rbio() after the flip trips
btrfs_stripe_check_write()'s "write to stripe outside any live stripe run"
WARN_ONCE and taints the kernel, although nothing violated the policy: the
data was placed before the policy existed.  punch-hole-warn-repro.sh hits it
on the switch when its killed writers still have dirty data (bhive, 7.3-rc2
lane, 2026-09-12); the same code on 6.18 escaped only by timing.

Keep the check off from the flip until every ordered extent that could have
been allocated before it has completed.  The property is applied inside a
transaction, where flushing delalloc cannot wait, so the drain runs in a
worker: start delalloc on all roots, wait for all ordered extents, clear the
flag.  Extents allocated after the flip have stripe runs and are unaffected;
a mount-time enable (the root directory's property) has nothing in flight and
does not queue the drain.  close_ctree() flushes the worker so it cannot
outlive the filesystem.

Assisted-by: Claude:claude-fable-5-1
3 days agobtrfs: stripe_meta: allocate tree blocks by whole stripes
Zygo Blaxell [Sun, 9 Aug 2026 22:05:48 +0000 (18:05 -0400)]
btrfs: stripe_meta: allocate tree blocks by whole stripes

Metadata gets the placement rule data already has: tree blocks are handed
out from runs of fully free stripes, and a stripe is never revisited once
the transaction that filled it has written it.  No separate mount option: the
chunk profile already decides it.  raid56 metadata has the same write hole
as raid56 data, so it gets the same protection at the same time, and
metadata on any other profile has no write hole to close -- the policy's
RAID56_MASK test simply does not match it, so nothing changes there.

It does cost a stranded stripe tail per commit, and a metadata allocation
that fails aborts the transaction rather than failing one write.  Those
are the price of covering raid56 metadata at all rather than a reason to
make it opt-in separately: a filesystem unwilling to pay them does not
want raid56 metadata, and converting it to raid1c3/raid1c4 removes both
the cost and the write hole.

Only system chunks are left uncovered: btrfs_is_stripe_meta_bg() tests the
METADATA flag and a system chunk does not carry it, so a raid56 system
chunk keeps the legacy read-modify-write.  The mount-time warning is
narrowed to say exactly that instead of claiming metadata is uncovered,
which it no longer is.

The machinery is the data machinery, including the per-sector liveness
map the previous patch gave it.  Metadata needed three things of its own:

 - A completion report.  A run drains when every byte allocated from it
   has been accounted for, and metadata had no equivalent of ordered
   extent completion, so its runs could never drain -- the deadlock that
   mixed block groups hit.  end_bbio_meta_write() now reports, and
   btrfs_open_stripe_write_abandoned() covers a tree block freed before
   it was ever written (COWed twice in one transaction, say).

 - A two-phase closure.  btrfs_retire_open_stripes() runs before the
   commit writes tree blocks, so it skips metadata runs; they are closed
   and drained afterwards by btrfs_retire_meta_stripes(), once every block
   is on disk.  Closing earlier would strand blocks the commit has not
   allocated yet, draining earlier would wait for writes it has not
   issued.  Metadata runs are also freed there rather than when their
   counter reaches zero: a stripe's columns can be written by separate
   rbios, and freeing on the first completion leaves the second with no
   run to pad or merge against.

 - Whole stripes per writeback pass.  The opportunistic writeback passes
   do not know about stripes and will happily write three tree blocks now
   and five later; btrfs_defer_stripe_meta_write() leaves the blocks
   dirty for the commit (or a WB_SYNC_ALL waiter) instead, the same shape
   as the zoned write-pointer deferral.

Two free paths bypass the usual completion reporting and must report the
block abandoned themselves: btrfs_free_tree_block() can send a
same-transaction unwritten block through the delayed-ref machinery when
check_ref_cleanup() finds its ref head already processed, and
clean_log_buffer() discards unwritten log tree blocks via
btrfs_pin_reserved_extent() without ever visiting btrfs_free_tree_block().
Either miss leaves the block counted as inflight forever: the run never
drains, the block group reference never drops, and unmount asserts.  Both
were found by the dm-log-writes replay matrix, whose crash-recovery mounts
exercise both paths routinely.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: cache a failed stripe run scan per block group
Zygo Blaxell [Sun, 16 Aug 2026 07:54:18 +0000 (03:54 -0400)]
btrfs: stripe_alloc: cache a failed stripe run scan per block group

On a large aged filesystem (85 TiB, mostly legacy pre-stripe_alloc data,
heavily fragmented free space), the delalloc workers spin at 100% CPU
while commits crawl at KiB/s.  NMI backtraces put the time in
btrfs_claim_free_stripe_run() called from btrfs_alloc_from_open_stripe()
for every small compressed extent allocation.

The cost is in find_free_stripe_run_slow(): when the single-entry fast
path misses (always, on fragmented block groups), the slow path walks
candidate stripes from the START of the block group, doing an rbtree
lookup per free-space piece, all under ctl->tree_lock.  When the block
group has no claimable run at all - the common case for block groups
filled with legacy data - the scan traverses the entire block group,
returns -ENOSPC, and remembers nothing: the next 4K allocation repeats
the whole scan.  Per-allocation cost is O(block group size) in the
fragmented worst case, multiplied by every block group find_free_extent
visits.

The stock allocator avoids exactly this pathology by caching the largest
extent a failed search saw (max_extent_size); the stripe claim path is a
new search primitive built beside it and never inherited the idea.  The
per-block-group stripe_claimable counter cannot serve this role: it is a
commit-scan-granular byte estimate that can err high (block groups where
the accounting promises claimable bytes but the scan finds no aligned,
usable run are precisely where the scan storm happens).

Add bg->max_claimable_run, an upper bound learned from the scans
themselves: (u64)-1 unknown, 0 after an exhaustive scan proved no
claimable run exists (find_free_stripe_run_slow() accepts any run of at
least one full stripe, so its failure is that proof).  Claims fail in
O(1) while the bound is below one full stripe, or when total free space
in the block group is smaller than a full stripe.  Adding free space
resets the bound to unknown in __btrfs_add_free_space(), which covers
all paths that can create a run: frees, unpins, and stripe run returns.
The bound is only trusted and only set once the block group is fully
cached, because cache loading links entries directly and would bypass
the reset.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: gate data admission on claimable whole-stripe supply
Zygo Blaxell [Fri, 14 Aug 2026 01:12:02 +0000 (21:12 -0400)]
btrfs: stripe_alloc: gate data admission on claimable whole-stripe supply

Wire stripe_claimable into the DATA reservation path so write() returns -ENOSPC
when there is no fully-free whole stripe to place the write crash-safely --
matching statfs f_bavail, which already subtracts the trapped partial-stripe
space.  Add stripe_claimable_admit() and AND it into the two data-admit sites:
__reserve_bytes() and btrfs_try_granting_tickets() (the latter is required, or a
flushed data ticket would be granted by the plain used<=total rule, bypassing the
gate).  Scoped to raid56 stripe_alloc DATA (stripe_margin_unit != 0); metadata,
non-raid56 and zoned space_infos are unaffected.

The gate refuses at reservation time, before the range becomes delalloc and later
parks at writeback with nowhere to land -- so ENOSPC is clean and there is no
fill-edge parking collapse.

Phase 1 is pessimistic: it gates on bytes_stripe_claimable alone, which errs LOW,
so it can refuse a write that would have landed in a partially-open stripe
(over-refuses by the open remainder, healed by the commit rescan raising claimable
and the FLUSH_DATA ticket retry).  A later change adds bytes_stripe_open to the
bound for statfs-exact behavior.

Assisted-by: Claude:claude-opus-4-8
3 days agobtrfs: raid56: adaptive park deadline from the parked-rbio backlog
Zygo Blaxell [Tue, 11 Aug 2026 06:53:38 +0000 (02:53 -0400)]
btrfs: raid56: adaptive park deadline from the parked-rbio backlog

Full-stripe batching parks a sub-stripe write's rbio for a deadline so the
writes that fill the rest of its stripe can merge into it, turning a
read-modify-write into one full-stripe write.  The deadline is a fixed
per-filesystem value.  It is long enough to catch those merges, but at a
small-file fill to ENOSPC -- where a run's stripes never fill because each
file's neighbours land in the next file's stripe rather than this one --
every partial write waits the deadline out, and then its 10x stuck cap, on
an arrival that never comes before padding to a full stripe and going down.
Lowering the deadline globally fixes that fill but throws away the merges
the deadline exists to catch on ordinary moderate writes.

Feed the deadline back from the parking machinery's own backlog instead of
guessing at the workload.  Track stripe_parked_now, the number of
currently-parked rbios, incremented as a partial write parks and
decremented as it unparks.  When it runs ahead of the stripe_park_congestion
knob (0 disables it, the default), a new async partial write takes the short
sync deadline through the existing sync-park path rather than the full one.
This is negative feedback: the shorter deadline drains the backlog, so once
it falls back below the knob later writes regain the full deadline and full-
stripe batching.  No space-state estimate is needed -- a small-file flood
builds the backlog directly, while a large sequential fill (already full
stripes, never parked) and a moderate steady stream do not.

Measured on an eight-device raid5.  A small-file balance-reclaim soak that
times out at the default deadline completes at a congestion of 4; on a
throttled moderate stream, where the backlog stays low, a congestion of 32
never trips, keeps the full deadline, and merges three times as much with
38% fewer RMW reads as the same filesystem under a flat 3ms deadline.  The
gauge and a congestion_short counter join the stripe_park_stats sysfs file
so the knob can be set from measurement.  Off by default, and no data-path
change: a shortened park still pads or reads exactly as it would have, only
sooner.

Assisted-by: Claude:claude-opus-4-8
3 days agobtrfs: stripe_alloc: count claimable whole-stripe supply directly
Zygo Blaxell [Sun, 9 Aug 2026 22:05:44 +0000 (18:05 -0400)]
btrfs: stripe_alloc: count claimable whole-stripe supply directly

Data reservations are admitted against arithmetic -- free space minus
trapped fragments minus open-run remainders minus a per-extent margin --
and under sustained near-full churn the arithmetic and the claim rule
disagree for long enough that admitted buffered writes reach writeback
with nothing claimable left: measured, ~5.2-5.5k reserved writebacks
dropped per fsstress churn run, silently for anything not waiting on
fsync.  Stock refuses the same write()s up front.  Nothing between
"durable by fsync" and "refused by write()" is acceptable when an
operator accident fills the disk.

First step, accounting only: measure the constraint instead of deriving
it.  bg->stripe_claimable counts bytes of fully free whole stripes --
exactly what btrfs_claim_free_stripe_run() can take, the complement of
stripe_unusable within each stripe.  The commit rescan derives it from
the same pass that computes trapped bytes (free minus trapped) and is
the sole upward correction; incremental maintenance under
ctl->tree_lock only ever DEBITS -- removals round their decrement OUT
to every touched stripe, claims subtract exactly what they took.  The
counter can therefore only under-count between commits, never
over-count.

Crediting freed whole stripes incrementally on the add side is
deliberately not done, having been tried and dropped.  Several add
paths re-add free space that a low-level remove never de-credited --
the async discard trim (unlink_free_space / bitmap_clear_bits, then
do_trimming's re-add through __btrfs_add_free_space) and
btrfs_remove_free_space's middle-split tail re-add -- so crediting on
add double-counts and drives the counter ABOVE the authoritative scan.
That is the dangerous direction: once admission gates on this counter,
an over-count admits reservations against phantom supply that writeback
then drops, while an under-count is an early, clean write()-time
ENOSPC.  Debit-only makes over-counting structurally impossible,
whatever a future re-add path forgets to de-credit.  (Reproduced with
compress+autodefrag+discard=async on a legacy-converted raid5
filesystem, incremental ~= 2x scanned; credit_return attribution
confirmed the phantom entered through do_trimming's re-add, not the
open-stripe allocator returns.)

A WARN_RATELIMIT at the rescan catches the dangerous direction anyway
(incremental above scanned), which under a debit-only rule means a
missed consumption site, and localizes it; the clamp to the scanned
value keeps every rescan authoritative regardless.  Rate limited rather
than _ONCE because such a gap recurs on every commit, and reporting
only the first hit hides that it is ongoing.

The space_info aggregate bytes_stripe_claimable follows the
stripe_unusable pattern (incremental between commits, re-totaled from
armed groups at the rescan), shows in the ENOSPC dump and in sysfs.
No admission change yet; that comes once the counter proves accurate
under the fill, churn, balance and reclaim suites.  The by-size
fast-fail in the claim keeps its early exit: the point of measuring is
to make such inputs trustworthy, not to search harder around them.

Data block groups only for now; raid56 metadata and mixed block groups
join when the data counter has settled.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: track per-sector liveness and pad from the map
Zygo Blaxell [Sun, 9 Aug 2026 03:14:23 +0000 (23:14 -0400)]
btrfs: stripe_alloc: track per-sector liveness and pad from the map

Padding used to ask where the run's allocation frontier was, which
cannot see an allocation abandoned below it -- a reservation released, an
allocation the finder discarded, an extent freed before its write was
ever issued.  Runs now carry a bit per sector, set at allocation and
cleared by the new btrfs_open_stripe_write_abandoned() report, and
padding fills exactly the sectors that are dead: this replaces
btrfs_stripe_run_pad_start() with btrfs_stripe_run_pad_mask().  The map
is sized once, with headroom for frontier growth, because the growth
path holds the run lock where nothing may sleep; a run that would
outgrow its map stops growing instead.  A closed run's final stripe
overhangs its shrunk end by construction, and those sectors -- the
returned tail, unclaimable while the stripe holds live data -- are dead
and paddable too.

The abandonment report is what closes a writeback ENOSPC race the
fsync-heavy near-full workload hits: an allocation undone without a
report left phantom inflight bytes and phantom-live sectors, and
reservations admitted against that state failed at writeback
(cow_file_range -28) where stock refuses the write() up front.  With
the report in place the same workload shows zero writeback failures at
every reservation margin setting, including margin disabled.

Claiming also learns an O(1) fast fail: the by-size index walk is
extracted into find_free_stripe_run(), stopping at the first entry whose
largest contiguous free run cannot hold a full stripe -- near-full, where
free space degenerates into many sub-stripe holes, this replaces a scan
of the whole tree on every allocation.

Moved out of the stripe_meta patch, which needs all of this for tree
blocks but introduced it tangled with the metadata machinery; data wants
it on its own.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: complete parked writes on allocation coverage, not clocks
Zygo Blaxell [Sat, 8 Aug 2026 15:27:36 +0000 (11:27 -0400)]
btrfs: stripe_alloc: complete parked writes on allocation coverage, not clocks

A parked partial-stripe write goes down its RMW path when its deadline
expires or a retirement flush kicks it, even when every byte it is
missing below the run's frontier belongs to an allocation whose data IO
is already in flight -- allocation happens at writeback submission, and
the commit's retirement drain waits for exactly those arrivals.  Timing
out such a park buys nothing and costs a stripe read plus a second write
of the same stripe: measured on an 8-device raid5 buffered fill, the
100ms deadline turns ~2200 parked stripes per 2GB into read-modify-
writes (pad_decline_live), and stretching the clock 20x recovers only
14% -- the clock is the wrong instrument.

Replace the clock with a coverage test.  A parked rbio is ready when its
gathered bios cover everything the covering run has allocated inside its
stripe (btrfs_stripe_run_alloc_ceiling); the remainder lies at or past
the frontier, so the existing pad turns it into a single full-stripe
write with no read phase.  Merges check readiness as they land, the park
timer holds unready parks instead of expiring them, and run-retirement
flushes leave unready parks parked: the retirement has already closed
the run (freezing the allocated prefix) and its drain waits on the very
arrivals that will complete them.  Waiter-driven flushes (fsync's
pre-writeback kick, ordered-extent waits) and sync parks keep today's
forced behaviour: a blocked waiter's latency beats a saved stripe read.

A stuck cap (10x the park deadline) bounds the wait when an arrival can
never come: a writeback error abandoned the allocation, or the stripe
was already written once by a forced sync park.  Such parks are forced
down the old path and counted.

New sysfs stripe_park_stats counters: unparked_ready (parks completed by
the coverage test) and stuck (parks forced at the cap).

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: trace why padding declined, at the moment it declined
Zygo Blaxell [Sat, 8 Aug 2026 07:57:22 +0000 (03:57 -0400)]
btrfs: stripe_alloc: trace why padding declined, at the moment it declined

The counters say how often padding refused and broadly why, but not what
the run looked like when it happened, and reconstructing that from the
extent tree afterwards cannot distinguish "the stripe was already
allocated when this write arrived" from "it was allocated shortly after".
Those want different fixes, so record the decision where it is made.

Also count the second refusal, which had no counter at all: the oracle can
allow padding and the sector walk still refuse, because a sector below the
frontier is not covered by this write.  That is the case where another
allocation shares the stripe and its data is not in this rbio -- a
different thing from the oracle finding the whole stripe allocated.

The tracepoint carries the stripe, how much of it this write covers, the
refusal reason, and the run's start/end/frontier/inflight, so a trace says
directly whether the frontier had already run past the stripe when the
write showed up.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: tunable park deadlines, and say why padding declined
Zygo Blaxell [Sat, 8 Aug 2026 06:03:40 +0000 (02:03 -0400)]
btrfs: stripe_alloc: tunable park deadlines, and say why padding declined

The deadline constants are meant to be judged "from measurements rather
than taste", but they are compile-time, so every data point costs a kernel
build and a reboot.  Measuring a buffered fill -- dd, no fsync, so nothing
kicks the park and the backstop is the only exit -- found 1861 of 3984
parks expiring at the 100ms deadline, which is precisely the no-waiter case
the constant exists for and the one with no numbers behind it.

Expose both deadlines as writable sysfs files, clamped to 60s because a
parked rbio holds its stripe lock, with 0 disabling parking for that class
(useful as an experiment in itself):

  /sys/fs/btrfs/<uuid>/stripe_park_timeout_ms       (default 100)
  /sys/fs/btrfs/<uuid>/stripe_park_sync_timeout_ms  (default 3)

Add the counters the stats file cannot supply.  rmw_reads counts only
parked writes that still had to read, so it cannot answer "does this
workload read-modify-write at all"; data_rmw counts every data RMW, which
with allow_rmw empty on a covered block group is the number the
stripe-exclusive claim is about, and it should be zero.

And record why padding refused, because the reasons are different defects:
the rest of the stripe is allocated and its data has not arrived yet
(wait longer, or kick when the frontier advances); no open run covers the
stripe, so the run closed before its own write went down; or the frontier
never reached the stripe at all.  Attributing them turns "some RMW
remains" into a specific thing to fix.

No behaviour change at the defaults.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: say whether a metadata read-modify-write is a write hole
Zygo Blaxell [Wed, 5 Aug 2026 22:15:06 +0000 (18:15 -0400)]
btrfs: raid56: say whether a metadata read-modify-write is a write hole

meta_rmw counts sub-stripe metadata writes, which is a proxy for exposure
rather than a measurement of it.  A stripe modified in place is only a write
hole if it holds data some completed transaction is relying on; a stripe
that two writes of the *same* transaction happen to split costs an extra
read but risks nothing, because a tear loses that whole transaction anyway.
The counter cannot tell those apart, so it cannot answer the only question
that matters.

The rbio can.  A read-modify-write has already read every column the write
does not cover, so at the point of the report it is holding the stripe's
on-disk contents.  Walk the uncovered tree block positions and read their
headers: a block whose bytenr and fsid match belongs there, and its
generation says which transaction put it there.  Compare that against the
generation of the blocks this write is carrying, taken from the same rbio,
so a transaction committing concurrently cannot skew the verdict:

  meta_rmw_cur   the same transaction's own blocks -- a cost
  meta_rmw_old   an earlier transaction's -- a write hole
  meta_rmw_free  no tree block there at all

System block groups are classified too, not just metadata ones.  A system
chunk carries no METADATA bit, so a flags test excludes it, but it holds
the chunk tree: the same tree block header, the same generation field, and
a worse consequence if a degraded crash tears it, since without the chunk
tree no logical address can be mapped at all.  meta_rmw already counted
system chunks; only the classification skipped them, so their read-modify-
writes were visible as a rate and never as a verdict.  Whether a raid56
system chunk ever rewrites parity over a committed tree block is therefore
an open question that this answers by measurement rather than by reasoning
about how the chunk tree is laid out.

This trusts nothing the allocator says about itself.  The stripe runs, the
liveness map and the drain accounting are all bookkeeping that could be
wrong in the same way twice; the header in the sector is what a degraded
read would actually have to reconstruct.

On a 3-device raid5 filesystem with raid5 metadata, 6000 small files with
periodic syncs and then a third rewritten, plain stripe_alloc reports 249
sub-stripe metadata writes of which 174 rewrite parity over committed tree
blocks.  Adding stripe_meta leaves 37 sub-stripe writes and none of them.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: report read-modify-write of uncovered stripes
Zygo Blaxell [Tue, 4 Aug 2026 19:51:54 +0000 (15:51 -0400)]
btrfs: stripe_alloc: report read-modify-write of uncovered stripes

The mount-time warning says which block groups stripe_alloc does not
cover.  It cannot say whether anything is actually landing there, and on
a filesystem with raid56 metadata that is the interesting question: every
sub-stripe write to an uncovered stripe is a write hole window, where
parity and data reach the disk separately and a crash in between leaves
the stripe unreconstructible.

Report it from the one place that knows the write is going out as a
read-modify-write rather than as a full or padded stripe.  Rate limited,
because a raid56-metadata filesystem does this continuously and the point
is to make the exposure visible rather than to fill the log, and paired
with a meta_rmw counter in the existing stripe_park_stats sysfs file so
the rate can be read off without grepping dmesg.

Silent when stripe_alloc is off: there the whole filesystem works this
way and the user has asked for nothing else.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: warn at mount when raid56 metadata is not covered
Zygo Blaxell [Tue, 4 Aug 2026 06:43:20 +0000 (02:43 -0400)]
btrfs: stripe_alloc: warn at mount when raid56 metadata is not covered

stripe_alloc closes the write hole for raid56 data.  It does nothing for
raid56 metadata, which keeps read-modify-write and keeps the hole, and
on a mixed-block-group filesystem it now does nothing at all.  A user
who mounts -o stripe_alloc on -d raid5 -m raid5 has every reason to
believe the filesystem is covered, and finds out otherwise only after a
crash on a degraded array -- with metadata damage, which is worse than
the data damage they were protecting against.

Say it once at mount, after the block groups are read, so the message
reflects what is actually on disk rather than what was asked for.  A
warning, not an error: the data guarantee is real and worth having on
its own, and a filesystem can be converted to raid1c3/raid1c4 metadata
without unmounting.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: claim fully-free stripes that span free space entries
Zygo Blaxell [Fri, 7 Aug 2026 01:35:56 +0000 (21:35 -0400)]
btrfs: stripe_alloc: claim fully-free stripes that span free space entries

The claim fast path searches single entries, so a fully-free full
stripe whose free space spans an entry boundary -- an extent entry
adjoining a bitmap, or two neighbouring bitmap windows -- was
unclaimable.  stripe_unusable accounting is entry-blind and counts
exactly those stripes as claimable, so admission reserves data against
them; at writeback the claim finds nothing, cow_file_range() gets
-ENOSPC, and the already-dirtied pages are dropped.  full_stripe_len
is not a power of two, so stripe boundaries drift through the fixed
128M bitmap windows and a straddling stripe is a certainty near full,
not a corner case.

Observed live at the raid6 fill edge (rolling-failure, then isolated
by fill-edge-debug with enospc_debug): two 384K stripes, each
straddling a bitmap window boundary, held the space_info accounting
786432 bytes above what the claim could reach, and every writeback
allocation against that phantom margin failed -ENOSPC while ~991MB of
genuinely trapped free space sat in the cache.  The reservation margin
cannot absorb this: the gap is per straddling stripe, not per
outstanding extent.

Add an entry-blind slow path: one offset-ordered walk accumulating
contiguous free coverage across entry boundaries, and a piecewise
removal that runs in the same tree_lock critical section as the find,
so a racing claimer cannot see a half-removed run.  The fast path is
unchanged and still serves the common case; the slow path runs only
after it fails, which is the near-full case where a stranded stripe
matters most.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: pessimistic data reservation margin
Zygo Blaxell [Mon, 3 Aug 2026 07:22:52 +0000 (03:22 -0400)]
btrfs: stripe_alloc: pessimistic data reservation margin

A byte-counted data reservation holds no collateral against the stripe
claim rule.  Between admission at write() time and the allocation at
writeback, the trapped-space picture keeps moving: commits close open
stripe runs and trap their sub-stripe tails, and free space returning
mid-transaction (unpinned deletions, same-transaction frees, drained
run tails, freed reservations) lands in the free space cache as
fragments the claim rule can never hand out but that no counter yet
reflects.  The counters were honest at every instant for NEW
admissions while OLD admissions were left holding air; delalloc
writeback gets no second chance, so the pages were dropped.  Measured
at the fill edge: ~19 MiB of orphaned bytes_may_use with accounting
and allocator in perfect agreement, and in a later round the admitted
may_use+margin exactly equaled the phantom mid-transaction fragments.

Be pessimistic at reservation time and optimistic at allocation time,
the same shape metadata reservations already use:

- bytes_stripe_margin: one full stripe width (fs_info->
  stripe_margin_unit, the widest raid56 data full stripe) per
  outstanding delalloc extent, charged and released inside
  btrfs_mod_outstanding_extents() so it stays exact across delalloc
  merges and splits -- including async compression, where the io-tree
  split hook grows the margin to one stripe per compressed piece,
  matching the true worst case.  Counted in btrfs_space_info_used()
  so it holds back admissions.  The margin exists only for in-flight
  dirty data; steady-state capacity and statfs are untouched.

- Admission probes len + margin through the ticketed FLUSH_DATA path
  (then immediately re-releases the probe, which the delalloc hooks
  re-charge), so a writer that cannot be covered waits for the
  flusher -- commits convert pinned deletions into claimable whole
  stripes -- and receives an honest ENOSPC at write(2) if flushing
  cannot produce cover.

- Every btrfs_add_free_space() into an armed group counts the added
  range's sub-stripe head and tail fragments as trapped immediately;
  whole stripes fully inside the range are trivially fully free and
  stay claimable.  A bounded overcount in the safe direction, never
  an undercount; the commit rescan remains the authority and
  reconciles (and now grants tickets when it lowers the counter,
  since admission waiters may be blocked on exactly that headroom).
  This closes the retire-to-rescan window the previous patch left
  open, and closes it in the one place every returning range passes
  through: counting at the individual close/drain call sites instead
  misses paths (the drain returns have two) and gets the arithmetic
  wrong (round_up() on the non-power-of-two 448K stripe width).

- When a margin-backed data allocation must split across free space
  fragments, every non-final piece is kept a whole-stripe multiple
  (rounddown; the width is not a power of two), so at most one piece
  per delalloc extent can strand a tail -- the margin pre-paid
  exactly one.

- A data writeback allocation returning ENOSPC anyway is loudly
  warned: the margin should make it impossible, and the pages are
  dropped.

With this, the fill-to-ENOSPC harness goes fully clean for the first
time: zero writeback drops, zero warnings, zero allocation failures,
margin drains to zero at idle, and fill capacity is unchanged.  A
writeback ENOSPC retry loop that this replaces is dropped entirely.

Known bounds, accepted: compressed writes are probed one unit per
128M range but charged per 128K piece (probe optimistic, charge
honest); direct IO is probed but carries no margin (its reserve-to-
allocate window is one syscall); a remount toggling stripe_alloc
with dirty delalloc drains the counter (charges are gated on the
mount option, releases are not, and the counter clamps at zero).

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: count open stripe run remainders against data reservations
Zygo Blaxell [Sun, 2 Aug 2026 07:35:36 +0000 (03:35 -0400)]
btrfs: stripe_alloc: count open stripe run remainders against data reservations

Close the remaining reservation-vs-allocation windows the commit-time
stripe_unusable rescan cannot see:

- bytes_stripe_open (new): the sum of open runs' unallocated
  remainders, maintained per block group under stripe_run_lock at
  every open/alloc/grow/close, synced into the space_info after each
  mutation, and counted in btrfs_space_info_used().  Claimed bytes are
  invisible to the free space cache and will either be allocated or
  become trapped tails at close, so reservations must not be admitted
  against them.

A closed run's returned tail is still only counted as trapped by the
commit-time rescan, so reservations can race the retire-to-rescan window
inside a commit and be admitted against freshly trapped tails.  The next
patch closes that window from the free space cache side, where every
returning range is seen and no call site can be missed.

Measured on the fill-to-ENOSPC rolling test before this change (with
only the bytes_stripe_unusable accounting): tree 'b' still lost 3.3%
(8532 blocks) and tree 'c' 30% (62371 blocks) to silent writeback
allocation failure as trapping compounded.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: skip parking for sync rbios finished by their unplug batch
Zygo Blaxell [Fri, 31 Jul 2026 08:41:19 +0000 (04:41 -0400)]
btrfs: raid56: skip parking for sync rbios finished by their unplug batch

Parking exists to widen the merge window, and for plugged submissions
the unplug callback is the natural end of that window from the
submitter's side: once raid_unplug() has sorted and merged the batch,
nothing more is coming from it.  A sync rbio parked after that point --
a sync(2) or WB_SYNC_ALL sweep, whose whole flush shares one plug --
has a waiter behind it and can only sit out the sync deadline.  Mark
rbios leaving an unplug batch and let sync ones skip parking.

Unplugged sync submissions (the fsync flush) still park: their sibling
bios arrive one by one and merge into the parked rbio, and the fsync
path kicks it as soon as they have all been submitted, so parking there
is the merge mechanism and the deadline already never fires.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: expose parking statistics in sysfs
Zygo Blaxell [Fri, 31 Jul 2026 08:41:19 +0000 (04:41 -0400)]
btrfs: raid56: expose parking statistics in sysfs

/sys/fs/btrfs/<uuid>/stripe_park_stats reports lifetime counters for
the parking machinery: rbios parked, bytes merged into parked rbios,
and how each park ended (filled to a full stripe, kicked by a waiter or
a settle/retire flush, or expired at its deadline), plus how many
flushed writes were padded to full stripes versus still needing the
RMW read phase.  The filled/kicked/expired split shows directly whether
the deadlines are sized right for a given system -- expired parks that
later reappear as rmw_reads are the batching the window failed to
capture -- so any future retuning (or an adaptive deadline) can argue
from measurements instead of taste.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: do not park sync writes into nocow runs
Zygo Blaxell [Fri, 31 Jul 2026 05:08:44 +0000 (01:08 -0400)]
btrfs: raid56: do not park sync writes into nocow runs

An in-place overwrite of a nodatacow file under stripe_alloc parked
like any partial write, but with a waiter behind it and nothing worth
merging: in-place overwrites arrive one fsync at a time, and unlike
the datacow fsync path nothing kicks the parked rbio before the page
writeback wait, so every fsync ate the full sync park deadline.
Measured against stock nodatacow on the same rig, that deadline was
the bulk of a ~3.7ms per-fsync regression.  Skip parking for sync
writes whose stripe belongs to a NOCOW-class run; async writeback
still parks and merges there.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: persist nocow runs across commits and remounts
Zygo Blaxell [Fri, 31 Jul 2026 03:51:51 +0000 (23:51 -0400)]
btrfs: stripe_alloc: persist nocow runs across commits and remounts

A nodatacow inode's private stripe run used to close at every
transaction commit like all runs, so a slowly appended nocow file burned
a fresh stripe per commit -- and after a remount its partial stripe's
free tail was abandoned outright.  Neither cost buys anything: the run
machinery's commit-time closing exists for invariant I2, and a nocow
stripe holds only the owner's write-hole-waived data, so there is
nothing for I2 to protect.

Keep NOCOW-class runs open across commits: the commit-time retirement
and its drain predicate skip them (their extents insert without the
window-sequence deferral, which is fine -- the data is on disk when the
ordered extent finishes, and later same-stripe writes can tear only the
owner's own data).  They still close on forced quiescing (read-only,
removal, unmount) and now on the owning inode's eviction, so a cached
but idle inode cannot pin a claimed tail forever.

Across remounts, re-adopt instead: when a nocow allocation's hint
points into a partial stripe that the committed extent tree proves is
wholly owned by the allocating inode, claim exactly the stripe's free
tail (a new exact-range claim that verifies every byte is free before
removing; nothing else can consume free space inside a partially used
stripe, so verify-then-remove cannot race) and continue the run at the
old frontier.  Appends to a nocow file then pack sequentially through
commits, evictions and remounts alike.

The re-adoption lookup must not block.  It runs from
btrfs_alloc_from_inode_stripe_run(), i.e. inside find_free_extent(),
which holds space_info->groups_sem for read, and stripe_extents_owned_by()
does a full btrfs_search_slot() on the extent tree.  The reverse order is
longstanding upstream -- delayed ref processing holds extent tree locks
and then calls find_free_extent(), which takes groups_sem -- so waiting
here closes a cycle.  Both sides only take groups_sem for read, which is
not enough: it is an rw_semaphore and block group creation and removal
take it for write, so a writer queued between the two readers blocks the
second one.  The check cannot be hoisted above the lock, since it is a
question about the specific stripe the allocator has just settled on, but
it does not have to block: it is read-only and advisory, and every caller
already treats "not provably ours" as a reason to decline the
optimisation rather than as a fact about the extents.  So set path->nowait
for the groups_sem caller and let -EAGAIN fall into the existing error
paths; the cost on contention is a re-adoption that does not happen.
btrfs_stripe_nocow_writable() keeps the blocking search -- it runs from
the nocow check with no groups_sem held, and a spurious "not ours" there
would force COW on an extent that does not need it.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: allow-rmw policy, and write-in-place for isolated nocow extents
Zygo Blaxell [Thu, 30 Jul 2026 21:40:29 +0000 (17:40 -0400)]
btrfs: stripe_alloc: allow-rmw policy, and write-in-place for isolated nocow extents

Re-enable write-in-place for nodatacow files and preallocated extents
under stripe-exclusive allocation, with the understood caveat that the
write hole cannot be prevented for data that opts out of COW: an
in-place write RMWs its stripe's parity, so a degraded crash can tear
the stripe.  What CAN be guaranteed is the blast radius: in-place is
permitted only for extents whose full stripes are isolated to the
writing inode, so such a crash can tear only the writing file's own
data -- the nodatacow contract, no worse.

The gate is per extent, decided where nocow eligibility is already
checked: fast path, the stripe belongs to one of the inode's own
NOCOW-class runs (which only ever held its extents); slow path, the
committed extent tree proves sole ownership (single plain data ref,
count 1, matching root and objectid; anything shared, foreign or
metadata fails).  The fully-free claim rule keeps uncommitted foreign
extents out of partially used stripes, so the committed tree is
authoritative.  Extents that fail -- anything allocated before stripe
isolation existed, extents shared through reflink or snapshots,
relocated extents -- simply stay force-COWed, and because their rewrite
is steered into the inode's private NOCOW run, the next overwrite of
the same data passes: legacy nocow files migrate themselves to
isolation in one COW generation, with no tool and no flag day.

Log-commit settling skips NOCOW-class runs: nodatacow data gets no
fsync survival guarantee (its own later in-place writes can always
tear it), so closing the run would trap its tail for nothing.  The
write-hole debug checker skips groups that hosted NOCOW-class runs,
like relocation-used groups, since isolated in-place writes land in
stripes whose runs have drained.

The interface is a word-list policy naming the cases in which
stripe_alloc may permit the legacy unsafe RMW, each independently:

  nodatacow  in-place writes for nodatacow files' extents
  prealloc   in-place writes into preallocated extents
  fsync      waive the close-at-log-commit guarantee: no settling, no
             per-inode LOG steering, no carry-forward; logged stripes
             may be extended and RMWed as before those patches

It is "allow_rmw", not "allow_overwrite": the fsync case overwrites
nothing, but all three permit read-modify-write of stripes that a
degraded crash can then tear.  The nodatacow and prealloc cases require
the per-extent stripe isolation above (the blast radius stays confined
to the writing file); fsync restores the 3a-era exposure where a
degraded crash may cost just-fsynced data, detectably, in exchange for
none of the log-commit costs.

The policy is persistent as the btrfs.stripe_alloc_allow_rmw property
on the top-level root directory, following stripe_alloc's precedent
(applied when the root inode loads during mount, before any user IO),
with a mount option of the same name as a non-persistent override; the
effective policy is their union.  Words are separated by comma, space
or colon -- the mount option form must use colon, since mount splits
options at commas.  Everything defaults off: plain stripe_alloc keeps
forcing COW and keeps the full fsync guarantee.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: isolate nodatacow and preallocated extents by stripe
Zygo Blaxell [Thu, 30 Jul 2026 21:27:24 +0000 (17:27 -0400)]
btrfs: stripe_alloc: isolate nodatacow and preallocated extents by stripe

Preallocated extents and nodatacow files' extents are candidates for
write-in-place, which reintroduces the raid56 write hole for every
stripe such a write touches: the RMW recomputes parity that also covers
whatever else shares the stripe.  Before write-in-place can be
re-enabled for them (a later change; stripe_alloc still forces COW
today), their placement must guarantee the blast radius: such an extent
must never share a stripe with any other file's data.

Steer them into private per-inode stripe runs of a new NOCOW class,
reusing the log-active inode machinery: runs owned by one inode, never
in the shared band slots, found by owner-and-class lookup.  Successive
allocations of the same file pack sequentially into the file's own
stripes; different files, and the datacow/relocation/log classes, never
share a stripe with them.  A preallocation signals itself through a new
btrfs_reserve_extent() parameter; nodatacow files are recognized by the
inode flag.  Placement remains best effort: when no fully-free stripes
are left for a private run the allocation falls back to the shared
runs, which is safe -- an extent that lands in a shared stripe simply
stays force-COWed when write-in-place arrives.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: pad sub-stripe writes to full stripes in open runs
Zygo Blaxell [Thu, 30 Jul 2026 19:49:41 +0000 (15:49 -0400)]
btrfs: raid56: pad sub-stripe writes to full stripes in open runs

A sub-stripe write does a full RMW: read every untouched data sector of
the stripe, recompute parity, write.  Under stripe-exclusive allocation
the read phase is usually pointless: a stripe covered by a live stripe
run has never been written at or past the run's allocation frontier, so
the sectors being read contain nothing.

When every data sector the rbio does not cover lies at or past the
frontier, zero-fill those sectors instead of reading them and write
them out with the stripe -- the zeros must reach the disk, or the
parity (computed over them) would not match what scrub reads back.  The
partial write becomes one full-stripe write: no read phase, one parity
pass.  A frontier that grows during the attempt is safe: the newer
allocation's write serializes behind this rbio's stripe lock and lands
over the zeros.  If any uncovered sector is below the frontier (already
allocated to someone else), fall back to the normal RMW.

Together with kicking parked rbios before the fast fsync's writeback
wait, this removes both stalls the raid56 layer added to fsync under
stripe_alloc: the park deadline and the RMW read round trip.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: kick parked rbios before the fast fsync's writeback wait
Zygo Blaxell [Thu, 30 Jul 2026 18:16:55 +0000 (14:16 -0400)]
btrfs: stripe_alloc: kick parked rbios before the fast fsync's writeback wait

The fast fsync path waits for page writeback, which completes only when
the raid56 layer writes the data -- but a partial-stripe rbio parks to
collect merges until its sync deadline, and on this path nothing unparks
it before the wait: the stripes are settled only later, in the logging
itself.  The full-sync path does not have this problem because the
ordered extent wait already flushes parked rbios before sleeping.

All of the fsync's writes are submitted before the wait, so nothing more
can merge into its stripes; flush the parked rbios covering the attached
ordered extents instead of sleeping out their deadline.  Removes the
sync park timeout from the fast fsync critical path.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: carry an inode's log tail forward at fsync
Zygo Blaxell [Thu, 30 Jul 2026 07:28:14 +0000 (03:28 -0400)]
btrfs: stripe_alloc: carry an inode's log tail forward at fsync

Closing a log-active inode's private stripe run at each log commit
traps the run's final partial stripe tail every time the inode fsyncs:
a steady fsync stream burns one stripe per log commit until the stripes
free or balance runs.

Reclaim the tails by carrying the partial stripe's live data forward.
At each log commit, the settling walk now computes the closed run's
final partial stripe, and the logging paths record the file ranges of
the logged extents that live inside it on a small per-inode table
(bounded; overflow just means an extent is not carried).  At the
inode's next fsync, before its delalloc flush, each recorded range that
still maps to the recorded disk bytenr is re-dirtied, defrag style
(reserve, reset delalloc state, mark the folios dirty; absent folios
are read back, which is a plain read of settled data).  The flush then
COWs the carried ranges together with the new data into the inode's
current private run, and the old partial stripe empties and frees
whole.

Everything downstream is the ordinary COW pipeline: new extent maps,
ordered extents, checksums, file extent items and delayed refs, and
the log's modified-extents snapshot -- taken inside btrfs_log_inode
after the flush -- picks up the new addresses by itself.  Reflinked
ranges need no special handling: foreign referents keep the old extent
alive in its closed (never again written) stripe, and only the space
reclaim degrades.  A range that was rewritten, truncated, punched or
compressed simply fails the mapping check and stays put.

Crash safety does not regress.  A carried extent's old copy is dropped
through the normal paths: if it was committed, the free pins until the
transaction commits; if it was logged but never committed, its ADD and
DROP delayed refs cancel in cleanup_ref_head(), which also pins
must_insert_reserved heads -- either way the old blocks cannot be
reallocated before the log that references them is superseded.

The settling walk also learned to report the partial stripe through a
widened btrfs_log_settle_stripes() signature (inode and file range
instead of fs_info); compressed extents pass a zero file length to opt
out of carrying while still settling.

The re-dirty reserves with NO_FLUSH.  carry_one_range() takes the folio
locks and the extent range lock before reserving, and a flushing
(ticketed) reservation can sleep in wait_reserve_ticket() until the
flusher makes progress -- but every way forward needs the locks we
hold: FLUSH_DELALLOC has to write back the carried range, which blocks
in __folio_lock() on our locked folio, and a transaction commit (with
flushoncommit) waits for the same writeback.  The whole filesystem then
wedges behind the stuck commit.  Carrying is best effort by design and
the carried range's data is already durable in its old stripe, so on
ENOSPC just skip the carry and let the old stripe free the slow way.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: private per-inode stripe runs for log-active inodes
Zygo Blaxell [Thu, 30 Jul 2026 01:43:12 +0000 (21:43 -0400)]
btrfs: stripe_alloc: private per-inode stripe runs for log-active inodes

Closing the open stripe run covering every logged extent at each log
commit made completed fsyncs crash-safe, but at a placement cost: an
fsync-heavy inode shares the open band runs with every other writer, so
each of its log commits closes a shared run, fragmenting concurrent
write streams and trapping the shared run's tail.

Give log-active inodes their own runs instead.  The first fsync of an
inode sets a sticky runtime flag (at btrfs_sync_file entry, before the
fsync flushes its own delalloc, so even that first fsync's allocations
are steered).  Datacow allocations for a flagged inode come from a
private LOG-class run: claimed like any run but never placed in the
shared band slots, owned by the inode, and found by owner lookup under
the block group's stripe_run_lock.  A per-inode hint seeds the
allocator's search with the run's location; the hint is advisory (a
stale hint costs a lookup miss, never a wrong run, since the owner
match is authoritative).  When no fully-free stripes remain for a
private run the allocation falls back to the shared runs, restoring
the previous placement with unchanged safety.

One inode's log commit now settles only its own stripes: other
writers' runs stay open and their streams stay contiguous, and the
only trapped tails are the fsyncing inode's own.  Private runs also
give each log-active inode exclusive stripes, which a later change
uses to copy live tails forward and reclaim them without touching
foreign extents.

The commit-time retirement closed runs by walking the band slots,
which private runs never occupy; walk the block group's run list
instead so every open run, slotted or private, is closed and drained
under invariant I2 (no open run survives a transaction commit).

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: settle a logged extent's stripes at log commit
Zygo Blaxell [Thu, 30 Jul 2026 00:51:24 +0000 (20:51 -0400)]
btrfs: stripe_alloc: settle a logged extent's stripes at log commit

Stripe-exclusive allocation bounds degraded-crash damage to the current
transaction, but within that window two log commits can still share a
stripe: fsync 1 writes the head of a stripe, the open run keeps filling
it, and a later write's read-modify-write rewrites the parity that
protects fsync 1's data.  A degraded crash during the second write tears
the first -- the write hole's shape, confined to the log window, and the
reason the fsync guarantee has so far been "loss is detectable" rather
than "completed fsyncs survive".

Close it with a case analysis.  A logged extent in a full stripe is
already safe: nothing ever writes a full stripe again, since COW never
overwrites and there are no free sectors left to allocate.  A logged
extent in a partial stripe is exposed only to future writes into that
stripe's remaining sectors -- so at log commit, close the stripe's open
run (nothing further allocates into it), kick any parked partial writes
for it, and wait for its in-flight data IO before the log super is
written.  This is the log-window analogue of invariant I2, which the
commit-time retirement provides for full commits.  Both log paths are
hooked: the fast path per extent map in log_one_extent(), and the
full-sync path where copy_items() walks new data extents (old-transaction
extents are skipped there, and are exactly the ones already settled by
their own commit).

The drain is bounded and join-free: run inflight is counted from
allocation, which happens during writeback with submission following in
the same pass, so the wait is bio flight time plus the parked-write
deadline that the flush short-circuits; write_done reporting needs no
transaction join, so waiting under the inode log mutex and a running
transaction handle is safe.

The cost is spatial: every fsync that logs an extent in a partial stripe
retires that stripe early, trapping its unwritten tail like any other
partially filled stripe until it frees or balance reclaims it.
Fsync-heavy workloads therefore burn a stripe tail per touched stripe
per fsync; the follow-up per-inode log runs and copy-forward relocation
exist to reclaim exactly that cost, and are optimizations on top of the
guarantee this patch completes.

Assisted-by: Claude:claude-fable-5
(cherry picked from commit 53c44fdbca58bd1fa267a5648e236ed4238d99ed)

3 days agobtrfs: stripe_alloc: control the policy with a filesystem property
Zygo Blaxell [Wed, 29 Jul 2026 16:59:27 +0000 (12:59 -0400)]
btrfs: stripe_alloc: control the policy with a filesystem property

A mount option is an awkward fit for write-hole protection: it occupies
a mount-option bit, and protection silently lapses whenever the option
is forgotten -- an fstab edit, a rescue mount, a recovery boot -- which
is exactly when a degraded raid56 is most likely to be written.

Control the policy with a "stripe_alloc" filesystem property instead,
following the property system's compression precedent: a btrfs.
namespace xattr, user-visible and admin-controlled, on the top-level
subvolume's root directory.  Set it once (setfattr -n btrfs.stripe_alloc
-v 1, or btrfs property once btrfs-progs learns the name) and it is
persistent: the kernel applies it when the root directory inode loads
its properties during mount, before any user IO.  Deleting the xattr
disables the policy; open runs drain at the next commit's retirement,
which runs unconditionally.  Stray copies of the xattr -- a received or
cloned subvolume -- are ignored: only the top-level root carries the
policy, so receiving a stream from a stripe_alloc filesystem cannot
flip the policy on the destination.

The support checks (free space tree, not zoned, no remap-tree, not
mixed block groups) are enforced both when the property is set and when
it is applied at mount.  The mixed block group test matters most here.
btrfs_check_mountopts() refuses mixed for the mount option, and without
the same test this would be a second way in that skips it -- enabling a
policy the series does not support there, after the block group read
that would have warned about uncovered metadata has already run, so the
user is told the filesystem is protected and it is not.

This stays within the series' no-on-disk-format-change constraint, and
that is the compatibility story: an older kernel mounts the filesystem
read-write and simply uses the legacy allocator, which is fully
compatible because the on-disk layout is unchanged.  New kernels honor
the property during the feature's long-tail testing period; if no use
case surfaces where stripe-exclusive allocation is worse than the write
hole it protects against, it can eventually become the only allocation
mode and the property a no-op.

Known old-kernel interactions with the btrfs. namespace: existing
kernels list and read the xattr (the btrfs. get path is a plain xattr
read) but refuse to set or remove unknown property names, so the flag
can only be managed from a kernel that knows it.  btrfs-progs
interaction (check, property list) with an unrecognized property is a
userspace compatibility item to verify and, if needed, patch.

The mount option is kept for now as a non-persistent override.  Later
protection stages with different risk profiles (the log-tree
full-stripe relocation) should be gated by their own property rather
than widening this one, so their testing exposure can be controlled
independently.

Assisted-by: Claude:claude-fable-5
(cherry picked from commit ecd4d3de8a0493f7c406d919d533f88e8b45390c)

3 days agobtrfs: stripe_alloc: never claim stripes covered by a live run
Zygo Blaxell [Wed, 29 Jul 2026 14:35:41 +0000 (10:35 -0400)]
btrfs: stripe_alloc: never claim stripes covered by a live run

The range-to-run lookups -- attaching an ordered extent to its stripe run
and reporting completed data IO by bytenr -- assume that at most one run
on a block group's list covers any given address.  Nothing enforced that.

A reservation that is discarded before anything references it (the
cow_file_range error path under ENOSPC, the find_free_extent backout
paths) returns its bytes to the free space cache immediately, with no
pinning: there is no committed state to protect.  When an ENOSPC failure
storm discards every allocation in a stripe, the stripe is fully free
again and the claim rule -- correctly, by its own lights -- hands it out
as part of a new run while the old run object is still on the list
draining its other stripes' IO.  Full-stripe write batching widened a
run's post-close drain from microseconds to the parked-write timeout, and
the soak test hit the overlap within minutes: new allocations' ordered
extents attached to the old run (first match by range), their completions
drained the old run's inflight accounting into an assertion failure, and
the new run's accounting never drained, wedging the commit's retire wait.
The overlap is harmless to data -- a stripe can only be re-claimed if
every byte of it is free, and discarded reservations never issued bios --
but the accounting corruption is fatal.

Freed committed extents cannot reproduce this: they return to the free
cache only in the unpin phase at the tail of a commit, and the same
commit's retirement already drained -- and freed -- every run opened
before it.  Only the unpinned immediate-free paths race with a draining
run.

Rather than enumerate those paths, enforce the lookups' assumption at the
claim site: btrfs_claim_free_stripe_run() now trims a candidate to end
before the first live run overlapping it, or rejects it if its head
overlaps.  Re-claiming such stripes just waits until the old run drains
off the list, which only comes up inside ENOSPC failure storms.

Reproduced with concurrent fill-to-ENOSPC/delete cycles, balance, and
fsstress on a 4-device raid5: the assertion fired within ~15 minutes
unpatched, and ~10 hours of the same load ran clean with this fix.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: raid56: batch stripe_alloc partial writes into full-stripe writes
Zygo Blaxell [Tue, 28 Jul 2026 15:19:50 +0000 (11:19 -0400)]
btrfs: raid56: batch stripe_alloc partial writes into full-stripe writes

A raid56 sub-stripe write pays a read-modify-write: read the rest of the
stripe, recompute parity, write.  The plug callback merges rbios submitted
within one plug window and the stripe cache saves re-reads for
back-to-back writes, but measurement shows what survives them: on a
4-device raid5, small-file writeback produces 100% sub-stripe rbios (zero
full-stripe writes) and a mixed 4K-512K workload ~55%, so parity is
recomputed and rewritten once per file that lands in a stripe.

Stripe-exclusive allocation gives raid56 something the allocator never
guaranteed before: the rest of an open run's stripe is either written
before the run closes -- within the current transaction -- or not at all.
That makes holding a partial write a sound bet, so park it: a partial
write rbio whose stripe belongs to a stripe run keeps the stripe
lock but does not start its RMW.  Later writes to the stripe merge into
it through the existing lock_stripe_add() path, and the moment its data
bitmap covers the stripe it is submitted as a single full-stripe write:
one parity computation, no reads.

A draining run counts, not just an open one.  A run closes the moment it
is fully allocated -- typically milliseconds before its last writes reach
the raid56 layer -- so gating on "open" would leave exactly those tail
writes unable to park and unable to pad, and they are the bulk of the
read-modify-writes this patch exists to remove.  A draining run is in
fact the safest thing to park against: its frontier is frozen, so
everything below it is inflight IO the commit drain already waits for
(arrival guaranteed) and everything above it is dead space the pad may
fill.

Completion accounting can never trigger the flush of runts -- parked bios
have not been submitted, and preallocated or discarded allocations
produce no bios at all -- so liveness comes from explicit flushes: the
run retirement paths flush before the commit's IO drain (which waits on
the very bios parked here), ordered-extent waiters flush their range on a
short retry period, and a timer bounds everything else.  Writes with a
blocked waiter (REQ_SYNC: fsync- and sync-driven writeback) park with a
~3ms deadline instead of 100ms -- long enough for the rest of one
writeback pass over the stripe to merge in, short enough to stay
invisible in fsync latency -- and a sync bio merging into a parked rbio
pulls the deadline in.  Only the bg->open_stripe slots are consulted for
eligibility, and a parked rbio that a racing retirement closed out from
under is bounded by the timer, never by the drain.

Measured (same 4-device raid5, deterministic workloads, classifying every
write rbio at rmw_rbio):

  workload       full-stripe rbios      total write rbios
  streaming      99% -> 99%             unchanged
  mixed 4K-512K  43% -> 97%             2478 -> 1615
  small files     0% -> 86%             1537 ->  335 (stripe reads 311->23)
  fsync-per-file  0% ->  0%             unchanged (nothing co-pending)

fsync latency is 12ms vs 8ms unpatched (each fsync pays one short park).
Batching also collapses trapped free space in a mixed-size forward fill
from ~87 MiB to ~3 MiB: stripes now fill completely before the commit
closes their run, so the frontier strands almost nothing.

Validated: btrfs selftests; mixed-size + concurrency + churn + balance
workload with trapped-space accounting returning to zero after deleting
everything; scrub and full sha256 read-back over 4005 mixed random files;
and the dm-log-writes write-hole crash matrix (24/24 controls clean, 0/36
armed cases with committed data damage) -- parking does not perturb the
stripe-exclusivity guarantee it rides on.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: grow the frontier run instead of stranding its tail
Zygo Blaxell [Tue, 28 Jul 2026 06:26:50 +0000 (02:26 -0400)]
btrfs: stripe_alloc: grow the frontier run instead of stranding its tail

When an allocation is larger than every open run's remainder, the
allocator claims fresh fully-free stripes and opens a separate run,
leaving the old run's tail behind.  The banded cursors keep that tail
open for a while, but a band collision or the commit eventually closes
it, and the tail -- perfectly usable space that a misfit merely jumped
over -- is stranded in a partially filled stripe.  In a forward fill
this happens at every size upshift, and measurement shows it is where
nearly all of stripe_alloc's trapped space comes from: on a mixed-size
fill it strands ~14% of the data written, a figure that band-granularity
tuning moves by at most a tenth and commit frequency does not move at
all.

Grow the frontier run instead.  If the freshly claimed stripes directly
follow the end of an open run of the same class, extend that run to
absorb them and place the allocation at the run's old tail, spilling
contiguously into the new stripes.  Nothing is stranded, and the extent
is physically contiguous.  In a forward fill the by-size claim naturally
returns the stripes adjacent to the frontier, so the single frontier run
just keeps growing -- the allocator packs the way the stock allocator
does, while keeping stripe exclusivity: the grown stripes were claimed
fully free, the run still closes at the next commit and is never
reopened, so every stripe of the run is filled within one open-run
lifetime.  A grown run keeps its open_seq; it can only still be in a
band slot if the retire walk for its window has not yet run, which the
open_stripe_lock nesting at the claim site excludes from racing.

Measured on a 4-device raid5 with a deterministic interleaved 4K-512K
fill (trapped space via the stripe_unusable counter, byte-identical data
both sides): 111.1 MiB trapped without growing, 7.2 MiB with -- a 94%
reduction, and usable capacity at ENOSPC within 0.5% of the stock
allocator (1561 vs 1569 MiB, vs 1421 MiB without growing).  The benefit
survives churn: with age-correlated deletion the grown runs' contiguous
packing lets whole stripes free together, and steady-state usable
capacity stays at 1486-1561 MiB versus 1284-1421 MiB without growing
across correlated and adversarial small-file deletion patterns.  Data
integrity verified by scrub and full sha256 read-back over mixed
random-content files, and trapped-space accounting still returns to
zero when all files are deleted.

The open-stripe selftest is updated: the misfit allocation now grows the
run and lands at the run's old tail, spanning the stripe boundary, and
the relocation-class case doubles as a check that a claim adjacent to
another class's run never grows it.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: stripe_alloc: keep an open run per size band to trap less
Zygo Blaxell [Tue, 28 Jul 2026 00:55:59 +0000 (20:55 -0400)]
btrfs: stripe_alloc: keep an open run per size band to trap less

A single open stripe run per class forces every allocation that does not
fit the current run's remainder to close that run -- trapping its
unallocated tail in a now partially filled stripe -- and claim a fresh
fully-free stripe.  A workload that interleaves small and large extents
(the common case) therefore strands a tail on every size change, even
though a later small allocation could have filled it.

Keep one open run per power-of-two band of remaining free space instead
(band k holds a run with remaining in [2^k, 2^(k+1)) sectors), per class.
An allocation takes the run in the smallest band that still fits --
segregated best fit -- so a small write lands in an already-open, nearly
full stripe rather than opening a new one, while a large write that no
open run can hold opens a fresh stripe and leaves the smaller runs open
for the small writes that do fit them.  After each allocation the run is
re-placed into the band its new remainder falls in; when two runs collide
in a band the fuller one is kept -- it can serve larger future
allocations, and closing it would trap more -- and the other is closed,
its tail returned to the free space cache.

16 bands cover a full stripe of up to 2^16 sectors, far more than any
raid56 geometry (nr_data_stripes * stripe_len / sectorsize is 158 sectors
at 10 data stripes and a 64K stripe).  Commit-time retirement and the
read-only / removal paths now walk every band of every class; only the
bg->open_stripe[][] slots can ever hold an open run, so one pass still
suffices, and the obsolete single-slot assertions are dropped.

This does not touch the write-hole guarantee: every run is still a
contiguous fill of fully-free stripes, closed at commit and never
reopened.  It only changes which open run an allocation joins, reducing
the free space trapped in partial stripes -- and thus stripe_unusable --
for mixed-size workloads.

The open-stripe selftest is rewritten to the multi-cursor contract: a
misfit allocation now keeps the old run open (its tail is not returned to
the cache) and a later small allocation backfills it, so fewer stripes are
claimed before the free space is exhausted.

Assisted-by: Claude:claude-opus-4-8
3 days agobtrfs: account stripe_alloc trapped free space for honest statfs
Zygo Blaxell [Mon, 27 Jul 2026 16:31:14 +0000 (12:31 -0400)]
btrfs: account stripe_alloc trapped free space for honest statfs

Free space in the partially filled stripes of a stripe_alloc (raid56
write-hole-safe) block group is real free space -- it is in the free
space tree and cache -- but the stripe-exclusive allocator cannot hand it
out until the whole stripe frees.  statfs therefore over-reports available
space, promising free space that a later allocation refuses with ENOSPC.

Track this trapped space per block group as stripe_unusable, summed into
space_info->bytes_stripe_unusable.  It is derived, so there is no on-disk
format change and the free space tree and cache are left untouched
(preserving the extent-tree/free-space-tree consistency btrfs check
verifies).

stripe_unusable is defined by a scan that accumulates every free byte of
the block group into a per-stripe array and then sums the stripes that are
partially filled.  A per-stripe accumulator, rather than a streaming sweep
or a per-stripe cache search, is what makes the result correct regardless
of the order the free space cache yields its ranges -- an offset-sorted
bitmap entry can emit runs that lie past a following extent entry, so the
ranges are not globally monotonic -- and regardless of whether free space
is stored as extents or bitmaps.  A debug-build assertion checks that the
scan distributes exactly the cache's free space.  Because trapped space
only settles at commit -- when the retire path returns partially filled
stripes and deleted extents are unpinned -- the scan is recomputed at
commit for groups whose free space changed (flagged cheaply on the
allocation and free paths), which suits the timescale of the reclaim it
feeds far better than a running per-extent tally.  The space_info total is
recomputed as the sum of the armed groups after those rescans, so it
cannot drift.

statfs subtracts bytes_stripe_unusable from the data f_bavail so df
reports what can actually be allocated, and the counter is exposed at
/sys/fs/btrfs/<uuid>/allocation/data/bytes_stripe_unusable.  It is
deliberately not part of btrfs_space_info_used(), so the reservation layer
is unchanged and this carries no ENOSPC-behaviour risk.

The counter is armed once a group's free space cache is loaded, so a group
contributes zero until then and statfs starts optimistic and settles to
honest as groups cache and commit.  It is disarmed when a group turns
read-only (its free space is then accounted as read-only and already
excluded from statfs) and re-armed by a rescan on the way back to
read-write, so a balance both recovers trapped space and updates the
counter.  A CONFIG_BTRFS_DEBUG-only sysfs trigger, stripe_unusable_rescan,
forces a full recompute for auditing the accounting.

Two deliberate imprecisions, matching existing behaviour rather than
bettering it: statfs subtracts bytes_stripe_unusable but not
bytes_zone_unusable, so stripe_alloc df reports availability before reclaim
while zoned df reports it after; and superblock stripes, permanently
unusable in every profile, are left to the existing bytes_super accounting
rather than separately reported here.  Both await a maintainer decision on
a common convention.

Assisted-by: Claude:claude-opus-4-8
3 days agobtrfs: stripe_alloc: refuse space_cache=v1
Zygo Blaxell [Wed, 5 Aug 2026 03:33:32 +0000 (23:33 -0400)]
btrfs: stripe_alloc: refuse space_cache=v1

The v1 free space cache inode is nodatacow, preallocated and nodatasum,
so the cache is overwritten in place during commit: a sub-stripe write
into a data block group, landing in whatever committed stripes the cache
occupies, with no csum that could reveal the damage afterwards.  That is
precisely the write this series exists to prevent.

The free space tree is not what stripe_alloc needs -- nothing in it reads
the tree, and the by-size index it allocates from is the in-memory free
space, which exists whatever the on-disk format is.  Having no cache at
all is fine too.  Only v1 has to be kept away, so say that instead of
demanding v2.

Three places, because the cache format can only be converted at mount and
never at remount, so the option alone is not the whole story:

 - btrfs_check_mountopts() rejects space_cache=v1 with stripe_alloc.

 - btrfs_reconfigure() rewrites the cache options after that validation,
   to restore what is on disk.  It has to, given the above.  Re-check
   afterwards rather than assume the options still mean what they did.

 - block group read time refuses to mount when v1 cache inodes are
   present on disk at all.  cache_generation only records whether the
   last mount wrote the cache; the inodes are the durable evidence, so
   btrfs_free_space_cache_v1_present() looks for one under
   BTRFS_FREE_SPACE_OBJECTID in the tree root.  Clearing them is one
   mount away, and the error message says so.

cache_save_setup() also declines to set the cache up while stripe_alloc
is on.  The checks above should make that unreachable, but it is the
point where the in-place write would actually be issued.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: add a write-hole invariant checker to the raid56 write path
Zygo Blaxell [Sat, 25 Jul 2026 15:11:02 +0000 (11:11 -0400)]
btrfs: add a write-hole invariant checker to the raid56 write path

With stripe-exclusive allocation, a raid56 data stripe may only be
written while an open or draining stripe run covers it: after its run
retires and drains at a transaction commit, nothing may ever write to
it again, and a write outside any run means an allocation bypassed the
policy.  Both cases are the write hole about to happen.

Check the invariant (under CONFIG_BTRFS_DEBUG) for every raid56 write
operation, full-stripe and sub-stripe alike, at rmw_rbio() time.  This
turns every upstream violation -- a missed allocation path, a
retirement ordering bug, an accounting leak -- into a deterministic
WARN at the moment of the offending write, instead of silent damage
that needs a crash plus a device failure plus a scrub to observe.  The
bios gathered in an rbio have not reported their IO done yet, so their
runs cannot drain under the check: no false positives from completion
races.

Block groups that ever hosted relocation-class runs are skipped
(sticky, debug-only flag): relocation legitimately overwrites its
preallocated extents in place after their runs drain, and the write
path cannot tell those writes from violations.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: retire stripe runs at commit and gate stripe_alloc
Zygo Blaxell [Sat, 25 Jul 2026 05:35:20 +0000 (01:35 -0400)]
btrfs: retire stripe runs at commit and gate stripe_alloc

Hook stripe run retirement into the transaction commit, right after
TRANS_STATE_COMMIT_DOING stops accepting joins with a single writer
left.  At that point every data extent the transaction references was
inserted by an ordered extent completion that joined earlier, implying
its own data IO is done; the retirement drain waits out in-flight
neighbour writes in the same stripes (a pure data-IO wait, never an
ordered extent wait, which would deadlock on the blocked join).  After
the drain, no stripe this transaction references can ever be written
again, so a crash after the superblock write cannot tear it -- closing
the raid56 write hole for stripe-allocated block groups without
requiring flushoncommit.  A defensive retirement in
btrfs_free_block_groups() covers the transaction abort path.

An ordered extent whose stripe run was opened after the committing
transaction's retire point cannot insert its file extent into that
transaction, so btrfs_finish_one_ordered() ends its handle and waits
for the commit's critical section to end.  That wait must not be taken
under the range's extent lock: buffered writers block on the locked
range in lock_and_cleanup_extent_if_need() while holding their
prepared, locked folios, which stops the writeback flusher and
kcompactd behind those folios, which stops reclaim -- and the
committing transaction is itself draining data bios whose submission
path can need memory (dm-crypt bounce pages on the host where this was
caught).  Drop the extent lock and the FINISHING_ORDERED tag before the
wait and re-take them before re-joining, preserving the
extent-lock-before-join ordering.  The window is safe: the range is
still covered by the pending ordered extent, so a writer that takes the
lock finds it, releases its folios and waits -- which is exactly what
unbinds writeback and reclaim.

Force COW for in-place writes that would land in raid56 data block
groups while stripe_alloc is enabled (nodatacow files and writes into
preallocated extents): a single in-place write could tear a stripe
containing other files' committed extents, making the guarantee
conditional on the whole filesystem's usage.  The check sits in
can_nocow_file_extent(), covering buffered and direct IO with one
choke point, and applies per extent so nocow to non-raid56 profiles
keeps working.  The data relocation inode is exempt: its extents live
in relocation-class stripe runs that never share stripes with other
data, and relocation depends on in-place writes.

Validate the option at mount: it requires the free space tree (the v1
space cache overwrites its data in place during commit), and is
refused with the remap-tree feature (whose relocation writes bypass
the ordered extent accounting) and on zoned filesystems (which have
their own allocator and no write hole).

Mixed data+metadata filesystems are refused too.  The immediate symptom
is a hang: a run drains when it is closed and its inflight_bytes reach
zero, and the only things that subtract are ordered extent completion, a
discarded allocation and a freed reservation.  Metadata has no ordered
extent -- btrfs_alloc_tree_block() allocates with is_data false and
end_bbio_meta_write() reports nothing back to the run -- so a metadata
allocation raises inflight_bytes and nothing ever lowers it, the run
never drains, and btrfs_retire_open_stripes() waits for a completion
that has no code path to arrive from.  The hung task detector stays
quiet, because wait_var_event() sleeps in a state it exempts; the
filesystem just stops.  Reproduced deterministically on
mkfs.btrfs -M -d raid5 -m raid5 mounted -o stripe_alloc: the first sync
after a few hundred small files never returns.

That symptom is not why the refusal is permanent: a later patch
(stripe_meta) gives metadata its own completion report, and the drain
then terminates.  These are why:

 - raid56 deliberately skips csum lookup for mixed block groups, to
   avoid recursing into a metadata read while holding the full stripe
   lock (see the comment above the map_type test in fill_data_csums()).
   That test reads the block group's flags, so in a mixed group it
   cannot tell a data stripe from a metadata stripe and disables
   verification for every one of them.  Stripe-exclusive allocation
   could keep the two apart -- allocation classes already never share a
   run, so never a stripe -- but nothing durable records which class a
   stripe held, and asking the extent tree while holding the full stripe
   lock is the recursion the test exists to avoid.  The recovery paths
   here assume a rebuilt data sector can be checked; in a mixed group it
   cannot.

 - Data and metadata draw on one space_info and one free space pool.
   Data reservations carry a pessimistic whole-stripe margin, metadata
   reservations carry none, and a metadata claim that finds no fully
   free full stripe returns ENOSPC -- which for metadata aborts the
   transaction rather than failing one write.  A data fill can starve
   metadata into an abort, which separate block groups cannot do.

Mixed block groups are a mkfs-time property of small filesystems, where
raid56 is least appropriate and stripe_alloc's trapped space costs
proportionally most, and the option cannot become applicable later.  So
do not carry a half-supported mode.

btrfs_is_stripe_alloc_bg() therefore requires DATA without METADATA as
belt and braces for a block group that somehow reaches the allocator
anyway, and moves out of extent-tree.c's file scope so block-group.c
can share the one copy of the rule.  (Metadata and system block groups
never carried the DATA flag, so they were already excluded.)

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: report stripe run data IO through the ordered extent lifecycle
Zygo Blaxell [Sat, 25 Jul 2026 05:32:11 +0000 (01:32 -0400)]
btrfs: report stripe run data IO through the ordered extent lifecycle

Pair every byte reserved from an open stripe run with exactly one
"write done" report, so commit-time retirement can wait for all data IO
into a window's stripes:

- Ordered extents get a stripe_run pointer, attached at creation by a
  range lookup (cheap: gated on the fs having any stripe runs at all,
  and a run's block group membership is established before its
  allocation returns, so the gate cannot miss).  NOCOW and PREALLOC
  ordered extents write into previously allocated extents, which can
  never lie inside a run claimed from fully-free stripes, and are
  skipped.  The report fires once at IO completion (the IO_DONE moment
  in can_finish_ordered_extent(), before any transaction join, so the
  commit-time drain can never deadlock on a blocked join), with a
  catch-all when an ordered extent is freed without completing IO.

- Reservations freed without an ordered extent ever owning them (error
  paths) report through btrfs_free_reserved_extent(); the one caller
  that frees a range an ordered extent did own (the finish-error path)
  uses btrfs_free_reserved_extent_ordered() to avoid double reporting.

- Preallocated extents never issue data IO and report at insertion;
  this also covers relocation's data inode preallocations.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: add the stripe_alloc allocation policy for raid56 data
Zygo Blaxell [Sat, 25 Jul 2026 05:24:37 +0000 (01:24 -0400)]
btrfs: add the stripe_alloc allocation policy for raid56 data

Wire the open stripe run allocator into find_free_extent() as a per-
block-group policy: with the new stripe_alloc mount option, allocations
from raid56 data block groups go through btrfs_alloc_from_open_stripe()
instead of the clustered allocator, and only ever land in fully-free,
stripe-aligned runs.  Since the loop's terminal LOOP_NO_EMPTY_SIZE
degradation only applies to the clustered path and stripe block groups
ignore empty_size/empty_cluster, the natural terminal behaviour is:
no fully-free stripe in any block group -> allocate a chunk -> ENOSPC.
The availability hint feeds max_extent_size so callers retry with
smaller allocations instead of failing early.

Stripe runs get an allocation class: relocation overwrites its
preallocated extents in place, so its allocations must never share a
stripe with ordinary cow data.  Classes never share a run, and one
block group at a time is softly dedicated to relocation by reusing
fs_info->data_reloc_bg (btrfs_clear_data_reloc_bg() moves from zoned
code to generic code for this; the class tag, not the dedication, is
what carries correctness).  The dedication is dropped when relocation
finishes or the dedicated group runs out of stripes.

Setting a block group read-only now retires its stripe runs (in
btrfs_inc_block_group_ro(), covering scrub, relocation and unused
block group deletion), pairing with the allocator's ->ro check under
the stripe_run_lock so no run can survive into or be created in a
read-only group.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: add open stripe run tracking for stripe-exclusive allocation
Zygo Blaxell [Sat, 25 Jul 2026 04:01:17 +0000 (00:01 -0400)]
btrfs: add open stripe run tracking for stripe-exclusive allocation

Add the in-memory state and lifecycle for "open stripe runs", the
allocation windows of the raid56 stripe-exclusive allocation policy.  A
run is a contiguous stripe-aligned region claimed whole from the free
space cache via btrfs_claim_free_stripe_run() and filled strictly
sequentially by btrfs_alloc_from_open_stripe().  A run closes when it is
exhausted, when an allocation does not fit its remainder, or when the
transaction commit retires it; closed runs are never reopened and their
unallocated tails return to the free space cache, where the fully-free
claim rule makes them unallocatable until the whole stripe frees.  This
is what will guarantee that a full stripe only receives writes within
one commit window, closing the raid56 write hole for these block groups.

Each run counts reserved bytes whose data IO has not completed yet,
maintained under the block group lock and reported back through
btrfs_open_stripe_write_done().  btrfs_retire_open_stripes() implements
commit-time retirement: bump the retire sequence, close every run opened
before it, and wait for their inflight bytes to drain.  It is a pure
data-IO wait, deliberately not an ordered extent wait: it is designed to
run after the committing transaction stops accepting joins
(TRANS_STATE_COMMIT_DOING with a single writer), where waiting for
ordered extent completion would deadlock on the blocked transaction
join, and where every extent the transaction references already has its
own data on disk.  Allocations racing with the commit open runs stamped
with a newer sequence and are neither retired nor waited for; their
extents can only be referenced by the next transaction.  Block groups
with runs are tracked on an fs_info list whose membership is
established before an allocation returns, which is what lets the retire
walk rely on the sequence stamp.

Exercised by a new sanity self-test; the raid56 stripe allocation
policy and the commit hook will be the first non-test users.

Assisted-by: Claude:claude-fable-5
3 days agobtrfs: add btrfs_claim_free_stripe_run() for stripe-exclusive allocation
Zygo Blaxell [Sat, 25 Jul 2026 03:58:30 +0000 (23:58 -0400)]
btrfs: add btrfs_claim_free_stripe_run() for stripe-exclusive allocation

Add a free space cache primitive that finds and removes a contiguous,
fully-free, stripe-aligned run of full stripes from a block group.  This
is the building block for a raid56 allocation policy that never issues
sub-stripe writes into stripes containing committed data, closing the
raid56 write hole for datacow writes: because a partially-filled stripe
can never satisfy the fully-free requirement, stripes retired at commit
time become unallocatable without any persistent allocator state.

The search walks the by-size free space index (largest max contiguous
free run first) rather than the by-offset tree: an entry whose largest
contiguous free run is smaller than a full stripe cannot contain a
fully-free stripe, and every following entry is no larger, so the search
stops at the first such entry.  Near-full, where the free space
degenerates into many sub-stripe holes, that is an O(1) fast fail
instead of a scan of the whole free space tree on every allocation --
the dominant cost of the known raid56 near-full allocation slowdown.

Full stripe geometry is relative to the block group start and supports
non-power-of-two stripe widths.  Unaligned head and tail remainders are
returned to the free space cache with their trim state preserved.  Runs
are found within a single free space entry; a fully-free stripe split
across an extent entry and a bitmap neighbour is deliberately not found,
which errs toward missing a claimable stripe, never toward claiming a
non-free byte.

The function is exercised by new sanity self-tests covering aligned and
capped claims, partial-stripe exclusion, head/tail carving, block-group-
relative geometry, bitmap entries, and non-power-of-two stripe widths.
The raid56 stripe allocation policy will be its first non-test user.

Assisted-by: Claude:claude-fable-5
5 days agoLinux 6.18.52 stable/linux-6.18.y
Greg Kroah-Hartman [Mon, 14 Sep 2026 11:36:19 +0000 (13:36 +0200)]
Linux 6.18.52

Link: https://lore.kernel.org/r/20260912065623.398859879@linuxfoundation.org
Tested-by: Brett A C Sheffield <bacs@librecast.net>
Tested-by: Peter Schneider <pschneider1968@googlemail.com>
Tested-by: Wentao Guan <guanwentao@uniontech.com>
Tested-by: Barry K. Nathan <barryn@pobox.com>
Tested-by: Ron Economos <re@w6rz.net>
Tested-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5 days agowifi: mt76: fix airoha_npu dependency tracking
Arnd Bergmann [Fri, 12 Jun 2026 20:13:19 +0000 (22:13 +0200)]
wifi: mt76: fix airoha_npu dependency tracking

commit 7cd57ff6c6263519e6e463cbc2e0898828a70c42 upstream.

There is a new build failure with MT7996E=m MT76_CORE=y and NET_AIROHA_NPU=m:

ld.lld: error: undefined symbol: airoha_npu_get
ld.lld: error: undefined symbol: airoha_npu_put
>>> referenced by npu.c
>>>               drivers/net/wireless/mediatek/mt76/npu.o:(mt76_npu_init) in archive vmlinux.a

Fix this by reworking the dependency for the MT7996_NPU to only
allow enabling that when mt76_core can link against the npu driver.

To make sure this gets caught more easily in the future when additional
mt76 variants need the same dependency, also turn CONFIG_MT76_NPU into
a tristate symbol that has the same dependency.

Fixes: 7fb554b1b623 ("wifi: mt76: Introduce the NPU generic layer")
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Link: https://patch.msgid.link/20260612201519.4054683-1-arnd@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5 days agostaging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction
Salman Alghamdi [Wed, 13 May 2026 20:34:40 +0000 (23:34 +0300)]
staging: rtl8723bs: rtw_mlme: add bounds checks before ie_length subtraction

commit 88e994c57a79f62d5338231d8d37ee8dd98baffe upstream.

Add guards to ensure ie_length is large enough before subtracting
fixed IE offsets to prevent unsigned integer underflow.

Fixes: 2038fe84b8bd ("staging: rtl8723bs: fix spacing around operators")
Fixes: d3fcee1b78a5 ("staging: rtl8723bs: fix camel case in struct wlan_bssid_ex")
Closes: https://lore.kernel.org/linux-staging/DI2H39EAAFBZ.3KI5NWN02AQ2S@linux.dev/
Cc: stable <stable@kernel.org>
Signed-off-by: Salman Alghamdi <me@cipherat.com>
Reviewed-by: Luka Gejak <luka.gejak@linux.dev>
Link: https://patch.msgid.link/20260513203455.31792-1-me@cipherat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5 days agostaging: rtl8723bs: os_dep: avoid NULL pointer dereference in rtw_cbuf_alloc
Shyam Sunder Reddy Padira [Tue, 14 Apr 2026 07:13:06 +0000 (12:43 +0530)]
staging: rtl8723bs: os_dep: avoid NULL pointer dereference in rtw_cbuf_alloc

commit bc851db06045a40c18233dd76ef0562d7f8bb6db upstream.

The return value of kzalloc_flex() is used without
ensuring that the allocation succeeded, and the
pointer is dereferenced unconditionally.

Guard the access to the allocated structure to
avoid a potential NULL pointer dereference if the
allocation fails.

Fixes: 980cd426a257 ("staging: rtl8723bs: replace rtw_zmalloc() with kzalloc()")
Cc: stable <stable@kernel.org>
Signed-off-by: Shyam Sunder Reddy Padira <shyamsunderreddypadira@gmail.com>
Reviewed-by: Dan Carpenter <error27@gmail.com>
Link: https://patch.msgid.link/20260414071308.4781-2-shyamsunderreddypadira@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5 days agopinctrl: airoha: an7583: add missed gpio22 pin group
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:40 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: add missed gpio22 pin group

[ Upstream commit 9ef86358855d5fd89db019ace33c097d2d752b9d ]

gpio22 pin group is missed, fix it.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoACPI: processor: Add cpuidle driver check in acpi_processor_register_idle_driver()
Tony W Wang-oc [Mon, 8 Jun 2026 19:03:59 +0000 (03:03 +0800)]
ACPI: processor: Add cpuidle driver check in acpi_processor_register_idle_driver()

[ Upstream commit 66c62e6773c54ce5233eb21c6d48999c3747bd13 ]

Commit 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle
driver registration") moved the ACPI idle driver registration to
acpi_processor_driver_init(), but it didn't check whether a cpuidle
driver was already registered.

For example, on Intel platforms, if the intel_idle driver is already
loaded, the code would still evaluate the _CST object in the ACPI
table and attempt to register the acpi_idle driver. This registration
would fail with -EBUSY due to the existing check in cpuidle_register_driver.

Add a check at the beginning of acpi_processor_register_idle_driver()
to avoid unnecessary _CST evaluate and potential registration failures.

Fixes: 7a8c994cbb2d ("ACPI: processor: idle: Optimize ACPI idle driver registration")
Signed-off-by: Tony W Wang-oc <TonyWWang-oc@zhaoxin.com>
Link: https://patch.msgid.link/20260608190359.3254-1-TonyWWang-oc@zhaoxin.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoACPI: processor: idle: Remove redundant static variable and rename cstate check function
Huisong Li [Wed, 11 Mar 2026 06:50:38 +0000 (14:50 +0800)]
ACPI: processor: idle: Remove redundant static variable and rename cstate check function

[ Upstream commit 4d613fb1ea0516e1f69d3a4ebfbf2572d5da5368 ]

The function acpi_processor_cstate_first_run_checks() is currently called
only once during initialization in acpi_processor_register_idle_driver().

Since its execution is already limited by the caller's lifecycle, the
internal static 'first_run' variable is redundant and can be safely
removed.

Additionally, the current function name is no longer descriptive of its
behavior, so rename the function to acpi_processor_update_max_cstate()
to better reflect its actual purpose.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Link: https://patch.msgid.link/20260311065038.4151558-4-lihuisong@huawei.com
[ rjw: Changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Stable-dep-of: 66c62e6773c5 ("ACPI: processor: Add cpuidle driver check in acpi_processor_register_idle_driver()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoACPI: processor: idle: Move max_cstate update out of the loop
Huisong Li [Wed, 11 Mar 2026 06:50:37 +0000 (14:50 +0800)]
ACPI: processor: idle: Move max_cstate update out of the loop

[ Upstream commit 1f23194c8b8208bf3a43beb6c97d4c843197b6f6 ]

The acpi_processor_cstate_first_run_checks() function, which updates
max_cstate on certain platforms, only needs to be executed once.

Move this call outside of the loop to avoid redundant executions.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Link: https://patch.msgid.link/20260311065038.4151558-3-lihuisong@huawei.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Stable-dep-of: 66c62e6773c5 ("ACPI: processor: Add cpuidle driver check in acpi_processor_register_idle_driver()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoACPI: processor: idle: Remove redundant cstate check in acpi_processor_power_init
Huisong Li [Wed, 11 Mar 2026 06:50:36 +0000 (14:50 +0800)]
ACPI: processor: idle: Remove redundant cstate check in acpi_processor_power_init

[ Upstream commit db19103ea847ed139da59a2fb71773081c12cd40 ]

The function acpi_processor_cstate_first_run_checks() is responsible
for updating max_cstate and performing initial hardware validation.

Currently, this function is invoked within acpi_processor_power_init().
However, the initialization flow already ensures this is called during
acpi_processor_register_idle_driver().  Therefore, the call in
acpi_processor_power_init() is redundant and effectively performs no work,
so remove it.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Link: https://patch.msgid.link/20260311065038.4151558-2-lihuisong@huawei.com
[ rjw: Changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Stable-dep-of: 66c62e6773c5 ("ACPI: processor: Add cpuidle driver check in acpi_processor_register_idle_driver()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agocpufreq/amd-pstate: Allow writes to dynamic_epp when state isn't modified
K Prateek Nayak [Fri, 8 May 2026 05:17:45 +0000 (05:17 +0000)]
cpufreq/amd-pstate: Allow writes to dynamic_epp when state isn't modified

[ Upstream commit c5eed6ddc757e477f52b3d99bfde9e59975c72ca ]

Writing the current "dynamic_epp" state to sysfs fails with -EINVAL even
though the desired result was achieved. Allow writes to "dynamic_epp"
that does not modify the state.

Fixes: e30ca6dd5345 ("cpufreq/amd-pstate: Add dynamic energy performance preference")
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://lore.kernel.org/r/20260508051748.10484-4-kprateek.nayak@amd.com
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agocpufreq/amd-pstate: Use "epp_default_dc" as default when dynamic_epp is disabled
K Prateek Nayak [Fri, 8 May 2026 05:17:47 +0000 (05:17 +0000)]
cpufreq/amd-pstate: Use "epp_default_dc" as default when dynamic_epp is disabled

[ Upstream commit caa822d312be54e3fe1a3b52c887e0888e149c12 ]

If "dynamic_epp" is disabled, the driver initialization and the default
EPP selection from sysfs currently sets the EPP based on the power
supply state of the system at that time but there is no power supply
callbacks registered to toggle it when the power supply state changes.

This can lead to faster battery drain on platforms that start off while
being plugged to the wall but later move to battery power since the EPP
stays at AMD_CPPC_EPP_PERFORMANCE.

Use "epp_default_dc" as the default EPP selection when dynamic_epp is
disabled, restoring older behavior. On servers, this defaults to
AMD_CPPC_EPP_PERFORMANCE and on other platforms, it defaults to
AMD_CPPC_EPP_BALANCE_PERFORMANCE.

Fixes: e30ca6dd5345 ("cpufreq/amd-pstate: Add dynamic energy performance preference")
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://lore.kernel.org/r/20260508051748.10484-6-kprateek.nayak@amd.com
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agocpufreq/amd-pstate: Add support for raw EPP writes
Mario Limonciello (AMD) [Sun, 29 Mar 2026 20:38:10 +0000 (15:38 -0500)]
cpufreq/amd-pstate: Add support for raw EPP writes

[ Upstream commit 6927f21852f38db2975b5d5539cbe5241c25a99b ]

The energy performance preference field of the CPPC request MSR
supports values from 0 to 255, but the strings only offer 4 values.

The other values are useful for tuning the performance of some
workloads.

Add support for writing the raw energy performance preference value
to the sysfs file.  If the last value written was an integer then
an integer will be returned.  If the last value written was a string
then a string will be returned.

Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Stable-dep-of: caa822d312be ("cpufreq/amd-pstate: Use "epp_default_dc" as default when dynamic_epp is disabled")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agocpufreq/amd-pstate: Add static asserts for EPP indices
Mario Limonciello (AMD) [Thu, 9 Oct 2025 16:17:56 +0000 (11:17 -0500)]
cpufreq/amd-pstate: Add static asserts for EPP indices

[ Upstream commit 077f23573d29d063a950e90aa77c8e1f79580147 ]

In case a new index is introduced add a static assert to make sure
that strings and values are updated.

Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Stable-dep-of: caa822d312be ("cpufreq/amd-pstate: Use "epp_default_dc" as default when dynamic_epp is disabled")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agocpufreq/amd-pstate: Fix some whitespace issues
Mario Limonciello (AMD) [Thu, 9 Oct 2025 16:17:55 +0000 (11:17 -0500)]
cpufreq/amd-pstate: Fix some whitespace issues

[ Upstream commit e9d62ca86a5525a742742fe69e9aa316cfd4f471 ]

Add whitespace around the equals and remove leading space.

Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
Stable-dep-of: caa822d312be ("cpufreq/amd-pstate: Use "epp_default_dc" as default when dynamic_epp is disabled")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoio_uring/waitid: fix KCSAN warning on io_waitid->head
Jens Axboe [Tue, 20 Jan 2026 02:46:26 +0000 (19:46 -0700)]
io_uring/waitid: fix KCSAN warning on io_waitid->head

[ Upstream commit b994ace83a2bc7699420f6a4c6b860c8da133159 ]

Storing of the iw->head entry inside the wait_queue callback, or when
removing a waitid item, really should use proper load/store
acquire/release semantics, and KCSAN correctly warns of that. Ensure
that they do so.

Reported-by: syzbot+eb441775f4f948a0902f@syzkaller.appspotmail.com
Fixes: a48c0cbf28c0 ("io_uring/waitid: have io_waitid_complete() remove wait queue entry")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoio_uring/waitid: use io_waitid_remove_wq() consistently
Jens Axboe [Thu, 9 Oct 2025 16:55:08 +0000 (10:55 -0600)]
io_uring/waitid: use io_waitid_remove_wq() consistently

[ Upstream commit ab673c1bcaf20ac70352eeb6bf5b828462676693 ]

Use it everywhere that the wait_queue_entry is removed from the head,
and be a bit more cautious in zeroing out iw->head whenever the entry is
removed from the list.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: b994ace83a2b ("io_uring/waitid: fix KCSAN warning on io_waitid->head")
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agonet/sched: fq: clamp quantum and initial_quantum in change path
Jamal Hadi Salim [Tue, 1 Sep 2026 21:39:22 +0000 (17:39 -0400)]
net/sched: fq: clamp quantum and initial_quantum in change path

[ Upstream commit 094cc07f98dfe70a34e2a1923af17fd29b8cf622 ]

The fq change path accepts TCA_FQ_QUANTUM in [1, INT_MAX] and
TCA_FQ_INITIAL_QUANTUM up to INT_MAX, while fq_init() already clamps to
[1, 1<<20]. A user can override the init clamp via tc qdisc change,
restoring the small-quantum deficit spin that the init clamp prevents.

Narrow iq_range.max to 1<<20 so TCA_FQ_INITIAL_QUANTUM is rejected at
parse time. Clamp TCA_FQ_QUANTUM to [256, 1<<20] in fq_change() and
fq_init() quantum to [256, 1<<20] for tiny-MTU devices.

Conditions to recreate the bug:
  CONFIG_NET_SCH_FQ=y. Requires CAP_NET_ADMIN (namespace-local via
  unshare -Urn suffices).

  tc qdisc add dev dummy0 root fq
  tc qdisc change dev dummy0 root fq quantum 1 stab data 32768 size_log 15 cell_log 0

Fixes: 709f34f7c28d ("net/sched: fq: add overflow bounds to quantum and initial quantum")
Reported-by: Vega <vega@nebusec.ai>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/QDISC-0CFC.v3.20260901204856@mojatatu.com.2
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoBluetooth: btmtk: hide unused btmtk_mt6639_devs[] array
Arnd Bergmann [Thu, 2 Apr 2026 14:11:15 +0000 (16:11 +0200)]
Bluetooth: btmtk: hide unused btmtk_mt6639_devs[] array

[ Upstream commit 81f971c6abec59240e2bcfc38756bda8172fa788 ]

When USB support is disabled, the array is not referenced anywhere,
causing a warning:

drivers/bluetooth/btmtk.c:35:3: error: 'btmtk_mt6639_devs' defined but not used [-Werror=unused-const-variable=]
   35 | } btmtk_mt6639_devs[] = {
      |   ^~~~~~~~~~~~~~~~~

Move it into the #ifdef block.

Fixes: 28b7c5a6db74 ("Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agotcp: reject non zerocopy devmem tx
Pavel Begunkov [Fri, 4 Sep 2026 13:43:07 +0000 (14:43 +0100)]
tcp: reject non zerocopy devmem tx

[ Upstream commit 125755776bc6d4dd53eaf551c87e3d460625d638 ]

Devmem tcp tx doesn't work without zero-copy, however it's not currently
enforced if NETIF_F_SG isn't present. In this case, tcp_sendmsg_locked()
will try the copy path and try to copy data from an iovec which consists
of offsets into the dma-buf and would normally fail. Moreover,
d9c56501c72fd ("net: tcp: block mixing readable and unreadable frags")
relies on that and assumes that the devmem binding is present IFF we're
using the zero-copy path, which can be used to mix net-iov and pages in
a single skb, and break invariants. Let's reject devmem tx without
zero-copy.

Note, the parameter check the patch is modifying is too loose, we can
create an io_uring request with dmabuf_id and all ZC flags, but which
won't have the binding. We replace it with stricter validation.

Fixes: bd61848900bff ("net: devmem: Implement TX path")
Fixes: d9c56501c72fd ("net: tcp: block mixing readable and unreadable frags")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Reviewed-by: Mina Almasry <almasrymina@google.com>
Link: https://patch.msgid.link/fdc2478d8f21268d7078556409887d8e6ba0ad32.1788529053.git.asml.silence@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoipmr: Add __rcu to netns_ipv4.mrt.
Kuniyuki Iwashima [Sat, 2 May 2026 18:07:47 +0000 (18:07 +0000)]
ipmr: Add __rcu to netns_ipv4.mrt.

[ Upstream commit a6039776c7994dd0b9a4acce23a3f897d1688cbf ]

kernel test robot reported this Sparse warning:

  $ make C=1 net/ipv4/ipmr.o
  net/ipv4/ipmr.c:312:24: error: incompatible types in comparison expression (different address spaces):
  net/ipv4/ipmr.c:312:24:    struct mr_table [noderef] __rcu *
  net/ipv4/ipmr.c:312:24:    struct mr_table *

Let's add __rcu annotation to netns_ipv4.mrt.

Fixes: b3b6babf4751 ("ipmr: Free mr_table after RCU grace period.")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605030032.glNApko7-lkp@intel.com/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260502180755.359554-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoipmr: Call ipmr_fib_lookup() under RCU.
Kuniyuki Iwashima [Wed, 6 May 2026 06:59:53 +0000 (06:59 +0000)]
ipmr: Call ipmr_fib_lookup() under RCU.

[ Upstream commit 019c892e46544af0ae94ec833f79aa903c837666 ]

Yi Lai reported RCU splat in reg_vif_xmit() below. [0]

When CONFIG_IP_MROUTE_MULTIPLE_TABLES=n, ipmr_fib_lookup()
uses rcu_dereference() without explicit rcu_read_lock().

Although rcu_read_lock_bh() is already held by the caller
__dev_queue_xmit(), lockdep requires explicit rcu_read_lock()
for rcu_dereference().

Let's move up rcu_read_lock() in reg_vif_xmit() to
cover ipmr_fib_lookup().

[0]:
WARNING: suspicious RCU usage
7.1.0-rc2-next-20260504-9d0d467c3572 #1 Not tainted
 -----------------------------
net/ipv4/ipmr.c:329 suspicious rcu_dereference_check() usage!

other info that might help us debug this:

rcu_scheduler_active = 2, debug_locks = 1
2 locks held by syz.2.17/1779:
 #0: ffffffff87896440 (rcu_read_lock_bh){....}-{1:3}, at: local_bh_disable include/linux/bottom_half.h:20 [inline]
 #0: ffffffff87896440 (rcu_read_lock_bh){....}-{1:3}, at: rcu_read_lock_bh include/linux/rcupdate.h:891 [inline]
 #0: ffffffff87896440 (rcu_read_lock_bh){....}-{1:3}, at: __dev_queue_xmit+0x239/0x4140 net/core/dev.c:4792
 #1: ffff88801a199d18 (_xmit_PIMREG#2){+...}-{3:3}, at: spin_lock include/linux/spinlock.h:342 [inline]
 #1: ffff88801a199d18 (_xmit_PIMREG#2){+...}-{3:3}, at: __netif_tx_lock include/linux/netdevice.h:4795 [inline]
 #1: ffff88801a199d18 (_xmit_PIMREG#2){+...}-{3:3}, at: __dev_queue_xmit+0x1d5d/0x4140 net/core/dev.c:4865

stack backtrace:
CPU: 1 UID: 0 PID: 1779 Comm: syz.2.17 Not tainted 7.1.0-rc2-next-20260504-9d0d467c3572 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x121/0x150 lib/dump_stack.c:120
 dump_stack+0x19/0x20 lib/dump_stack.c:129
 lockdep_rcu_suspicious+0x15b/0x1f0 kernel/locking/lockdep.c:6878
 ipmr_fib_lookup net/ipv4/ipmr.c:329 [inline]
 reg_vif_xmit+0x2ee/0x3c0 net/ipv4/ipmr.c:540
 __netdev_start_xmit include/linux/netdevice.h:5382 [inline]
 netdev_start_xmit include/linux/netdevice.h:5391 [inline]
 xmit_one net/core/dev.c:3889 [inline]
 dev_hard_start_xmit+0x170/0x700 net/core/dev.c:3905
 __dev_queue_xmit+0x1df1/0x4140 net/core/dev.c:4871
 dev_queue_xmit include/linux/netdevice.h:3423 [inline]
 packet_xmit+0x252/0x370 net/packet/af_packet.c:276
 packet_snd net/packet/af_packet.c:3082 [inline]
 packet_sendmsg+0x39ad/0x5650 net/packet/af_packet.c:3114
 sock_sendmsg_nosec net/socket.c:797 [inline]
 __sock_sendmsg net/socket.c:812 [inline]
 ____sys_sendmsg+0xa21/0xba0 net/socket.c:2716
 ___sys_sendmsg+0x121/0x1c0 net/socket.c:2770
 __sys_sendmsg+0x177/0x220 net/socket.c:2802
 __do_sys_sendmsg net/socket.c:2807 [inline]
 __se_sys_sendmsg net/socket.c:2805 [inline]
 __x64_sys_sendmsg+0x80/0xc0 net/socket.c:2805
 x64_sys_call+0x1d9c/0x21c0 arch/x86/include/generated/asm/syscalls_64.h:47
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xc1/0x1020 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f37e563ee5d
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 93 af 1b 00 f7 d8 64 89 01 48
RSP: 002b:00007ffe5caa7fa8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00000000005c5fa0 RCX: 00007f37e563ee5d
RDX: 0000000000000000 RSI: 00002000000012c0 RDI: 0000000000000004
RBP: 00000000005c5fa0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000000 R14: 00000000005c5fac R15: 00000000005c5fa0
 </TASK>

Fixes: b3b6babf4751 ("ipmr: Free mr_table after RCU grace period.")
Reported-by: syzkaller <syzkaller@googlegroups.com>
Reported-by: Yi Lai <yi1.lai@intel.com>
Closes: https://lore.kernel.org/netdev/afrY34dLXNUboevf@ly-workstation/
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260506065955.1695753-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoerofs: fix EFSCORRUPTED on multi-algorithm images in z_erofs_map_sanity_check()
Zhan Xusheng [Mon, 1 Jun 2026 08:51:36 +0000 (16:51 +0800)]
erofs: fix EFSCORRUPTED on multi-algorithm images in z_erofs_map_sanity_check()

[ Upstream commit 27f2d085bd72abe4235689d34d8654cfc876d568 ]

Commit a5242d37c83a ("erofs: error out obviously illegal extents in
advance") changed the per-extent algorithm presence check from "is the
bit set" to "is the only bit set":
  -      !(sbi->available_compr_algs & (1 << map->m_algorithmformat))
  + (sbi->available_compr_algs ^ BIT(map->m_algorithmformat))

`available_compr_algs` is a bitmap of every compression algorithm
available in the image (z_erofs_parse_cfgs() iterates it with
for_each_set_bit()), so an image that enables more than one algorithm
has multiple bits set.  XOR is zero only when the bitmap is exactly
BIT(map->m_algorithmformat); for any image with two or more algorithms
the test is non-zero for every extent and the read fails with
-EFSCORRUPTED ("inconsistent algorithmtype %u").

Reproducer (mkfs.erofs from erofs-utils 1.7.1):
  $ mkdir src
  $ yes A | head -c 100K > src/a
  $ head -c 64K /dev/zero > src/b
  $ mkfs.erofs -zlz4:deflate multi.erofs src
  $ mount -t erofs -o loop multi.erofs /mnt
  $ cat /mnt/a >/dev/null
  cat: /mnt/a: Structure needs cleaning
  $ dmesg | tail
    erofs (device loop0): inconsistent algorithmtype 0 for nid 46
    erofs (device loop0): read error -117 @ 0 of nid 46

The erofs on-disk format (Z_EROFS_COMPRESSION_MAX = 4 with LZ4, LZMA,
DEFLATE, ZSTD) and the kernel parser explicitly support
multi-algorithm images, and erofs-utils 1.7.1 generates them via the
"-z X:Y" syntax.

Restore the original per-bit presence check.

Fixes: a5242d37c83a ("erofs: error out obviously illegal extents in advance")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoerofs: relax sanity check for tail pclusters due to ztailpacking
Gao Xiang [Wed, 8 Jul 2026 03:18:45 +0000 (11:18 +0800)]
erofs: relax sanity check for tail pclusters due to ztailpacking

[ Upstream commit d3386e17393bec1341cfeedb9d08d6846ccd6fb2 ]

If the tail data can be inlined into the inode meta block, it should
be converted into a regular tail pcluster.

In principle, it should be converted into an uncompressed pcluster if
there is not enough gain to use compression (map->m_llen < map->m_plen);
but since there are various shipped images, relax the condition for
ztailpacking tail pcluster fallback instead of reporting corruption
incorrectly.

Reported-and-tested-by: Yifan Zhao <zhaoyifan28@huawei.com>
Reported-by: Alberto Salvia Novella <es20490446e@gmail.com>
Closes: https://github.com/erofs/erofs-utils/issues/51
Fixes: a5242d37c83a ("erofs: error out obviously illegal extents in advance")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoblock: fix merging data-less bios
Keith Busch [Tue, 11 Nov 2025 14:06:20 +0000 (06:06 -0800)]
block: fix merging data-less bios

[ Upstream commit fd9ecd005252b595fd02ff7fcc4056251027404d ]

The data segment gaps the block layer tracks doesn't apply to bio's that
don't have data. Skip calculating this to fix a NULL pointer access.

Fixes: 2f6b2565d43cdb5 ("block: accumulate memory segment gaps per bio")
Reported-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoblk-mq-dma: always initialize dma state
Keith Busch [Wed, 10 Dec 2025 10:43:46 +0000 (02:43 -0800)]
blk-mq-dma: always initialize dma state

[ Upstream commit a0750fae73c55112ea11a4867bee40f11e679405 ]

Ensure the dma state is initialized when we're not using the contiguous
iova, otherwise the caller may be using a stale state from a previous
request that could use the coalesed iova allocation.

Fixes: 2f6b2565d43cdb5 ("block: accumulate memory segment gaps per bio")
Reported-by: Sebastian Ott <sebott@redhat.com>
Tested-by: Sebastian Ott <sebott@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoblock: save page offset gaps in cloned bio
Keith Busch [Wed, 19 Aug 2026 15:49:37 +0000 (08:49 -0700)]
block: save page offset gaps in cloned bio

[ Upstream commit 96c8ea3c5add7920b3c43840d1ea76b3354c8d2d ]

The cloned bio needs to inherit the accumulated gaps between vectors so
that we can know if this bio can subscribe to the iova coalescing
optimization.

When cloning for a split, the gap only applies to the front bio since
that's as far as has been processed. The remaining bio can reset its
gaps to 0 since it advanced past the checked vectors, and will start its
accounting from there on the next split check.

Fixes: 2f6b2565d43c ("block: accumulate memory segment gaps per bio")
Reported-by: Eric Auger <eauger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260819154937.3903312-1-kbusch@meta.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agointegrity: Eliminate weak definition of arch_get_secureboot()
Nathan Chancellor [Mon, 9 Mar 2026 20:37:02 +0000 (13:37 -0700)]
integrity: Eliminate weak definition of arch_get_secureboot()

[ Upstream commit 7caedbb5ade345df0eec0bf01035c780919a9f56 ]

security/integrity/secure_boot.c contains a single __weak function,
which breaks recordmcount when building with clang:

  $ make -skj"$(nproc)" ARCH=powerpc LLVM=1 ppc64_defconfig security/integrity/secure_boot.o
  Cannot find symbol for section 2: .text.
  security/integrity/secure_boot.o: failed

Introduce a Kconfig symbol, CONFIG_HAVE_ARCH_GET_SECUREBOOT, to indicate
that an architecture provides a definition of arch_get_secureboot().
Provide a static inline stub when this symbol is not defined to achieve
the same effect as the __weak function, allowing secure_boot.c to be
removed altogether. Move the s390 definition of arch_get_secureboot()
out of the CONFIG_KEXEC_FILE block to ensure it is always available, as
it does not actually depend on KEXEC_FILE.

Reported-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 31a6a07eefeb ("integrity: Make arch_ima_get_secureboot integrity-wide")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agoapparmor: fix kernel-doc comments for inview
John Johansen [Mon, 2 Feb 2026 11:37:18 +0000 (03:37 -0800)]
apparmor: fix kernel-doc comments for inview

[ Upstream commit 3734b9463bd4fb5ac350842db55e2e0ccbf1b7a5 ]

subns was renamed inview to better reflect the function of the flag.
Unfortunately the kernel-doc was not properly updated in 2 places.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202602020737.vGCZFds1-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202602021427.PvvDjgyL-lkp@intel.com/
Fixes: 796c146fa6c82 ("apparmor: split xxx_in_ns into its two separate semantic use cases")
Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7581: fix incorrect led mapping in phy4_led1 pin function
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:36 +0000 (05:03 +0300)]
pinctrl: airoha: an7581: fix incorrect led mapping in phy4_led1 pin function

[ Upstream commit e20c85c79cc2f45b87eb3dab38d4c641bbf83ed6 ]

phy4_led1 pin function maps led incorrectly. It uses the same map as
phy3_led1. PHY{X} should map to LAN{N}_PHY_LED_MAP(X-1).

Fixes: 579839c9548c ("pinctrl: airoha: convert PHY LED GPIO to macro")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: Fix AIROHA_PINCTRL_CONFS_DRIVE_E2 in an7583_pinctrl_match_data
Nathan Chancellor [Wed, 12 Nov 2025 18:44:30 +0000 (11:44 -0700)]
pinctrl: airoha: Fix AIROHA_PINCTRL_CONFS_DRIVE_E2 in an7583_pinctrl_match_data

[ Upstream commit 0341d1b1ebf10bcbb9f35e174e83dbb21068387d ]

Clang warns (or errors with CONFIG_WERROR=y / W=e):

  pinctrl/mediatek/pinctrl-airoha.c:2064:41: error: variable 'an7583_pinctrl_drive_e2_conf' is not needed and will not be emitted [-Werror,-Wunneeded-internal-declaration]
   2064 | static const struct airoha_pinctrl_conf an7583_pinctrl_drive_e2_conf[] = {
        |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Due to a typo, an7583_pinctrl_drive_e2_conf is only used within
ARRAY_SIZE() (hence no instance of -Wunused-variable), which is
evaluated at compile time, so it will not be needed in the final object
file.

Fix the .confs assignment for AIROHA_PINCTRL_CONFS_DRIVE_E2 in
an7583_pinctrl_match_data to clear up the warning.

Closes: https://github.com/ClangBuiltLinux/linux/issues/2142
Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Acked-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: add missed gpio32 pin group
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:33 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: add missed gpio32 pin group

[ Upstream commit 81cc2285cea84e3ed8688d353e1250cf8899c80a ]

gpio32 pin group is missed for an7583 SoC. This patch add it.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: fix misprint in gpio19 pinconf
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:35 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: fix misprint in gpio19 pinconf

[ Upstream commit a7f3e2b7730fc1d6c7431af49e0dc1ee97589795 ]

Pin 21 (gpio19) duplicate pinconf settings of pin 20. Fix it using
a proper bit number in the configuration register.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: fix incorrect led mapping in phy4_led1 pin function
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:37 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: fix incorrect led mapping in phy4_led1 pin function

[ Upstream commit a3602577fdfc49c6dc08d67304426d5ef6d7dec6 ]

phy4_led1 pin function maps led incorrectly. It uses the same map as
phy3_led1. PHY{X} should map to LAN{N}_PHY_LED_MAP(X-1).

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: fix gpio21 pin group
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:39 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: fix gpio21 pin group

[ Upstream commit abf92c45cc82e9a01aa581f9fbc790e78250a4d4 ]

gpio21 pin group refers to gpio22 pin, this is wrong.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: fix phy1_led1 pin function
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:41 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: fix phy1_led1 pin function

[ Upstream commit dbe28a2a22a3455d1adbf9fd61d3537603ac3072 ]

phy1_led1 pin function wrongly refers to gpio1 instead of gpio11.
Fix it.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
5 days agopinctrl: airoha: an7583: remove undefined groups from pcm_spi pin function
Mikhail Kshevetskiy [Sat, 6 Jun 2026 02:03:42 +0000 (05:03 +0300)]
pinctrl: airoha: an7583: remove undefined groups from pcm_spi pin function

[ Upstream commit 7b87a686a5ab138b3f8ca3d7e3489d8371c02695 ]

pcm_spi_int, pcm_spi_cs2, pcm_spi_cs3, pcm_spi_cs4 pin groups are not
defined, so pcm_spi function can't be applied to these groups.

Fixes: 3ffeb17a9a27 ("pinctrl: airoha: add support for Airoha AN7583 PINs")
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
Signed-off-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>