]> git.hungrycats.org Git - linux/log
linux
35 hours 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
35 hours 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)

35 hours 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)

35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
35 hours 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
2 days agobtrfs: remove TRANS_JOIN_NOLOCK
Tal Zussman [Thu, 17 Sep 2026 04:00:13 +0000 (00:00 -0400)]
btrfs: remove TRANS_JOIN_NOLOCK

btrfs_join_transaction_spacecache() was the only user of
TRANS_JOIN_NOLOCK and is gone, so remove the join type, its entries in
the blocked types table, and the special cases in join_transaction() and
start_transaction().

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: stop reading free space inodes from the commit root
Tal Zussman [Thu, 17 Sep 2026 04:00:12 +0000 (00:00 -0400)]
btrfs: stop reading free space inodes from the commit root

Free space inode data was only read when loading the v1 cache, which is
gone, so btrfs_get_extent() and btrfs_lookup_bio_sums() no longer need
to search the commit root for them.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: stop special-casing free space inodes in the delalloc accounting
Tal Zussman [Thu, 17 Sep 2026 04:00:11 +0000 (00:00 -0400)]
btrfs: stop special-casing free space inodes in the delalloc accounting

Free space inodes never have delalloc or outstanding extents any more,
so they don't need to be kept off the root's delalloc inode list or out
of the outstanding extents tracepoint.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the free space inode special cases from the COW paths
Tal Zussman [Thu, 17 Sep 2026 04:00:10 +0000 (00:00 -0400)]
btrfs: remove the free space inode special cases from the COW paths

Free space inodes are never written anymore, so drop the special cases
for them in cow_file_range(), fallback_to_cow(),
can_nocow_file_extent() and btrfs_finish_one_ordered().

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the free space inode ordered extent special cases
Tal Zussman [Thu, 17 Sep 2026 04:00:09 +0000 (00:00 -0400)]
btrfs: remove the free space inode ordered extent special cases

Free space inodes never have ordered extents anymore. Drop the lockdep
exceptions for them and btrfs_join_transaction_spacecache(), which was
only used to finish their ordered extents during a commit.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE
Tal Zussman [Thu, 17 Sep 2026 04:00:08 +0000 (00:00 -0400)]
btrfs: remove BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE

Free space inodes no longer reserve data or delalloc space, as nothing
writes to them. Remove the flush mode and the special cases that
selected it.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the free space cache trimming ranges
Tal Zussman [Thu, 17 Sep 2026 04:00:07 +0000 (00:00 -0400)]
btrfs: remove the free space cache trimming ranges

cache_writeout_mutex and trimming_ranges let the v1 cache writer see
ranges that were unlinked from the free space tree while being
discarded. Nothing consumes the list anymore, and the tree itself is
protected by tree_lock, so remove them.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: replace btrfs_set_free_space_cache_v1_active() with a cleanup helper
Tal Zussman [Thu, 17 Sep 2026 04:00:06 +0000 (00:00 -0400)]
btrfs: replace btrfs_set_free_space_cache_v1_active() with a cleanup helper

The only caller passes active = false. Turn it into
btrfs_cleanup_free_space_cache_v1() and fold the block group loop into
it.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the SPACE_CACHE mount option flag
Tal Zussman [Thu, 17 Sep 2026 04:00:05 +0000 (00:00 -0400)]
btrfs: remove the SPACE_CACHE mount option flag

Nothing sets BTRFS_MOUNT_SPACE_CACHE anymore, so every test of it is
false. Remove the flag, the checks rejecting the v1 cache on zoned
filesystems and for sector sizes other than the page size, and the
deprecation warning. Show a read-only filesystem that still has an old
cache as nospace_cache, since that's what's in effect. space_cache and
space_cache=v1 keep falling back to no space cache with a warning.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove btrfs_disk_cache_state
Tal Zussman [Thu, 17 Sep 2026 04:00:04 +0000 (00:00 -0400)]
btrfs: remove btrfs_disk_cache_state

With neither the writer nor the loader left, nothing acts on
disk_cache_state. Remove it, the need_clear handling when reading block
groups, and the enum. While at it, drop the unused cache_generation
field from struct btrfs_block_group.

lookup_free_space_inode() converted old style space inodes by clearing
disk_cache_state so the cache would be rewritten with the new inode
flags. Without that it only sets flags on the in-memory inode, which
every remaining caller truncates or deletes right after, so drop the
conversion too.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the v1 space cache load path
Tal Zussman [Thu, 17 Sep 2026 04:00:03 +0000 (00:00 -0400)]
btrfs: remove the v1 space cache load path

Nothing writes a v1 space cache any more, and since commit 545e560a5b0f
("btrfs: disable v1 space cache") the mount option can't be enabled to
read one either. Remove load_free_space_cache(), its io_ctl helpers and
struct btrfs_io_ctl. Drop the gfp constraint on the inode mapping as
well, it only covered the cache's page cache allocations.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: drop the transaction handle from the prealloc helpers
Tal Zussman [Thu, 17 Sep 2026 04:00:02 +0000 (00:00 -0400)]
btrfs: drop the transaction handle from the prealloc helpers

The v1 space cache created its inode during the transaction commit, and
btrfs_prealloc_file_range_trans() existed so that preallocation could
reuse the open handle. It was the only caller passing a transaction, so
__btrfs_prealloc_file_range() and insert_prealloc_file_extent() now
always start their own. Fold the wrapper into
btrfs_prealloc_file_range() and drop the parameter.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: rename cache_write_mutex to dirty_bgs_update_mutex
Tal Zussman [Thu, 17 Sep 2026 04:00:01 +0000 (00:00 -0400)]
btrfs: rename cache_write_mutex to dirty_bgs_update_mutex

The v1 space cache writeout is gone, but the mutex is still needed. It
keeps btrfs_remove_block_group() from deleting a block group item while
btrfs_start_dirty_block_groups() is updating it outside the commit
critical section.

Rename it to reflect what it protects, and update the comments around
the dirty block group writeout that still refer to the space cache.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the v1 space cache write path
Tal Zussman [Thu, 17 Sep 2026 04:00:00 +0000 (00:00 -0400)]
btrfs: remove the v1 space cache write path

Nothing writes out a v1 space cache any more. Remove the writers and
their io_ctl helpers, along with create_free_space_inode() and
btrfs_prealloc_file_range_trans(), whose only user was the cache inode
creation. The io_list and io_ctl block group fields were only used by
the writers, so remove them too.

btrfs_truncate_free_space_cache() only needed the block group to wait
for and clear in-flight cache IO, so drop that parameter.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the free space cache endio workqueue
Tal Zussman [Thu, 17 Sep 2026 03:59:59 +0000 (23:59 -0400)]
btrfs: remove the free space cache endio workqueue

Free space inodes are no longer written to, so nothing queues ordered
extent completion on endio_freespace_worker. Remove it and always use
endio_write_workers in btrfs_queue_ordered_fn().

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove the v1 space cache writeout from the transaction commit
Tal Zussman [Thu, 17 Sep 2026 03:59:58 +0000 (23:59 -0400)]
btrfs: remove the v1 space cache writeout from the transaction commit

Nothing sets SPACE_CACHE anymore, so the dirty block group writers never
have a cache to write out or wait for. Remove cache_save_setup(),
btrfs_setup_space_cache(), the io_list handling, the io_bgs list and
BTRFS_TRANS_CACHE_ENOSPC, and the abort-time cleanup of in-flight cache
IO.

The -ENOENT retry in btrfs_write_dirty_block_groups() handled a free
space endio worker creating a block group during the commit critical
section, so drop it too.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: stop enabling the v1 space cache from the on-disk state
Tal Zussman [Thu, 17 Sep 2026 03:59:57 +0000 (23:59 -0400)]
btrfs: stop enabling the v1 space cache from the on-disk state

Since commit 545e560a5b0f ("btrfs: disable v1 space cache") the mount
options can no longer request the v1 space cache, but a filesystem with
an active v1 cache and no free space tree still enables it from
cache_generation, and remount does the same. Drop both, so SPACE_CACHE
can never be set.

btrfs_start_pre_rw_mount() then sees the on-disk cache as active but
unwanted and cleans it up, as -o nospace_cache does today. That covers
the read-only to read-write remount as well, so drop the toggle in
btrfs_remount_cleanup(), which would otherwise start a transaction on
remounts of a read-only filesystem with an old cache.

The cleanup is now unconditional, and the first read-write mount fails
if it fails, as it did with -o nospace_cache. This also lets an old
filesystem mount without options when the page size is larger than the
sector size, which btrfs_check_features() rejected once SPACE_CACHE was
set from the superblock.

Assisted-by: Claude:claude-fable-5-1
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: drop unused uring encoded IO REISSUE stash helpers
Yang Xiuwei [Wed, 19 Aug 2026 02:54:36 +0000 (10:54 +0800)]
btrfs: drop unused uring encoded IO REISSUE stash helpers

After not keeping state across -EAGAIN, restoring bc->data on REISSUE is
dead.  Remove it, stop using the cmd PDU on the write path, and fold the
read -EAGAIN check into the existing error path.

Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: don't stash uring encoded data across -EAGAIN
Yang Xiuwei [Wed, 19 Aug 2026 02:54:35 +0000 (10:54 +0800)]
btrfs: don't stash uring encoded data across -EAGAIN

Returning -EAGAIN while leaving btrfs_uring_encoded_data in the cmd PDU
leaks if the request is cancelled or the ring exits before reissue.
io_uring does not free driver PDU allocations on cleanup.

Write: io_queue_sqe() always issues with IO_URING_F_NONBLOCK first, so
return -EAGAIN before allocating and free data on every exit.

Read: free on nowait -EAGAIN too; only -EIOCBQUEUED keeps the
allocation for btrfs_uring_read_finished().

Fixes: 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
Fixes: e32dcdb0af9f ("btrfs: add io_uring interface for encoded writes")
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: unlock inode and extent in caller when uring read extent fails
Yang Xiuwei [Wed, 19 Aug 2026 02:54:34 +0000 (10:54 +0800)]
btrfs: unlock inode and extent in caller when uring read extent fails

btrfs_uring_read_extent() runs only after btrfs_encoded_read() has
taken the inode shared lock and the extent lock.  On failure it used to
unlock in out_fail, and a pages-array allocation failure returned
-ENOMEM without unlocking at all.

Unlock in the caller instead on all failure returns, matching the
copy_to_user() error path.  The deferred -EIOCBQUEUED path still unlocks
in btrfs_uring_read_finished().

Fixes: 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
Suggested-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: free iov when btrfs_uring_read_extent fails
Yang Xiuwei [Wed, 19 Aug 2026 02:54:33 +0000 (10:54 +0800)]
btrfs: free iov when btrfs_uring_read_extent fails

After btrfs_uring_read_extent(), the caller always jumped to out_acct.
That skips kfree(data->iov), which is only correct for -EIOCBQUEUED
where the deferred path owns the iov. On failure, fall through to
out_free instead.

Fixes: 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: always return -EIOCBQUEUED after btrfs_uring_read_extent_endio
Yang Xiuwei [Wed, 19 Aug 2026 02:54:32 +0000 (10:54 +0800)]
btrfs: always return -EIOCBQUEUED after btrfs_uring_read_extent_endio

If all bios finish before btrfs_encoded_read_regular_fill_pages()
returns, it calls btrfs_uring_read_extent_endio() and previously
returned the I/O status.  A negative errno then made
btrfs_uring_read_extent() unlock and free while
btrfs_uring_read_finished() did the same again.

Return -EIOCBQUEUED so only the deferred path cleans up.

Reported-by: Yue Sun <samsun1006219@gmail.com>
Closes: https://lore.kernel.org/linux-btrfs/20260630091609.3414-1-samsun1006219@gmail.com/
Suggested-by: Jens Axboe <axboe@kernel.dk>
Fixes: 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: === misc-next on b-for-next ===
David Sterba [Wed, 21 Feb 2024 14:50:10 +0000 (15:50 +0100)]
btrfs: === misc-next on b-for-next ===

Any commits after this one are for testing and evaluation only.

Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: keep unused block groups queued when a pass fails
Boris Burkov [Wed, 16 Sep 2026 22:17:24 +0000 (15:17 -0700)]
btrfs: keep unused block groups queued when a pass fails

Once any block_group sets ret!=0 in the main loop of
btrfs_delete_unused_bgs(), the check
  if (ret || btrfs_mixed_space_info(space_info)) {
          btrfs_put_block_group(block_group);
          continue;
  }
skips the rest of the unused bgs while unlinking them from
fs_info->unused_bgs. There is no "level triggered" re-queueing of empty
block groups onto fs_info->unused_bgs so it is possible to leak quite a
bit of space this way and unless we happen to get a balance or
re-use/re-empty one of these bgs, they are leaked for good, which can
lead to a spurious enospc later.

While I have observed such leaked blocked groups that are empty but not
on the unused_bgs list on production systems, I have not observed that
it is definitely due to this issue. I also reproduced this behavior by
injecting an ENOSPC error from btrfs_start_trans_remove_block_group
which can also fail with ENOMEM, so this feels like a legitimate
injection point.

To fix it, instead of checking ret in the loop, just break out of the
loop when ret != 0. Also, link the bg to the retry list at the
individual failure sites so that the failing bg is not leaked.

Assisted-by: LLM (reproducer/error injection)
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove duplicate error message when writing super blocks
Filipe Manana [Wed, 16 Sep 2026 16:36:11 +0000 (17:36 +0100)]
btrfs: remove duplicate error message when writing super blocks

If the total error count is greater the maximum allowed number of errors,
we print exactly the same error message twice. Remove one of the messages.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: remove redundant eb generation check in btrfs_buffer_uptodate()
Filipe Manana [Wed, 16 Sep 2026 16:20:52 +0000 (17:20 +0100)]
btrfs: remove redundant eb generation check in btrfs_buffer_uptodate()

It's pointless to check if the extent buffer's generation does not match
the value of 'parent_transid' because if it does, then we have already
entered the previous if statement and returned from the function.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: add missing unlikely to a couple error checks during sys chunk array validation
Filipe Manana [Wed, 16 Sep 2026 16:11:51 +0000 (17:11 +0100)]
btrfs: add missing unlikely to a couple error checks during sys chunk array validation

It's unexpected to find errors during sys chunk array validation and all
checks use the unlikely tag except for two of them, so add it.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: check if there is space for chunk item when validating sys chunk array
Filipe Manana [Wed, 16 Sep 2026 15:49:37 +0000 (16:49 +0100)]
btrfs: check if there is space for chunk item when validating sys chunk array

We checked if have enough remaining space for a key before dereferencing a
key, but we then dereference a chunk item, to get the number of stripes,
without checking if there is space for the item. So add a check to see if
there is enough space for a chunk item before dereferencing the item to
extract the stripe count.

Fixes: 2a9bb78cfd36 ("btrfs: validate system chunk array at btrfs_validate_super()")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: abort transaction on failure to update inode for hole punching and reflinking
Filipe Manana [Wed, 16 Sep 2026 14:43:41 +0000 (15:43 +0100)]
btrfs: abort transaction on failure to update inode for hole punching and reflinking

If we fail to update the inode we error out without aborting the
transaction, which can result in a persistent inconsistency if after
the failure the transaction is committed, as we have dropped file
extent items from a range and either punched a hole or insert a new file
extent item for that range (for reflinks).

So add the missing transaction abort.

Fixes: 2aaa66558172 ("Btrfs: add hole punching")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: add "/dev/root" exception for device path update
Qu Wenruo [Sat, 12 Sep 2026 08:42:06 +0000 (18:12 +0930)]
btrfs: add "/dev/root" exception for device path update

[BEHAVIOR CHANGE]
Since commit 108cc8733989 ("btrfs: fix a lockdep caused by path
resolution during device scan"), users with btrfs rootfs but without an
initramfs are complaining that grub2 can no longer detect the rootfs
device:

 /usr/sbin/grub-probe: error: cannot find a device for / (is /dev mounted?).

[CAUSE]
Although using btrfs without an initramfs is not recommended (if a new
device is added to the rootfs, the system can no longer boot, as there
is no way to register all devices), there is still a minority of users
doing this.

If there is no initramfs but the rootfs is on a block-device-based
filesystem, the kernel boot sequence initializes a minimal ramfs/tmpfs,
creates "/dev/root" with the proper device number for the rootfs, and
then invokes mount using "/dev/root".

That's why the end user will get the mount output:

 /dev/root on / rw

To be honest, this is a user space problem: no one should trust the
device path shown in mount, only the device number.

E.g. one can even use "/proc/self/fd/*" to mount an fs, and that proc
path will be registered, and no one else can mount that fs using that
path.

Before commit 108cc8733989 ("btrfs: fix a lockdep caused by path
resolution during device scan"), btrfs had an internal path lookup
workaround to address such weird paths, it works by checking if the
existing device path can still resolve to the device number.

But that path resolution is deadlock prone, thus it's replaced by a
simple devt check.

This works fine in most cases, as a btrfs device is registered by udev at
boot time, thus all paths are sane.

However this will not work for systems without an initramfs, causing the
unreachable "/dev/root" path to exist forever without a way to rename
it.

[WORKAROUND]
Despite updating the docs to discourage root btrfs without an initramfs,
add an exception to the device path rename requirement.

If the device has the name "/dev/root", we know it's booted without
an initramfs, and only for that case we allow device path update.

And if someone intentionally created "/dev/root" after boot, the
existing devt checks will reject that weird name as usual.

This should satisfy the minority of users, and still keep most of the
existing guards preventing unexpected/unnecessary device path updates.

But still, I prefer grub2 to implement a more robust device
number based probing, and no one should use btrfs as rootfs without an
initramfs.

Fixes: 108cc8733989 ("btrfs: fix a lockdep caused by path resolution during device scan")
Link: https://lore.kernel.org/linux-btrfs/CAKLYgeL7nrA4nXcewdv9Fqg_s=3GS=vmoypnEiZBKQ7rySZFuQ@mail.gmail.com/
Link: https://lore.kernel.org/linux-btrfs/dfbe1e27-dab8-4d55-8cf3-0b28eeac5df4@gmail.com/
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
2 days agobtrfs: clear free space tree creation state on rebuild failure
Guanghui Yang [Wed, 16 Sep 2026 05:16:38 +0000 (05:16 +0000)]
btrfs: clear free space tree creation state on rebuild failure

btrfs_rebuild_free_space_tree() sets BTRFS_FS_CREATING_FREE_SPACE_TREE
before rebuilding the free space tree.  Several error paths return
without clearing this flag.

The transaction restart failure path can leave the flag set on a live
filesystem, causing delayed reference processing to be skipped. Clear it
on all free space tree rebuild failure paths. Keep
BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves
the free space tree untrusted. Callers must fall back to extent-tree
caching.

Fixes: 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
CC: stable@vger.kernel.org # 6.14+
Assisted-by: LLM
Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Signed-off-by: David Sterba <dsterba@suse.com>
3 days agobtrfs: handle lack of space when cleaning up verity items
Daniel Linjama [Wed, 16 Sep 2026 06:15:56 +0000 (09:15 +0300)]
btrfs: handle lack of space when cleaning up verity items

When enable_verity() hits the qgroup limit, rollback_verity() needs its
own metadata reservation. When the qgroup limit or lack of space refuses
the rollback, the whole filesystem is forced read-only even though the
qgroup limit was for one subvolume only. Also orphan cleanup at the next
mount fails the same way, so the leftover items are never removed: with
-EDQUOT the subvolume stays unreachable, and with -ENOSPC on a full
filesystem the next read-write mount fails.

Start transactions with btrfs_start_transaction_fallback_global_rsv() in
btrfs_orphan_cleanup(), drop_verity_items() and rollback_verity(). Those
calls only delete items and free the space in the end, so they may use
the global reserve and skip the qgroup limit, which avoids -ENOSPC and
-EDQUOT.

Fixes: 146054090b08 ("btrfs: initial fsverity support")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Daniel Linjama <daniel@dev.linjama.com>
Signed-off-by: David Sterba <dsterba@suse.com>
3 days agobtrfs: fix creation of compressed inline extents that don't save space
Filipe Manana [Mon, 14 Sep 2026 17:11:30 +0000 (18:11 +0100)]
btrfs: fix creation of compressed inline extents that don't save space

If the compressed data of an inline extent is larger than or equals to the
size of the uncompressed data, we are still allowing the creation of the
compressed inline extent, which does not result in any benefits, quite the
contrary as we waste metadata space and have to decompress when reading.

This is a recent regression introduced in commit 3eaf5f082c4c ("btrfs:
extract inlined creation into a dedicated delalloc helper").

It happens because we are passing the block size to btrfs_compress_bio(),
so we don't get -E2BIG from the compression code anymore, but we can not
pass i_size either, because if i_size is smaller than sector size, we
end up never creating lzo compressed inline extent for such small i_size
values. So refuse the compressed result at run_delalloc_inline() if
its size is not smaller than the uncompressed size (i_size).

Reported-by: Hanabishi <i.r.e.c.c.a.k.u.n+kernel.org@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/c97652a5-ac6b-4de6-aa23-3cdebc01d00b@gmail.com/
Fixes: 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper")
CC: stable@vger.kernel.org # 7.1+
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
3 days agobtrfs: simplify heuristic_collect_sample() to handle large folios better
Qu Wenruo [Thu, 10 Sep 2026 02:05:53 +0000 (11:35 +0930)]
btrfs: simplify heuristic_collect_sample() to handle large folios better

Currently heuristic_collect_sample() is purely page size based, and it
has a lot of extra handling just inside the page.

However we already have large folio support, there is no need to look up
the same folio repeatedly.

Simplify the handling by:

- Use @cur as the iterator instead of page index

- Handle the sample copying on a per-folio basis
  Although kmap_local_folio() requires an offset to handle HIGHMEM
  page mapping, we have rejected large folios for HIGHMEM systems
  completely.

  So we can safely handle all sample copying inside the folio in one
  go.

- Remove unnecessary unaligned range handling
  All the range passed in should be block aligned, thus there is no need
  to handle cases where sample crosses the block boundary.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
3 days agobtrfs: fix off-by-one end related to inode_need_compress()
Qu Wenruo [Thu, 10 Sep 2026 02:05:52 +0000 (11:35 +0930)]
btrfs: fix off-by-one end related to inode_need_compress()

In most cases btrfs uses @end as the inclusive end bytenr for a range,
and this applies to inode_need_compress().

However we have several sites not following the inclusive bytenr:

- run_delalloc_inline()
  Which assigned @blocksize as @end for inode_need_compress()

  This makes inode_need_compress() always skip the disk_i_size check.

- heuristic_collect_sample()
  Which assigned "start + BTRFS_MAX_UNCOMPRESSED" to @end, which is
  the exclusive bytenr.

Neither is really causing any real problem, as
heuristic_collect_sample() has proper checks to avoid reading anything
beyond @end, and the sampling read size is 16 bytes, so it has enough
headroom to handle that off-by-one problem.

But still I do not like anything out of the common scheme, so fix the
off-by-one @end for both call sites, and add extra ASSERT()s to catch
such unaligned parameters.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
3 days agobtrfs: cleanup and rename submit_extent_folio()
Qu Wenruo [Sun, 13 Sep 2026 11:29:15 +0000 (20:59 +0930)]
btrfs: cleanup and rename submit_extent_folio()

Cleanup submit_extent_folio() by:

- Remove @size parameter
  Since commit b2e743927fdd ("btrfs: make btrfs_do_readpage() to do
  block-by-block read"), all callers are passing sectorsize as @size,
  so there is no need for such parameter.

  Furthermore since we only write one block at a time, there is no need
  for a while() loop, nor the advance of various local variables.

- Update the comments on the parameter list
  * @disk_bytenr is shared for both read and write
  * rename @page to @folio

- Update the return value to return 0 or error
  Since we won't queue multiple blocks anyway, there is no point in
  returning the queued bytes.
  It makes more sense to return an error code, although the only error
  code will be -EUCLEAN for writes.

- Rename submit_extent_folio() to submit_one_block()

- Rename submit_one_sector() to submit_write_sector()

- Update the error message to utilize the new returned error code inside
  submit_write_sector()

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tree-checker: cache accessor return value in CHECK_FE_ALIGNED()
Filipe Manana [Fri, 11 Sep 2026 10:56:29 +0000 (11:56 +0100)]
btrfs: tree-checker: cache accessor return value in CHECK_FE_ALIGNED()

We are calling an accessor for a file extent item multiple times in the
CHECK_FE_ALIGNED() macro, even when we don't find a corruption (once in
the if statement's expression and then once again in the expression for
the return value). This adds extra runtime overhead (which is critical
since the tree checker runs against every extent buffer when it's read
or before persisting it) and increases the module's size.

So cache the accessor's return value in a variable and use it, reducing
runtime, object size and making the source code shorter too. Also avoid
repeating twice the IS_ALIGNED() computation.

Before:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  2073340  217928   15624 2306892  23334c fs/btrfs/btrfs.ko

After:

  $ size fs/btrfs/btrfs.ko
     text    data     bss     dec     hex filename
  2073076  217928   15624 2306628  233244 fs/btrfs/btrfs.ko

Also running the following fsstress test and capturing the runtime of
check_extent_data_item() (the only caller of CHECK_FE_ALIGNED()) in
nanoseconds (using bpftrace), showed the following runtime improvements:

Test:

  mkfs.btrfs -f /dev/nullb0
  mount /dev/nullb0 /mnt
  fsstress -w -p 8 -n 5000 -s 12345 -d /mnt
  umount /mnt

Before:

  Count: 2033671
  Range:  0.000 - 1336060.000; Mean: 679.642; Median: 656.000; Stddev: 2031.323
  Percentiles:  90th: 850.000; 95th: 909.000; 99th: 1272.000
       0.000 -       6.647:      11 |
       6.647 -      28.241:      36 |
      28.241 -     110.807:     176 |
     110.807 -     426.512:   38012 #
     426.512 -    1633.663: 1983372 #####################################################
    1633.663 -    6249.399:    8315 |
    6249.399 -   23898.422:    3243 |
   23898.422 -   91382.340:     153 |
   91382.340 -  349418.114:      36 |
  349418.114 - 1336060.000:      11 |

After:

  Count: 2092797
  Range:  0.000 - 1677284.000; Mean: 627.650; Median: 617.000; Stddev: 1848.010
  Percentiles:  90th: 809.000; 95th: 859.000; 99th: 1209.000
       0.000 -       6.823:       18 |
       6.823 -      29.602:       82 |
      29.602 -     118.702:      416 |
     118.702 -     467.232:   515774 #################
     467.232 -    1830.549:  1565599 #####################################################
    1830.549 -    7163.339:     5297 |
    7163.339 -   28023.237:     4186 |
   28023.237 -  109619.427:      166 |
  109619.427 -  428793.471:       25 |
  428793.471 - 1677284.000:        4 |

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tree-checker: fix error message regarding free space extent items
Filipe Manana [Thu, 10 Sep 2026 16:48:06 +0000 (17:48 +0100)]
btrfs: tree-checker: fix error message regarding free space extent items

The error message mentions a free space info item, but we are processing a
free space extent item, so fix the message.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tree-checker: print dev extent offset in error message
Filipe Manana [Thu, 10 Sep 2026 16:37:48 +0000 (17:37 +0100)]
btrfs: tree-checker: print dev extent offset in error message

If a dev extent's offset is not sector size aligned, the error message is
printing the dev extent's objectid instead of the offset. This is a copy
paste error, as before this check we check the objectid field.

Fixes: 008e2512dc56 ("btrfs: tree-checker: add dev extent item checks")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: increment extent count once when logging extents during fast fsync
Filipe Manana [Wed, 9 Sep 2026 11:26:30 +0000 (12:26 +0100)]
btrfs: increment extent count once when logging extents during fast fsync

In btrfs_log_changed_extents() we increment the extent count twice, and
we then fallback to a transaction commit if the count reaches a threshold
of 32K. However we increment the count twice, which is confusing and
pointless. So increment the count only once and reduce the threshold to
half (16K).

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use u64 for the page indices in heuristic_collect_sample()
Tal Zussman [Wed, 9 Sep 2026 17:10:48 +0000 (13:10 -0400)]
btrfs: use u64 for the page indices in heuristic_collect_sample()

index and index_end are derived from the u64 start and end offsets, and
index is shifted back into a byte offset for offset_in_folio(), which
needs a cast to u64 to be safe on 32-bit. Make them u64 instead so the
cast goes away. They still fit pgoff_t where they are passed to
filemap_get_folio(), as they came from a valid file offset.

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use folios for reading super blocks from the block device
Tal Zussman [Mon, 7 Sep 2026 20:20:01 +0000 (16:20 -0400)]
btrfs: use folios for reading super blocks from the block device

btrfs_read_disk_super() and the zoned super block log comparison go
through read_cache_page_gfp() and page_address(), and
btrfs_release_disk_super() recovers the page with virt_to_page(). Use
mapping_read_folio_gfp(), folio_address(), and virt_to_folio() instead.
This removes the last callers of read_cache_page_gfp() and put_page()
in btrfs.

Compute the super block address with offset_in_folio() as
write_dev_supers() does, rather than assuming it is at the start of
the page.

Assisted-by: Claude:claude-fable-5-1
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: fix stale function references in compression comments
Tal Zussman [Mon, 7 Sep 2026 20:20:00 +0000 (16:20 -0400)]
btrfs: fix stale function references in compression comments

add_ra_bio_pages() was renamed to add_ra_bio_folios(), and
btrfs_compress_filemap_get_folio() wraps filemap_get_folio(), not
find_get_page(). Update the comments accordingly.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: convert heuristic_collect_sample() to use folios
Tal Zussman [Mon, 7 Sep 2026 20:19:59 +0000 (16:19 -0400)]
btrfs: convert heuristic_collect_sample() to use folios

Convert the sampling loop to folios. This removes the last caller of
find_get_page() in btrfs and saves a call to compound_head() per sampled
page. Document that the lookup is not supposed to fail with an ASSERT().

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: convert btrfs_compr_pool_scan() to use folios
Tal Zussman [Mon, 7 Sep 2026 20:19:58 +0000 (16:19 -0400)]
btrfs: convert btrfs_compr_pool_scan() to use folios

The compression pool holds order-0 folios, but btrfs_compr_pool_scan()
walks it as struct page through page->lru. Walk it as folios, matching
the other compression pool functions. This removes the last use of
page->lru in btrfs and saves a call to compound_head() per freed
folio.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tests: use eb folio helpers in extent buffer memory checks
Tal Zussman [Mon, 7 Sep 2026 20:19:57 +0000 (16:19 -0400)]
btrfs: tests: use eb folio helpers in extent buffer memory checks

dump_eb_and_memory_contents() and verify_eb_and_memory() hardcode one
page per folio instead of using get_eb_folio_index() and
get_eb_offset_in_folio() like the rest of the extent buffer code. Use
the helpers and folio_address(). This removes the last struct page usage
in the file.

No functional change. The tests only run with sectorsize == PAGE_SIZE,
and the test extent buffers are backed by order-0 folios.

Assisted-by: Claude:claude-fable-5-1
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tests: convert test_find_delalloc() to use folios
Tal Zussman [Mon, 7 Sep 2026 20:19:56 +0000 (16:19 -0400)]
btrfs: tests: convert test_find_delalloc() to use folios

This removes the last btrfs callers of find_or_create_page(),
find_lock_page(), SetPageDirty(), ClearPageDirty(), and get_page(), and
15 calls to compound_head(). The folio lookups return an ERR_PTR instead
of NULL, so adjust the error handling.

Update the comments and test messages accordingly.

The test still works in PAGE_SIZE units, which relies on the test inode
never getting large folios, so assert that the folios are order-0 where
that matters.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tests: rename process_page_range() to process_folio_range()
Tal Zussman [Mon, 7 Sep 2026 20:19:55 +0000 (16:19 -0400)]
btrfs: tests: rename process_page_range() to process_folio_range()

It already operates on folios. No functional change.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Tal Zussman <tz2294@columbia.edu>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: take commit root semaphore when iterating in mark_block_group_to_copy()
Hongling Zeng [Mon, 31 Aug 2026 05:38:01 +0000 (13:38 +0800)]
btrfs: take commit root semaphore when iterating in mark_block_group_to_copy()

mark_block_group_to_copy() iterates over the commit root with
skip_locking=true. A concurrent transaction commit can swap and free
the commit root during iteration, causing use-after-free when
accessing extent buffers.

Fix it by using path->need_commit_sem to protect the commit root search.

Fixes: 78ce9fc269af ("btrfs: zoned: mark block groups to copy for device-replace")
CC: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.5
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use kvmalloc() to allocate compression workspace buffer for zlib and zstd
Qu Wenruo [Tue, 8 Sep 2026 07:15:41 +0000 (16:45 +0930)]
btrfs: use kvmalloc() to allocate compression workspace buffer for zlib and zstd

With the experimental bs > ps support, the workspace buffer for both
zlib and zstd can be as large as 64K, and on 4K page sized systems such
kmalloc() calls have a much higher chance to fail, as that requires
physically contiguous memory to fulfill such allocation.

The same also applies to S390's hardware accelerated path, which
requires a buffer size of 4 pages.

Meanwhile lzo is already using kvmalloc() for its buffer, and there is
no special requirement for any physically contiguous memory anyway.

So change the zlib and zstd workspace buffer allocation to use
kvmalloc() to reduce the chance of memory allocation failure.

Reviewed-by: Daniel Vacek <neelx@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use kvmalloc() for uncompress_inline()
Qu Wenruo [Tue, 8 Sep 2026 07:15:40 +0000 (16:45 +0930)]
btrfs: use kvmalloc() for uncompress_inline()

Although btrfs doesn't support inlined extents larger than PAGE_SIZE
for bs > ps cases, it's still possible for the experimental bs > ps
support to mount a btrfs created on a system with a much larger page size,
thus can still hit an inlined extent that is way larger than the current
page size.

E.g. a compressed inline extent which has 32K compressed size, is created
on 64K page sized ARM64 with 64K sectorsize, then mounted on x86_64 with
the experimental bs > ps support.

In that case, when reading the compressed inline extent, we need to
allocate a buffer that is the same size as the compressed inline extent
(32K).

That kmalloc() call will request physically contiguous memory for that
32K allocation, and if the system has a very fragmented memory space,
such allocation can fail.

But there is really no reason that we require such buffer to be
physically contiguous, so change it to kvmalloc() to reduce the chance
of allocation failure for bs > ps cases.

And for all bs <= ps cases, the kvmalloc() call will just be fulfilled by
kmalloc() so this will not bring any change to the most common cases.
Only bs > ps will get the benefit of less memory allocation failure.

Reviewed-by: Daniel Vacek <neelx@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tree-log: use kvmalloc() for overwrite_item()
Qu Wenruo [Tue, 8 Sep 2026 07:15:39 +0000 (16:45 +0930)]
btrfs: tree-log: use kvmalloc() for overwrite_item()

The @src_copy buffer utilized inside overwrite_item() can be as large as
the nodesize.

For an existing btrfs with 64KiB nodesize, it means there is a high
chance to fail the kmalloc() call if there is not enough physically
contiguous pages.

Meanwhile there is really no need for such physically contiguous pages,
as we only use that buffer to compare the content of the item.

Use kvmalloc() to replace the kmalloc() call.  For most cases that
kvmalloc() call will be easily fulfilled by regular kmalloc(), but for
really large items and large nodes, kvmalloc() will have a much higher
chance to get memory allocated.

Reviewed-by: Daniel Vacek <neelx@suse.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use kvmalloc() for b-tree split_item()
Qu Wenruo [Mon, 7 Sep 2026 22:17:39 +0000 (07:47 +0930)]
btrfs: use kvmalloc() for b-tree split_item()

[BUG]
There is a bug report that the kmalloc() call inside split_item() failed
with the following call trace, and triggered a transaction abort:

  kworker/u69:8: page allocation failure: order:4, mode:0x40c40(GFP_NOFS|__GFP_COMP), nodemask=(null)
  CPU: 3 UID: 0 PID: 1154528 Comm: kworker/u69:8 Not tainted 7.0.2 #1 PREEMPTLAZY
  Workqueue: events_unbound btrfs_async_reclaim_metadata_space
  Call Trace:
   <TASK>
   dump_stack_lvl+0x47/0x60
   warn_alloc.cold+0x67/0xec
   __alloc_pages_slowpath.constprop.0+0x9bf/0xed0
   __alloc_frozen_pages_noprof+0x1ac/0x1c0
   ___kmalloc_large_node+0x9d/0xc0
   __kmalloc_noprof+0x17b/0x1f0
   split_item+0x9e/0x2e0
   btrfs_del_csums+0x285/0x400
   __btrfs_free_extent.isra.0+0x6de/0x12b0
   __btrfs_run_delayed_refs+0x522/0x10c0
   btrfs_run_delayed_refs+0x4d/0x1d0
   flush_space+0x34d/0x4e0
   do_async_reclaim_metadata_space+0x89/0x1d0
   btrfs_async_reclaim_metadata_space+0x44/0x60
   process_one_work+0x145/0x230
   worker_thread+0x185/0x2e0
   kthread+0xca/0x100
   ret_from_fork+0x14e/0x200
   ret_from_fork_asm+0x11/0x20
   </TASK>
  BTRFS error (device dm-3 state A): Transaction aborted (error -12)
  BTRFS: error (device dm-3 state A) in btrfs_del_csums:1053: errno=-12 Out of memory
  BTRFS info (device dm-3 state EA): forced readonly
  BTRFS: error (device dm-3 state EA) in do_free_extent_accounting:3168: errno=-12 Out of memory
  BTRFS error (device dm-3 state EA): failed to run delayed ref for logical 1202913873920 num_bytes 274432 type 184 action 2 ref_mod 1: -12
  BTRFS: error (device dm-3 state EA) in btrfs_run_delayed_refs:2247: errno=-12 Out of memory

[CAUSE]
The kmalloc() call is to allocate a buffer to store the full item.
However as shown in the above call trace, the order can be high (4), and
since we're using GFP_NOFS, it's impossible to reclaim memory by writing
back dirty pages.

When there is no physically contiguous memory left, such high order
allocation can easily fail, and if such kmalloc() happens in a critical
path we can trigger a transaction abort.

[FIX]
Instead of kmalloc(), which requires physically contiguous pages, use
kvmalloc().

There is no special requirement for physically contiguous pages here, we
just want virtually contiguous memory as a buffer.

Reported-by: xavierbachmeyer182 <xavierbachmeyer182@protonmail.com>
Link: https://lore.kernel.org/linux-btrfs/250decb0-d940-4fe6-9b54-d06e1b293a1b@suse.com/
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: replace is_data_bbio() with is_data_inode() for direct usage
Zhen Ni [Mon, 22 Dec 2025 03:59:42 +0000 (11:59 +0800)]
btrfs: replace is_data_bbio() with is_data_inode() for direct usage

After commit 81cea6cd7041 ("btrfs: remove btrfs_bio::fs_info by
extracting it from btrfs_bio::inode"), the btrfs_bio::inode field is
mandatory for all btrfs_bio allocations. The NULL check is redundant and
can be removed.

As is_data_bbio() would be a trivial wrapper for is_data_bbio() replace
all calls in in bio.c

Link: https://lore.kernel.org/linux-btrfs/20251219084316.1164580-1-zhen.ni@easystack.cn
Signed-off-by: Zhen Ni <zhen.ni@easystack.cn>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: zstd: avoid a copy in zstd_decompress_bio()
Usama Arif [Fri, 4 Sep 2026 16:41:48 +0000 (09:41 -0700)]
btrfs: zstd: avoid a copy in zstd_decompress_bio()

zstd_decompress_bio() gives zstd a sectorsize-sized scratch buffer, and
btrfs_decompress_buf2page() then copies the part overlapping the read bio
into the destination folios. Every delivered byte is written twice.

Instead, choose the output buffer per streaming call. zstd_map_dest()
kmaps the current page-bounded segment of the read bio, so zstd writes
into the page cache directly. The scratch buffer is kept only for output
with no destination: the prefix before a read starting inside a
compressed extent, which zstd cannot skip, and gaps left by folios
already in the page cache.

Varying the output buffer across calls is safe: btrfs uses the default
ZSTD_bm_buffered mode, where the sliding window lives in the dstream's
internal buffer and the caller's dst is a pure sink. The read bio's
iterator must still advance by exactly the bytes delivered, since
btrfs_decompress_bio() zero-fills from it; that used to happen inside
btrfs_decompress_buf2page() and is now an explicit bio_advance(), made
only for output that reached a folio.

bio_iter_iovec() exposes at most one base page, so direct output is
page-bounded. Compared to the old sectorsize-sized chunks, this can
increase stream calls when sectorsize exceeds PAGE_SIZE, but eliminates
the extra btrfs copy for output delivered to the read bio; the 64 KiB
sectorsize row below shows the copy still wins there.

Benchmarked the change in 2-vCPU x86-64 KVM guests (4 KiB pages, RAM
disk) using a 64 MiB zstd-compressed file. Results are medians of seven
cold-cache reads in each of six interleaved A/B boot pairs; mincore
confirmed zero resident pages before every run.

Normal sequential reads with readahead produced:

  sectorsize       base       patched    reduction
  4 KiB          8.678 ms     8.004 ms       7.80%
  16 KiB         8.216 ms     7.934 ms       3.64%
  64 KiB         7.875 ms     7.344 ms       6.88%

Random 4 KiB preads at 4 KiB sectorsize, means of six interleaved A/B
boot pairs, patched better in all six:

  base           patched        gain
  264.33 MB/s    272.67 MB/s     3.2%

Signed-off-by: Usama Arif <usama.arif@linux.dev>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: pre-allocate delayed dir index for non-overwrite rename
Jeff Layton [Tue, 25 Aug 2026 16:04:20 +0000 (12:04 -0400)]
btrfs: pre-allocate delayed dir index for non-overwrite rename

For rename() without an overwrite target, pre-allocate the delayed
dir index before any btree modifications so that ENOMEM can be returned
before the source is unlinked from the old directory.

Add a prealloc parameter to btrfs_add_link() that allows callers to
pass pre-allocated delayed dir index resources. When provided,
btrfs_add_link() takes ownership: it either passes the prealloc to
btrfs_insert_dir_item() (which commits or frees it), or frees it
on early error. All existing callers pass NULL to preserve the current
behavior.

In btrfs_rename(), when new_inode is NULL (no overwrite), call
btrfs_prealloc_delayed_dir_index() before the first btree modification
and pass the result through to btrfs_add_link(). If the prealloc fails,
-ENOMEM is returned before any btree state has changed. The local
prealloc pointer is cleared once ownership passes to btrfs_add_link(),
so the out_fail path only frees one we still own.

For overwrite rename (new_inode != NULL), the transaction still aborts
on ENOMEM since earlier unlink operations have already made irreversible
btree modifications.

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: handle ENOMEM from btrfs_insert_dir_item() without aborting
Jeff Layton [Tue, 25 Aug 2026 16:04:19 +0000 (12:04 -0400)]
btrfs: handle ENOMEM from btrfs_insert_dir_item() without aborting

Now that btrfs_insert_dir_item() returns -ENOMEM before modifying the
btree (thanks to delayed dir index pre-allocation), callers can handle
ENOMEM gracefully instead of aborting the transaction.

- btrfs_add_link(): add -ENOMEM to the recoverable errors alongside
  -EEXIST and -EOVERFLOW.
- btrfs_create_new_inode(): on -ENOMEM from btrfs_add_link(), orphan the
  newly-created inode instead of aborting. The inode item was already
  written with nlink 1, and discard_new_inode() marks it bad so eviction
  won't delete it. So clear_nlink() alone is not enough: persist nlink 0
  via btrfs_update_inode(), otherwise orphan cleanup would see nlink > 0,
  drop the orphan item, and leak the inode. Fall back to aborting only if
  that update also fails.

This turns a filesystem-killing abort into a graceful -ENOMEM return for
create(), mkdir(), mknod(), symlink(), and link() under memory pressure.

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: pre-allocate delayed dir index before btree modification
Jeff Layton [Tue, 25 Aug 2026 16:04:18 +0000 (12:04 -0400)]
btrfs: pre-allocate delayed dir index before btree modification

Move the delayed dir index allocation in btrfs_insert_dir_item() before
the insert_with_overflow() call that modifies the btree. Previously, the
allocations happened after the DIR_ITEM was already inserted, meaning an
ENOMEM failure left the btree in a partially-modified state that could
only be resolved by aborting the transaction.

Add an optional caller-provided btrfs_dir_index_prealloc parameter to
btrfs_insert_dir_item(). When non-NULL, ownership of the prealloc
transfers to btrfs_insert_dir_item(). When NULL, it allocates internally.
All existing callers pass NULL to preserve the current behavior.

Since ownership transfers, btrfs_insert_dir_item() must free the prealloc
on every path that does not commit it. Route all such exits (including
the early path allocation failure) through a common out_free_prealloc
label, rather than keying cleanup on need_delayed_index.

Remove the btrfs_insert_delayed_dir_index() wrapper, as there are no
more callers.

Assisted-by: LLM
Suggested-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: split btrfs_insert_delayed_dir_index() into prealloc and commit phases
Jeff Layton [Tue, 25 Aug 2026 16:04:17 +0000 (12:04 -0400)]
btrfs: split btrfs_insert_delayed_dir_index() into prealloc and commit phases

Split btrfs_insert_delayed_dir_index() into three functions using a new
btrfs_dir_index_prealloc struct to bundle the pre-allocated resources:

- btrfs_prealloc_delayed_dir_index(): allocates the struct and performs
  the two GFP_NOFS allocations (delayed node + delayed item) that can
  fail with -ENOMEM. Returns the struct, or ERR_PTR on failure.
- btrfs_insert_delayed_dir_index_prealloc(): populates the item data,
  inserts into the rb-tree, and reserves metadata space. Cannot fail
  with -ENOMEM since all allocations were done in the prealloc step.
- btrfs_free_delayed_dir_index_prealloc(): frees pre-allocated
  resources when the caller's btree insertion fails. Tolerates NULL.

The prealloc is returned as a pointer rather than filled into a
caller-provided struct, so that a plain NULL means "no prealloc" and
callers do not need a separate flag to track whether one exists. It is
consumed (and freed) by either the commit or the free helper, so
ownership is unambiguous.

The original btrfs_insert_delayed_dir_index() is refactored into a thin
wrapper that calls the prealloc and commit functions.

This split allows callers to move the fallible memory allocations before
the point of no return (the DIR_ITEM btree insertion), so that -ENOMEM
can be returned cleanly without aborting the transaction.

Assisted-by: LLM
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: fix typos and repeated words in comments
Hemanth Selam [Mon, 7 Sep 2026 04:48:01 +0000 (10:18 +0530)]
btrfs: fix typos and repeated words in comments

Fix misspellings and repeated words in comments, found with
scripts/checkpatch.pl and codespell.  Only touches comments, no code
changes.

Assisted-by: Cursor:claude-opus-5
Signed-off-by: Hemanth Selam <hemanth.selam@gmail.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use bio::remaining for async checksumming synchronization
Daniel Vacek [Wed, 2 Sep 2026 13:56:27 +0000 (15:56 +0200)]
btrfs: use bio::remaining for async checksumming synchronization

We can use bio::remaining counter to sync the offloaded checksumming.
As a result we can slim down the btrfs_bio structure by 24 bytes
and simplify the code a bit.

Difference in pahole output:

- /* size: 328, cachelines: 6, members: 15 */
+ /* size: 304, cachelines: 5, members: 14 */

Moreover this will allow us enabling async checksumming with encryption
where we need to checksum the bounce bio instead of our regular one
embedded in btrfs_bio. And so we need to extend it's lifetime. This is
the preferred way to do so.

This also fixes a bug in experimental build where the async checksumming
was using the system workqueue instead of fs_info::endio_workers.

Fixes: dd57c78aec39 ("btrfs: introduce btrfs_bio::async_csum")
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: consume given iter directly instead of copying in csum_one_bio()
Daniel Vacek [Wed, 2 Sep 2026 09:20:24 +0000 (11:20 +0200)]
btrfs: consume given iter directly instead of copying in csum_one_bio()

Avoid copying the iter twice in async case.  We already have a copy
csum_one_bio() can consume directly. No need to copy it again the second
time.  We can use this copy also in the sync case and get rid of the
parameter.

Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: zoned: handle RAID profiles in btrfs_can_activate_zone()
Johannes Thumshirn [Mon, 24 Aug 2026 16:19:10 +0000 (18:19 +0200)]
btrfs: zoned: handle RAID profiles in btrfs_can_activate_zone()

btrfs_can_activate_zone() only accounts for the single and DUP profiles.
For a RAID0, RAID1, RAID1C3, RAID1C4 or RAID10 block group the profile
switch matches no case, so 'ret' stays false and the function reports
that no zone can be activated, even when the devices have plenty of
active zones left.

As a side effect BTRFS_FS_NEED_ZONE_FINISH gets set and, since
btrfs_can_activate_zone() bails out early once that bit is set, data
allocations will fail permanently: writers loop on -EAGAIN and hang in
btrfs_new_extent_direct() waiting for the bit to clear.

Each of these profiles needs one active zone per device, just like
single, so handle them the same way.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: tree-checker: reject file extent items for special files
Qu Wenruo [Tue, 1 Sep 2026 00:31:33 +0000 (10:01 +0930)]
btrfs: tree-checker: reject file extent items for special files

File extent items are only utilized by regular files or symlinks, other
files like directory/char/block/FIFO/sock files should not have any file
extent item.

Previously we were unable to reject such cases, as the inode item may not
be in the same leaf.
But we already have @prev_key in check_leaf_item(), this means we just
need a new way to pass the mode of the previously hit inode item, then
we can detect such problems.

Introduce a new helper structure, saved_inode_info, to record the inode
number and its mode hit in the same leaf, and keep it across the whole
leaf.
Then if we hit a file extent item, and the inode item is in the same
leaf, we can refer to that to determine if we need to reject the file
extent item.

Now with the following corrupted fs tree, the kernel can safely reject
the leaf:

item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
generation 3 transid 9 size 12 nbytes 16384
block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0
sequence 1 flags 0x0(none)
item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
index 0 namelen 2 name: ..
item 2 key (256 DIR_ITEM 496027801) itemoff 16075 itemsize 36
location key (257 INODE_ITEM 0) type FILE
transid 9 data_len 0 name_len 6
name: foobar
item 3 key (256 DIR_INDEX 2) itemoff 16039 itemsize 36
location key (257 INODE_ITEM 0) type FILE
transid 9 data_len 0 name_len 6
name: foobar
item 4 key (257 INODE_ITEM 0) itemoff 15879 itemsize 160
generation 9 transid 9 size 8192 nbytes 8192
block group 0 mode 60600 links 1 uid 0 gid 0 rdev 0
                   ^^ This is BLK type, not REG.
sequence 2 flags 0x0(none)
item 5 key (257 INODE_REF 256) itemoff 15863 itemsize 16
index 2 namelen 6 name: foobar
item 6 key (257 EXTENT_DATA 0) itemoff 15810 itemsize 53
generation 9 type 1 (regular)
extent data disk byte 13631488 nr 8192
extent data offset 0 nr 8192 ram 8192
extent compression 0 (none)
extent encryption 0

With the patch, kernel will reject it with the following tree-checker
errors:

  BTRFS critical (device loop0): corrupt leaf: root=5 block=30408704 slot=6 ino=257 file_offset=0, unexpected file extent item type 1 for inode mode 060600
  BTRFS error (device loop0): read time tree block corruption detected on logical 30408704 mirror 1

Reported-by: ZhengYuan Huang <gality369@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/20260817132051.267646-1-gality369@gmail.com/
Assisted-by: LLM (for generating the corrupted image)
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use ordered extent to grab the logical address for submission
Qu Wenruo [Tue, 1 Sep 2026 00:01:01 +0000 (09:31 +0930)]
btrfs: use ordered extent to grab the logical address for submission

In submit_one_sector() we call btrfs_get_extent() to grab the IO extent
map so that we know where the logical location to submit the block.

However there is no guarantee that there is an IO extent map for the
block, and if there is no IO extent map nor ordered extent,
btrfs_get_extent() can grab the file extent from on-disk metadata.

That's why we have ASSERT()s to reject holes and compressed file
extents.

On the other hand, for the write range we should have both an IO extent
map and an ordered extent, so there is no reason not to grab the ordered
extent instead.

There is some minor advantages:

- No hole ordered extent
  So no need to rely on ASSERT()s to reject hole extents.

  And the ASSERT()s are depending on the kernel config, without
  CONFIG_BTRFS_ASSERT those ASSERT()s won't even trigger.

- No IO errors
  Unlike btrfs_get_extent() which can return IO error when doing the
  metadata tree search, btrfs_lookup_ordered_extent() will either return
  an OE or not found.

- Cached OE in bio_ctrl->bbio
  At bbio allocation we have already did an OE lookup, and we have a
  high chance that the current block also belongs to that OE.
  Use that cached OE can reduce the frequency to do an rb-tree search.

- Smaller rb-tree
  Unlike extent-map-tree, which can contain cached extent maps, the life
  span of ordered extents are much shorter, they get removed from the
  ordered tree after the file extent item is inserted into the subvolume
  tree.

  So doing ordered extent tree search can be a tiny faster.

And since we're here, also address some minor points:

- Add error message for every EUCLEAN error

- Remove a dead comment on btrfs_folio_clear_dirty()
  We no longer call folio_clear_dirty_for_io() since commit 095be159f3eb
  ("btrfs: unify folio dirty flag clearing"), so the folio flag is
  still dirty, and the folio dirty flag will be cleared by the last dirty
  block.

Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Daniel Vacek <neelx@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: remove runtime tweakable feature sysfs interface
Qu Wenruo [Fri, 21 Aug 2026 10:12:10 +0000 (19:42 +0930)]
btrfs: remove runtime tweakable feature sysfs interface

There are 2 features that are marked runtime tweakable inside
/sys/fs/btrfs/features/

- acl
  Which is a mount option, and it will not show up in
  /sys/fs/btrfs/<fsid>/features/ directory anyway.

- extended_iref
  This feature can only be enabled, but not disabled at runtime.
  Furthermore it's already the default behavior since 3.12.

  So it means this feature is always enabled and cannot be disabled for
  modern btrfs.

So there is no need to maintain the ability to modify btrfs' runtime
features through sysfs.

And furthermore, the existing btrfs_feature_attr_store() is race-prone,
it relies on fs_info->transaction_kthread, but our sysfs interfaces are
enabled before transaction_kthread.

Meaning at mount time a sysfs write can trigger NULL pointer dereference
if the transaction_kthread is not yet initialized.
The opposite is also possible during unmount.

Thankfully that race is not possible in the real world, as the only
supported feature is already enabled.

But it also means we do not really need to keep the race-prone
infrastructure, so just remove it completely, and make the per-module
and per-mount features files to be completely read-only.

Even with the sysfs tweakable features removed, we can still enable
extended_iref feature through ioctl.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: avoid long stall when dropping a non-shared large subvolume
Qu Wenruo [Thu, 27 Aug 2026 06:55:30 +0000 (16:25 +0930)]
btrfs: avoid long stall when dropping a non-shared large subvolume

Commit 011b46c30476 ("btrfs: skip subtree scan if it's too high to avoid
low stall in btrfs_commit_transaction()") introduced a mechanism to skip
large subtree during snapshot dropping.

But even for a subvolume without any shared tree blocks, we can still
queue quite a lot of qgroup records into one transaction, and cause a
long qgroup related stall.

So also add a check against the subvolume root level, to determine if we
need to mark qgroup inconsistent.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: reject new qgroup rescan during subvolume dropping
Qu Wenruo [Thu, 27 Aug 2026 06:55:29 +0000 (16:25 +0930)]
btrfs: reject new qgroup rescan during subvolume dropping

Commit 011b46c30476 ("btrfs: skip subtree scan if it's too high to avoid
low stall in btrfs_commit_transaction()") introduced a threshold to skip
huge subtree scan during subvolume dropping.

But that's not covering all cases, e.g. rescan can still be started
immediately after that huge subtree skipping.
This will cause rescan to do the same accounting for that subtree
anyway, still causing a long stall during transaction commit.

Introduce a new runtime qgroup flag,
BTRFS_QGROUP_RUNTIME_BIT_REJECT_RESCAN, so that during cleanup of a
subvolume, no new qgroup rescan can be initiated.

The rejection uses the same -EINPROGRESS, as if there is already a
running qgroup rescan.

And since we have the extra bit, we can no longer allow plain assignment
in btrfs_quota_enable(), as the plain assignment will override the
REJECT_RESCAN bit.
To co-operate this new flag:

- Make btrfs_quota_enable() to only set BTRFS_QGROUP_STATUS_BIT_ON
  So it won't override the existing
  BTRFS_QGROUP_RUNTIME_BIT_REJECT_RESCAN bit.

- Make btrfs_quota_disable() to clear every non-rescan bit
  This includes:
  * BTRFS_QGROUP_STATUS_BIT_ON
  * BTRFS_QGROUP_STATUS_BIT_INCONSISTENT
  * BTRFS_QGROUP_RUNTIME_BIT_NO_ACCOUNTING

  For rescan related bits, they are either cleared by the rescan thread,
  or by the caller who rejects rescan.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: qgroup: use atomic operations for btrfs_fs_info::qgroup_flags
Qu Wenruo [Tue, 25 Aug 2026 04:12:31 +0000 (13:42 +0930)]
btrfs: qgroup: use atomic operations for btrfs_fs_info::qgroup_flags

Currently we define btrfs_fs_info::qgroup_flags as u64, to match the
on-disk qgroup status item's flag.

But for now we have only 4 bits utilized for that flag, and since it's
u64 we have no way to properly use the existing atomic bit operations
(requires an unsigned long pointer).

This results in a lot of non-atomic operations inside qgroup code. Some
maybe fine as other locks are involved, but still it's not a good
practice.

Remove those non-atomic operations by:

- Re-define btrfs_fs_info::qgroup_flags as unsigned long
- Define BTRFS_QGROUP_STATUS_BIT_* and BTRFS_QGROUP_RUNTIME_BIT_*
  Instead of the old value define the bit number.

- Use set_bit()/clear_bit()/test_bit() to replace open-coded bit
  operations

- Add one extra check at qgroup status item read time
  To make sure the on-disk flag is still inside ULONG_MAX.
  Otherwise reject the status item and disable qgroup.

- Get rid of unnecessary spinlock when checking a single bit

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: remove unused variable flags from btrfs_read_qgroup_config()
Qu Wenruo [Tue, 25 Aug 2026 04:12:30 +0000 (13:42 +0930)]
btrfs: remove unused variable flags from btrfs_read_qgroup_config()

Since commit e562a8bdf652 ("btrfs: introduce
BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN"), that @flags variable is no
longer utilized.  Just remove it.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: skip extent tree lock in the shrinker for inodes without extent maps
Breno Leitao [Mon, 24 Aug 2026 11:54:45 +0000 (04:54 -0700)]
btrfs: skip extent tree lock in the shrinker for inodes without extent maps

find_first_inode_to_shrink() takes inode->extent_tree.lock in write mode
on every inode it walks, only to find out whether that inode has any
extent maps. Most inodes have none, so the lock is taken and dropped
again without any work being done.

Check whether the tree is empty before taking the lock. tree->root is
only modified with the tree lock held for write, so the unlocked read is
a harmless race: a false empty just defers the inode to a later scan,
which already happens whenever the write_trylock() below fails, and a
false non-empty falls through to the existing check under the lock.

Across the Meta production fleet the extent map shrinker is ~0.35% of
non-idle kernel CPU. Attributing callees to their caller,
find_first_inode_to_shrink() is ~65% of that, and the write_trylock() it
does is ~30% of the whole shrinker.

Micro benchmark: a 6 GiB btrfs on a loop device, 100000 empty files kept
open, plus 200 1 MiB files created last so they get the highest inode
numbers and every scan has to walk all the empty ones first. Each round
drops the page cache, re-reads the data files to recreate the extent
maps, then triggers the shrinker with "echo 2 > /proc/sys/vm/drop_caches".
15 rounds per run on ARM64 (Neoverse V2), 8 CPUs, no lock debugging.

Cost of find_first_inode_to_shrink() from the ftrace function profiler,
in ns per inode walked, median of runs:

                          base   patched    delta
    idle                  46.4      40.1   -13.6%
    4 concurrent readers  47.8      38.4   -19.7%

A separate build with CONFIG_LOCK_STAT, same test, for the extent map
tree rwlock. The shrinker is not the only user of that lock, every
extent map insert and lookup takes it too, which is why the acquisition
count drops by two thirds rather than to nothing:

                              base   patched    delta
    write acquisitions      628016    228000   -63.7%
    hold time total (us)     47512     22717   -52.2%
    acq cacheline bounces     1574      1288   -18.2%

Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: remove on-stack paddrs[] array usage
Qu Wenruo [Wed, 19 Aug 2026 01:06:19 +0000 (10:36 +0930)]
btrfs: remove on-stack paddrs[] array usage

Since the bs > ps support, we have to handle cases where a data block is
inside several discontiguous pages.

Thus we need a local paddrs[] array to assemble a data block for bs > ps
cases.

However to handle all possible bs/ps combinations, we have to declare
such array using the max block size vs page size, no matter the current
block size and page size.

This adds 128 bytes on-stack memory usage for several call sites, and
also introduced several duplicated helpers to calculate checksum for a
data block:

- btrfs_calculate_block_csum_folio()
- btrfs_calculate_block_csum_pages()
- btrfs_check_block_csum()

The differences are mostly in how the data is passed.
The first one accepts a contiguous paddr range.
The second one accepts an array of paddrs[].
The last one is just a simple wrapper of the first one.

However the most common interface to iterate a data block is through
bio, and we have already converted most callers to use the bio based
interface, e.g. btrfs_bio_data_csum_ok() and btrfs_csum_one_bio_block().

Convert the remaining two call sites to address the remaining paddrs[]
usage:

- btrfs_calculate_block_csum_pages() inside verify_bio_data_sectors()
  This can be switched to btrfs_csum_one_bio_block().

  This removes the 128 bytes on-stack memory usage.

- btrfs_calculate_block_csum_pages() inside verify_one_sector()
  This call site doesn't use on-stack memory for paddrs[], but reuses
  the existing btrfs_raid_bio::bio_paddrs[] or
  btrfs_raid_bio::stripe_paddrs[].

  So implement a local version called calculate_block_csum_paddrs().

Now there is no fixed on-stack paddrs[] usage anymore.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: use a shared helper to calculate data checksum for a bio
Qu Wenruo [Wed, 19 Aug 2026 01:06:18 +0000 (10:36 +0930)]
btrfs: use a shared helper to calculate data checksum for a bio

Since we are already calculating data checksum using bio interface,
extract the generation part into btrfs_csum_one_bio_block(), and use that
to replace the paddrs[] array based solution in csum_one_bio().

This will reduce 128 bytes on-stack memory usage for csum_one_bio().

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: enhance btrfs_data_csum_ok() to use bio for page iteration
Qu Wenruo [Wed, 19 Aug 2026 01:06:17 +0000 (10:36 +0930)]
btrfs: enhance btrfs_data_csum_ok() to use bio for page iteration

Currently btrfs_data_csum_ok() requires a @paddr[] array to iterate all
possible pages for bs > ps cases.

However for all btrfs_data_csum_ok() call sites, we already have a
btrfs_bio, and the bio infrastructure has many flexible ways to iterate
multiple pages already.

Change btrfs_data_csum_ok() to make full use of btrfs_bio by:

- Change the parameter list to require a @bvec_iter pointer
  And remove @bio_offset, which can be calculated through @bvec_iter and
  bbio->saved_iter.

  Also remove paddrs[], we will iterate all the pages using bio
  interfaces.

- Make the same parameter changes to repair_one_sector()

- Use bio interfaces to iterate pages from a bio

- Rename the function to btrfs_bio_data_csum_ok()

- Remove on-stack paddrs[] array usage

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: replace btrfs_repair_io_failure() to use bio for page iteration
Qu Wenruo [Wed, 19 Aug 2026 01:06:16 +0000 (10:36 +0930)]
btrfs: replace btrfs_repair_io_failure() to use bio for page iteration

Currently btrfs_repair_io_failure() uses a @paddrs[] array to iterate
pages.

Such a parameter is required for bs > ps cases, as one fs block crosses
several pages.

However there is a much simpler and existing way to iterate pages: bio
and bvec_iter.

This changes btrfs_repair_io_failure() by:

- Use a const @bvec_iter pointer to locate where the pages are
- Extract file offset/logical from the @bbio
- Require no @step parameter
  Above features allow us to shorten the parameter list.

- Rename the function to btrfs_repair_bbio_failure()

- Change the caller in btrfs_repair_eb_io_failure() to allocate a bbio
  Unlike the data read path, we do not have a handy bbio in that case.
  So we need to allocate one just for btrfs_repair_bbio_failure().

- Change the error reporting in btrfs_repair_bbio_failure() to include
  root id and use inode number directly
  Now for btree inode we will report a proper inode number (1).

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: refactor read_key_bytes() to remove the dest_folio parameter
Qu Wenruo [Mon, 17 Aug 2026 07:30:43 +0000 (17:00 +0930)]
btrfs: refactor read_key_bytes() to remove the dest_folio parameter

The function read_key_bytes() have 3 call sites:

- For BTRFS_VERITY_DESC_ITEM_KEY offset 0 inside btrfs_get_verity_descriptor()
- For BTRFS_VERITY_DESC_ITEM_KEY offset 1 inside btrfs_get_verity_descriptor()
  Those are to read the description items, which are pretty small with
  fixed item size.

  Those call sites do not utilize the @dest_folio parameter.

- For btrfs_read_merkle_tree_page()
  This is to read the BTRFS_VERITY_MERKLE_ITEM_KEY, which can be pretty
  large and split into multiple items.

  This is the only call site utilizing the @dest_folio parameter.

Just for the only btrfs_read_merkle_tree_page() call site, we have a
complex scheme for @dest and @dest_folio parameters.
Since @dest can be NULL, it means if we pass @dest as NULL, then no
matter if @dest_folio is provided, the merkle data will not be loaded
into that @dest_folio.

This can lead to a bug where a highmem folio is not mapped, then we pass
folio_address(folio), which is NULL, into read_key_bytes(), causing no
data to be written into @dest_folio.

To address the complex scheme between @dest and @dest_folio, remove the
@dest_folio parameter completely, and let the only caller to map the
folio and pass the mapped kernel address into read_key_bytes() instead.

This not only reduces the parameter list, but also make it much clear on
the @dest parameter handling.
The only downside is a longer duration of locally mapped page, but this
should still be fine, as kmap_local_folio() can survive context switch.

Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
Link: https://lore.kernel.org/linux-btrfs/20260817022012.19658-1-zenghongling@kylinos.cn/
Fixes: 146054090b08 ("btrfs: initial fsverity support")
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: roll back sprout setup after device add failure
Guanghui Yang [Mon, 10 Aug 2026 23:32:27 +0000 (09:02 +0930)]
btrfs: roll back sprout setup after device add failure

btrfs_init_new_device() calls btrfs_setup_sprout() before creating the
first writable chunks for a seed filesystem. That moves the seed devices
out of fs_info->fs_devices, clears the seeding state and installs a new
fsid for the sprout filesystem.

If a later step fails, the error path removes the new device but leaves
fs_info->fs_devices in the partially initialized sprout state.  The
mounted filesystem can then be left with no open devices after the
failed device add.

Add the inverse of btrfs_setup_sprout() and use it from the error path
so the mounted seed filesystem is restored before the temporary
seed_devices copy is released.

Fixes: 2b82032c34ec ("Btrfs: Seed device support")
Assisted-by: Codex:gpt-5
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Guanghui Yang <3497809730@qq.com>
[ Fix a conflict with per-profile available space, revert sprout before
  updating per-profile available space estimation. ]
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
5 days agobtrfs: free unlinked replace target on initialization failure
Guanghui Yang [Sat, 8 Aug 2026 06:13:55 +0000 (14:13 +0800)]
btrfs: free unlinked replace target on initialization failure

btrfs_init_dev_replace_tgtdev() allocates the replacement target before
looking up its dev_t and initializing its zoned device information. If
either lookup_bdev() or btrfs_get_dev_zone_info() fails, the device has
not been linked into fs_devices->devices yet, but the error path only
drops the block device file reference.

Free the allocated device on this error path to release its name,
allocation state, zone info, and the device itself.

The issue was found by a failure-path metadata residual analyzer and
verified with targeted failure injection on v6.14.

Assisted-by: Codex:gpt-5
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
6 days agoLinux 7.3-rc3
Linus Torvalds [Sun, 13 Sep 2026 21:38:02 +0000 (14:38 -0700)]
Linux 7.3-rc3

6 days agoMerge tag 'trace-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
Linus Torvalds [Sun, 13 Sep 2026 19:27:00 +0000 (12:27 -0700)]
Merge tag 'trace-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

 - Don't destroy user event fields when removal fails

   User event fields are destroyed before the event is removed from
   visibility. But that can fail leaving the still visible event with no
   fields. Move the destroying of the fields to after the event is
   successfully removed from visibility.

 - Initialize function graph state is fork before calling
   copy_exec_state()

   For non-CLONE_VM forks, copy_exec_state() allocates a new
   task_exec_state. If that allocation fails, ftrace_graph_exit_task()
   will free the tasks ret_stack pointer. Since that pointer is still
   using the parent's ret_stack, it mistakenly frees the parent's
   pointer too.

   Call ftrace_graph_init() on the task first which will NULL out the
   new tasks's ret_stack and if the copy fails, it will not free
   anything.

 - Remove FGRAPH_MAX_INDEX

   The macro FGRAPH_MAX_INDEX was added but never used. Remove it.

 - Save ent_size in function graph printing of nested functions

   The function graph tracer needs to look at the next event to see if
   the next event is the return of the current function entry. If it is,
   it prints a single line:

ktime_get();

   Otherwise it prints it like a nested function:

tick_nohz_irq_exit() {
    ktime_get();
    kcpustat_irq_exit();
}

   In order to look at the next event, it must save the current event so
   that it has the information to print from it. It saves the event in
   the iterator descriptor called "ent". What it doesn't save is the
   ent_size of the event which is now used to know if the function graph
   arguments are to be printed. The peek doesn't save the size so the
   size used happens to be that of the size of the last event that was
   seen.

   Save the entry event size in the iterator descriptor so that the
   correct size is used.

 - Fix several errors with freeing data in the histogram code

   The histogram code had a lot of leaked or or incorrect accounting
   when failures happen. Correct them.

 - Fix histogram regression of .percent and .graph modifiers

   Up until 6.3 histogram values could have "percent" or "graph"
   modifiers that changed how they were printed. But a change that added
   restricting histograms values from being strings, stack traces and
   other modifiers inadvertently prevented them from using the percent
   and graph modifiers, which were legal use cases for values.

   Put back the percent and graph modifiers.

 - Fix various typos in the comments

 - Set the trace_clock before initializing a histogram with clock
   argument

   The histogram API allows the user to specific which trace clock to
   use via a "clock=" string. The histogram is set up first before the
   clock is checked. If the passed in clock is not valid, it exits
   without fully fixing up the histogram leaving it on the list and a
   use-after-free can trigger.

   Update the clock argument first and if it fails then exit gracefully
   before the histogram trigger is placed on any lists.

 - Restore :mod: trailer after parsing in ftrace_set_clr_event

   The function ftrace_set_clr_event() modifies the parse string and
   needs to put it back to what was passed in. It searches for ":mod:"
   via a strsep() but fails to put back the first ':' in the string.

   Add back the ':' in the passed in string.

 - Take trace_array reference when opening a tracer options file

   The options files are dynamically created and some tracers add their
   own options. When a tracer adds their own list of options, the
   trace_array holding them has an array to hold the list of options for
   each tracer. This array increases in size via a krealloc(), and the
   new entry gets a newly allocated array to hold the options of the new
   tracer being added.

   The element in each entry of the tracer's option array holds a
   pointer back to the trace_array, a pointer to the tracer it is
   associated to, a pointer to the flags of the option.

   The issue is that these arrays are freed when the trace_array is
   freed when its instance it represents is removed from the instances
   directory. There's a race that an open of one of these options files
   can happen when the instance is being removed.

   Add a new helper function to be called by the open function of the
   options file to iterate all existing trace_arrays under a lock and
   find the one that has the given option element in one of it's tracer
   arrays. If found, then update the associated trace_array's reference
   counter to keep it from being freed. If not found, have the open call
   return -ENODEV.

 - Disable interrupts when acquiring the lock in rb_wake_up_waiters()

   The function rb_wake_up_waiters() assumes it will be called in
   interrupt context and does not disable irqs when taking
   cpu_buffer->reader_lock, which can be called in hard interrupt
   context. The issue is in PREEMPT_RT, this function is called in
   thread context leaving this lock open to a deadlock.

   Take the lock with interrupts disabled.

 - Use rcu_assign_pointer() for tmp_ops filter hash

   The tmp_ops used in update_ftrace_direct_mod() assigns its
   filter_hash field directly, but that field is annotated as __rcu and
   sparse complains. Assign it with rcu_assign_pointer()

 - Fix use-after-free in enable_trigger_private_data_free()

   The trace_event_call is accessed through the event_trigger_data's
   trace_event_file pointer to put the trace_event_call on freeing. The
   issue is that the trace_event_file data may have been freed already
   causing a use-after-free. Add a field to the event_trigger_data that
   points directly to the trace_event_call so that it can decrement its
   reference directly without needing to go through the
   trace_event_file.

 - Fix accounting of buffer data remote headers

   trace_buffer_desc_size() and trace_remote_alloc_buffer() undercount
   the number of pages is needed for the asked for size as it doesn't
   take into account the meta data on each page. Add a helper function
   to do the calculation properly and use that in these functions.

 - Catch nr_page_va overflow in ring_buffer_desc sizing

   The number of pages per remote ring buffer is capped by
   ring_buffer_desc::nr_page_va (32 bits). A buffer_size large enough to
   overflow that field would silently allocate a descriptor smaller than
   what was asked for.

 - Do not resize the subbuf order if any per_cpu buffer is disabled

   The mmapping of ring buffers disables resizing the subbuffers, but it
   is done per-cpu whereas the subbuf size change is done for all the
   per_cpu buffers under the buffer->mutex. It could change the size of
   some while the mapping is happening on others. Have the resize of the
   subbuf order check all the per_cpu buffers under the lock to see if
   any of them is disabled before starting and causing an inconsistency
   between buffers that are being mapped.

* tag 'trace-v7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (25 commits)
  ring-buffer: Check resize_disabled before publishing the new subbuf order
  tracing/remotes: Catch nr_page_va overflow in ring_buffer_desc sizing
  tracing/remotes: Account for ring buffer page header in size calculation
  tracing: Don't dereference trace_event_file in deferred trigger free
  ftrace: Use rcu_assign_pointer() for tmp_ops filter hash
  ring-buffer: Acquire the lock with irqsave in rb_wake_up_waiters()
  tracing: Take trace_array reference when opening a tracer options file
  tracing: Fix ring_buffer_read_page_size() kernel-doc
  tracing: Restore :mod: trailer after parsing in ftrace_set_clr_event()
  tracing: Fix memory corruption from a "STACKTRACE" histogram key
  tracing: Fix memory corruption from the histogram stacktrace modifier
  tracing: Undo the registration when enabling the histogram trigger fails
  tracing: Take the reference before publishing the named histogram trigger
  tracing: Set the trace clock before registering the histogram trigger
  tracing: Fix typo "preceeded" in comment
  tracing: Fix typo "availabe" in comment
  tracing: Let histogram values keep the percent and graph modifiers
  tracing: Keep the entry count when the histogram stats allocation fails
  tracing: Free histogram the field rejected for a bad modifier
  tracing: Free histogram the var ref when its initialization fails
  ...

6 days agoMerge misc regression fixes that seem to have fallen through the cracks
Linus Torvalds [Sun, 13 Sep 2026 17:18:23 +0000 (10:18 -0700)]
Merge misc regression fixes that seem to have fallen through the cracks

Thorsten continues to track regressions, and reporting on known issues
with fixes that don't seem to make any progress.

I'm going to do an rc3 release later today - let's not keep these known
issues pending for yet another rc for no obvious reason.

Reported-by: Thorsten Leemhuis <regressions@leemhuis.info>
Link: https://lore.kernel.org/all/46403cf8-9a81-4596-87eb-dde58ae4c5db@leemhuis.info/
* regressions:
  media: ipu-bridge: do not use the CVS device lookup for IVSC
  wifi: mt76: mt792x: fix NULL dereference in ACPI SAR init during probe
  wifi: mt76: mt7921: skip unknown CLC firmware records

6 days agomedia: ipu-bridge: do not use the CVS device lookup for IVSC
Sergey Zagursky [Wed, 2 Sep 2026 21:15:24 +0000 (22:15 +0100)]
media: ipu-bridge: do not use the CVS device lookup for IVSC

Since commit c6b1b34b5090 ("media: pci: intel: Add CVS support for IPU
bridge driver") the internal camera no longer works on laptops where the
sensor sits behind an IVSC, for example a Dell XPS 16 9640 (IPU6,
INTC10CF, ov02c10):

  intel-ipu6 0000:00:05.0: Found supported sensor OVTI02C1:00
  intel-ipu6 0000:00:05.0: Connected 1 cameras
  ivsc_csi intel_vsc-92335fcf-3203-4472-af93-7b4453ac29da: mei-csi probed
      without device fwnode!

No sensor subdevice is registered, the media graph has no sensor entity
and userspace finds no camera at all.

ipu_bridge_get_ivsc_csi_dev() first looks for the platform device named
"intel_vsc" and returns its mei-csi child. That device is created by
mei_vsc, which on this machine only appears once the LJCA USB bridge and
its SPI controller have probed, about a second after the IPU6 probe that
runs the bridge:

  07:59:29.297  platform INTC10CF:00 created (ACPI scan)
  07:59:41      intel-ipu6 probe -> ipu_bridge_init()
  07:59:42.391  platform intel_vsc created (mei_vsc)

The commit above added two fallbacks for CVS which match on the ACPI
companion alone. They are reached for every entry of ivsc_acpi_ids[],
IVSC IDs included. The IVSC ACPI device has two physical nodes:

  INTC10CF:00/physical_node  -> platform/INTC10CF:00  (no driver bound)
  INTC10CF:00/physical_node1 -> platform/intel_vsc    (mei_vsc)

so bus_find_device_by_acpi_dev(&platform_bus_type, adev) returns the bare
platform device. ipu_bridge_instantiate_ivsc() then attaches the IVSC
software node to that device instead of to the mei-csi client, the bridge
reports success, and the probe is never retried. mei_csi later probes
without a fwnode, the CSI-2 link is never described, and the sensor ACPI
device, which has an honoured _DEP on the IVSC device, is never
enumerated.

Before those fallbacks existed the lookup returned NULL here, the bridge
failed with -ENODEV and the probe was retried once the IVSC device had
shown up.

Skip those fallbacks for IVSC devices, keying on the IVSC IDs rather than
the CVS ones: new CVS IDs keep being added, whereas the IVSC list is
complete. CVS binds a driver to the ACPI device itself, so matching on the
companion stays unambiguous there.

Fixes: c6b1b34b5090 ("media: pci: intel: Add CVS support for IPU bridge driver")
Link: https://lore.kernel.org/linux-media/20260901194526.6369-1-gvozdoder@gmail.com/
Cc: stable@vger.kernel.org
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Sergey Zagursky <gvozdoder@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
6 days agowifi: mt76: mt792x: fix NULL dereference in ACPI SAR init during probe
Devin Wittmayer [Tue, 25 Aug 2026 18:17:12 +0000 (11:17 -0700)]
wifi: mt76: mt792x: fix NULL dereference in ACPI SAR init during probe

Some laptops carry a MediaTek power table in their firmware, and the
driver reads it to set a transmit limit for each frequency range.  It
only fills in the ranges themselves when it registers the device.

The startup step that does this existed already, but it never programmed
anything.  Two recent commits made it run a regulatory update instead,
which sets the limits on the way through, long before registration.

As a result, on a machine that has the table the driver reads through an
empty pointer and the interface never appears:

  BUG: kernel NULL pointer dereference, address: 0000000000000004
  RIP: 0010:mt792x_init_acpi_sar_power
  Call Trace:
   mt7921_set_tx_sar_pwr
   mt7921_mcu_regd_update
   mt7921_regd_update
   mt7921_run_firmware
   mt7921e_mcu_init
   mt7921_init_work

Skip it when the ranges are missing. They are applied again once the
device is up, which is where they came from before.

Reported-by: Klara Modin <klarasmodin@gmail.com>
Closes: https://lore.kernel.org/linux-wireless/aoyxqHYvSuaBeubf@soda.int.kasm.eu/
Fixes: 9b80bd9cab40 ("wifi: mt76: mt7921: add regulatory wiphy self manager support")
Fixes: e9f3f1cc133f ("wifi: mt76: mt7925: add regulatory wiphy self manager support")
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Tested-by: David Gow <david@davidgow.net>
Tested-by: Klara Modin <klarasmodin@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
6 days agowifi: mt76: mt7921: skip unknown CLC firmware records
Laxman Acharya Padhya [Sun, 16 Aug 2026 17:48:40 +0000 (23:33 +0545)]
wifi: mt76: mt7921: skip unknown CLC firmware records

Treat an out-of-range CLC index as newer firmware rather than a
malformed image. linux-firmware 20260810 ships MT7922 records with
idx 3, and rejecting them made mt7921e fail to probe.

Keep the record-length checks, and report those as errors so a
truncated table is visible instead of a silent retry loop.

Fixes: 9417c5818a01 ("wifi: mt76: mt7921: validate CLC firmware records")
Reported-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Reviewed-by: Junjie Cao <junjie.cao@intel.com>
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
6 days agoring-buffer: Check resize_disabled before publishing the new subbuf order
David Carlier [Sat, 12 Sep 2026 10:39:38 +0000 (11:39 +0100)]
ring-buffer: Check resize_disabled before publishing the new subbuf order

ring_buffer_subbuf_order_set() stores the new order and only then walks
the CPUs, returning -EBUSY if any of them has resizing disabled. A user
mapped buffer has resizing disabled, and __rb_map_vma() reads
buffer->subbuf_order without buffer->mutex, so an mmap of an already
mapped CPU racing the failing order change sizes the mapping with the
new order and inserts pages past the sub-buffer into the VMA.

Check the CPUs before storing the new order.

Cc: stable@vger.kernel.org
Fixes: 117c39200d9d ("ring-buffer: Introducing ring-buffer mapping functions")
Link: https://patch.msgid.link/20260912103938.1127021-1-devnexen@gmail.com
Signed-off-by: David Carlier <devnexen@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
6 days agotracing/remotes: Catch nr_page_va overflow in ring_buffer_desc sizing
Vincent Donnefort [Fri, 11 Sep 2026 19:39:36 +0000 (20:39 +0100)]
tracing/remotes: Catch nr_page_va overflow in ring_buffer_desc sizing

The number of pages per remote ring buffer is capped by
ring_buffer_desc::nr_page_va (32 bits). A buffer_size large enough to
overflow that field would silently allocate a descriptor smaller than
what was asked for.

Return SIZE_MAX from trace_buffer_desc_size() on nr_page_va overflow.

Link: https://patch.msgid.link/20260911193937.602202-3-vdonnefort@google.com
Fixes: 2e67fabd8b77 ("ring-buffer: Introduce ring-buffer remotes")
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>