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).
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.
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.
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.
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):
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.
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.
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.
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.
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.
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.)
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.
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.
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.
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.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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.
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>
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>
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>
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>
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>
- 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>
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:
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
[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>
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
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>
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>
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>
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>
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>
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.
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>
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>
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>
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:
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>
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>
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>
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>
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>
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:
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>
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:
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>
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>
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>
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>
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.
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>
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>
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:
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
...
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
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>
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:
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.
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>
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.