* [PATCH AUTOSEL 7.0-6.18] btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer
[not found] <20260505095149.512052-1-sashal@kernel.org>
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: replace ASSERT with proper error handling in stripe lookup fallback Sasha Levin
` (7 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, Johannes Thumshirn, David Sterba, Sasha Levin, clm,
linux-btrfs, linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit fe0cdfd7118d8b40a21bfac221bb4982c5e10e10 ]
In the 'punch a hole' case of btrfs_delete_raid_extent(),
btrfs_duplicate_item() can return -EAGAIN when the leaf needs to be
split and the path becomes invalid. The old code treats any error as
fatal and breaks out of the loop.
Additionally, btrfs_duplicate_item() may trigger setup_leaf_for_split()
which can reallocate the leaf node. The code continues using the old
leaf pointer, leading to use-after-free or stale data access.
Fix both issues by:
- Handling -EAGAIN specifically: release the path and retry the loop.
- Refreshing leaf = path->nodes[0] after successful duplication.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: Subsystem `btrfs`; action verb `handle` / `refresh`;
claimed intent is to handle `-EAGAIN` from `btrfs_duplicate_item()` and
refresh a stale `leaf` pointer in `btrfs_delete_raid_extent()`.
Step 1.2 Record: Tags present:
- `Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>`
- `Signed-off-by: robbieko <robbieko@synology.com>`
- `Reviewed-by: David Sterba <dsterba@suse.com>`
- `Signed-off-by: David Sterba <dsterba@suse.com>`
No `Fixes:`, `Reported-by:`, `Tested-by:`, `Link:`, or `Cc:
stable@vger.kernel.org` tag was present.
Step 1.3 Record: The commit describes two bugs in the “punch a hole”
case of `btrfs_delete_raid_extent()`: `btrfs_duplicate_item()` can
return `-EAGAIN`, which old code treats as fatal, and
`btrfs_duplicate_item()` can change the leaf through
`setup_leaf_for_split()`, leaving the caller’s cached `leaf` pointer
stale. Symptom/failure mode: failed deletion path via false fatal error,
plus possible use-after-free or stale metadata access. No affected
kernel version is stated in the commit body.
Step 1.4 Record: This is not hidden; it is explicitly a bug fix. It
fixes memory safety/stale pointer handling and retry handling for a
known nonfatal `-EAGAIN` path.
## Phase 2: Diff Analysis
Step 2.1 Record: One file changed: `fs/btrfs/raid-stripe-tree.c`, 10
insertions, no removals. One function modified:
`btrfs_delete_raid_extent()`. Scope classification: single-file surgical
filesystem metadata fix.
Step 2.2 Record:
- Before: after `btrfs_duplicate_item()`, any nonzero return, including
`-EAGAIN`, broke out of the loop and returned an error.
- After: `-EAGAIN` releases the path and retries the outer search loop.
- Before: `leaf` was captured before `btrfs_duplicate_item()` and reused
afterward.
- After: `leaf = path->nodes[0]` is refreshed before item access and
stripe physical address updates.
Step 2.3 Record: Bug categories are memory safety and logic/correctness.
Verified mechanism: `btrfs_duplicate_item()` calls
`setup_leaf_for_split()`, which can release and re-search the path and
return `-EAGAIN`; after success, `btrfs_duplicate_item()` itself
refreshes its local `leaf`, showing the caller must not assume its
previous `leaf` remains valid.
Step 2.4 Record: The fix is obviously correct by local pattern: existing
`btrfs_duplicate_item()` callers in `fs/btrfs/file.c` already handle
`-EAGAIN` by releasing/retrying and refresh `leaf` after success.
Regression risk is low: no API change, no locking change, no new
feature, and the behavior change is limited to one special-case branch.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` shows the buggy punch-hole code in
`btrfs_delete_raid_extent()` was introduced by `6aa0e7cc569eb` (`btrfs:
implement hole punching for RAID stripe extents`), first contained by
`v6.14-rc1~207^2~7`.
Step 3.2 Record: No `Fixes:` tag exists, so there was no tagged commit
to follow. I independently identified `6aa0e7cc569eb` as the introducer
by blaming the changed lines.
Step 3.3 Record: Recent `fs/btrfs/raid-stripe-tree.c` history shows this
commit is part of a six-patch bug-fix series for RAID stripe tree
deletion. The immediately following commit, `a8d58a7c02009`, fixes
unchecked return values in the same function, but this candidate’s stale
pointer and `-EAGAIN` fix is standalone and applied cleanly to the
current `7.0.y` checkout.
Step 3.4 Record: On `master`, the author has several nearby Btrfs fixes,
including this six-patch RAID stripe tree deletion series and older
Btrfs fixes. The commit was committed and reviewed by David Sterba, the
Btrfs maintainer.
Step 3.5 Record: Dependencies found: the buggy branch requires
`6aa0e7cc569eb`; stable branches without that commit do not need this
fix. No prerequisite commit is needed for the patch hunk itself on
`7.0.y`; `git apply --check` succeeded there.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c fe0cdfd7118d8...` found the original
submission at `https://patch.msgid.link/20260413065249.2320122-6-
robbieko@synology.com`. `b4 dig -a` found only v1 of the series. The
patch was `[PATCH 5/6]`.
Step 4.2 Record: `b4 dig -w -C` showed original recipients were
`robbieko <robbieko@synology.com>` and `linux-btrfs@vger.kernel.org`.
The mbox shows Johannes Thumshirn replied “Looks good” with `Reviewed-
by`, and David Sterba later said the series was “Added to for-next,
thanks.”
Step 4.3 Record: No `Reported-by` or bug-report `Link:` tag exists.
WebFetch to lore was blocked by Anubis, but `b4` successfully downloaded
the mbox.
Step 4.4 Record: The series contains six RAID stripe tree deletion
fixes. This patch is patch 5/6; the following patch is related but not a
prerequisite for this specific retry/stale-pointer fix.
Step 4.5 Record: Web/lore stable searches did not find a stable-specific
request or objection. This is unresolved only for stable-list
discussion; it does not affect the technical decision.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: Modified function: `btrfs_delete_raid_extent()`.
Step 5.2 Record: Callers/impact surface verified:
- `do_free_extent_accounting()` calls `btrfs_delete_raid_extent()` for
data extents.
- `__btrfs_free_extent()` calls `do_free_extent_accounting()` when
references drop to zero.
- `btrfs_free_extent()` queues data refs from several Btrfs paths,
including `btrfs_drop_extents()` and `btrfs_mark_extent_written()`.
- `btrfs_punch_hole()` calls `btrfs_replace_file_extents()`, which calls
`btrfs_drop_extents()`.
Step 5.3 Record: Key callees are `btrfs_search_slot()`,
`btrfs_duplicate_item()`, `btrfs_release_path()`, `btrfs_item_size()`,
`btrfs_item_ptr()`, and `btrfs_partially_delete_raid_extent()`.
`btrfs_duplicate_item()` calls `setup_leaf_for_split()`.
Step 5.4 Record: The path is reachable from normal Btrfs file extent
freeing, including file hole punching through `btrfs_punch_hole()`, but
only when the filesystem has the RAID stripe tree incompat feature and a
supported data profile.
Step 5.5 Record: Similar pattern found in `fs/btrfs/file.c`: callers of
`btrfs_duplicate_item()` handle `-EAGAIN` by releasing/retrying and
refresh `leaf` afterward. This strongly validates the fix pattern.
## Phase 6: Stable Tree Analysis
Step 6.1 Record: The buggy introducer `6aa0e7cc569eb` is present in
`stable/linux-6.14.y` through `stable/linux-7.0.y`; it is absent from
`stable/linux-6.13.y` and older checked LTS branches.
`stable/linux-6.6.y` and `6.12.y` have `raid-stripe-tree.c` but lack
this punch-hole code.
Step 6.2 Record: Expected backport difficulty is clean or minor for
affected newer stable trees. Verified `git apply --check` succeeds on
the current `7.0.y` checkout. The exact affected hunk also exists in
`6.18.y`, `6.19.y`, and `7.0.y`; `6.18.y` differs elsewhere in the file
but not in the relevant hunk.
Step 6.3 Record: No same-title or same “stale leaf pointer” fix exists
in checked stable branches. Related six-patch series fixes are not
present in `7.0.y`.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: Subsystem is Btrfs filesystem metadata, specifically
RAID stripe tree. Criticality: important for users of Btrfs RAID stripe
tree; not universal. It is gated by `RAID_STRIPE_TREE` and supported
data profiles.
Step 7.2 Record: The file is actively developed: recent history shows
several RAID stripe tree fixes and cleanups, including this six-patch
deletion-path series.
## Phase 8: Impact And Risk Assessment
Step 8.1 Record: Affected population is Btrfs users with RAID stripe
tree enabled, especially supported data profiles such as
DUP/RAID1/RAID0/RAID10 per `btrfs_need_stripe_tree_update()`.
Step 8.2 Record: Trigger condition is deleting/freeing a data extent
range that falls strictly inside a RAID stripe extent (`found_start <
start && found_end > end`) and then hits either `-EAGAIN` from
`btrfs_duplicate_item()` or a leaf change after duplication. User
reachability is verified through Btrfs file hole-punching and extent
dropping paths, but exact ease of triggering the leaf split was not
runtime-tested.
Step 8.3 Record: Failure mode severity is HIGH: use-after-free/stale
metadata access in filesystem metadata code, plus incorrect fatal
handling of a retryable `-EAGAIN`. The commit body explicitly states
UAF/stale data access; code inspection verifies the stale pointer
mechanism.
Step 8.4 Record: Benefit is high for affected users because it prevents
memory-safety/stale metadata behavior in a filesystem metadata update
path. Risk is low because it adds only 10 lines in one branch and
follows existing Btrfs caller patterns.
## Phase 9: Final Synthesis
Step 9.1 Record:
Evidence for backporting:
- Fixes a real memory-safety/stale pointer bug and incorrect `-EAGAIN`
handling.
- Small, contained, one-function change.
- Matches established `btrfs_duplicate_item()` caller behavior in
`fs/btrfs/file.c`.
- Reviewed by Johannes Thumshirn and David Sterba; merged by David
Sterba.
- Bug exists in newer stable branches from `6.14.y` onward and is absent
from older checked branches.
Evidence against:
- Affects a narrower, experimental Btrfs RAID stripe tree feature, not
all Btrfs users.
- No `Reported-by`, reproducer, or `Tested-by` tag.
- It is part of a six-patch series, so adjacent RAID stripe tree
deletion fixes should also be reviewed.
Unresolved:
- I did not runtime-test the path.
- I could not read lore via WebFetch due Anubis, but `b4` mbox retrieval
succeeded.
- I did not prove exact clean application for every stable branch, only
current `7.0.y`; source inspection indicates minor/clean for newer
affected branches.
Step 9.2 Record:
1. Obviously correct and tested? Obviously correct by code and existing
Btrfs pattern; no explicit `Tested-by`.
2. Fixes a real bug? Yes, stale `leaf` use and retryable `-EAGAIN`
mishandling.
3. Important issue? Yes, HIGH severity memory-safety/stale metadata
access in filesystem metadata code.
4. Small and contained? Yes, 10 insertions in one function.
5. No new features/APIs? Yes.
6. Can apply to stable trees? Yes for `7.0.y` verified; applicable to
`6.14.y+` trees containing the introducer.
Step 9.3 Record: No automatic exception category applies; this is not a
device ID, quirk, DT, build, or documentation patch.
Step 9.4 Record: The risk-benefit balance favors backporting to stable
trees that contain `6aa0e7cc569eb`. It should not be backported to older
trees that lack the RAID stripe extent hole-punching code.
## Verification
- [Phase 1] Parsed `git show --format=fuller fe0cdfd7118d8`: confirmed
subject, body, tags, author, committer, and absence of
`Fixes:`/`Reported-by`/`Tested-by`.
- [Phase 2] Inspected `git diff --function-context fe0cdfd7118d8^
fe0cdfd7118d8`: confirmed 10 insertions in
`btrfs_delete_raid_extent()`.
- [Phase 2] Read `fs/btrfs/ctree.c`: confirmed `btrfs_duplicate_item()`
calls `setup_leaf_for_split()` and refreshes its local `leaf`.
- [Phase 3] Ran `git blame` on affected lines: identified
`6aa0e7cc569eb` as introducer.
- [Phase 3] Ran `git describe --contains 6aa0e7cc569eb`: first contained
by `v6.14-rc1~207^2~7`.
- [Phase 3] Checked author history on `master`: found the six related
Btrfs RAID stripe tree fixes.
- [Phase 4] Ran `b4 dig -c`, `-a`, `-w -C`, and `-m`: found patch URL,
v1-only series, recipients, mbox, maintainer/reviewer responses.
- [Phase 4] Read mbox: Johannes gave `Reviewed-by`; David said series
was added to for-next.
- [Phase 5] Used `rg` and source reads to trace `btrfs_punch_hole()` →
`btrfs_replace_file_extents()` → `btrfs_drop_extents()` →
`btrfs_free_extent()` → delayed free accounting →
`btrfs_delete_raid_extent()`.
- [Phase 5] Searched similar patterns: `fs/btrfs/file.c` handles
`-EAGAIN` and refreshes `leaf` after `btrfs_duplicate_item()`.
- [Phase 6] Checked stable branches with `git merge-base --is-ancestor`:
`6.14.y` through `7.0.y` contain introducer and lack fix; `6.13.y`
lacks introducer.
- [Phase 6] Ran `git apply --check` for the candidate patch on current
`7.0.y`: success.
- [Phase 7] Read `fs/btrfs/Kconfig` and `fs/btrfs/raid-stripe-tree.h`:
verified RAID stripe tree is feature-gated and profile-limited.
- [Phase 8] Verified failure mode from commit body plus code flow
through `setup_leaf_for_split()` and stale caller `leaf`.
**YES**
fs/btrfs/raid-stripe-tree.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 86ddc3ecb4060..22327f4833113 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -194,9 +194,19 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "right" item. */
ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey);
+ if (ret == -EAGAIN) {
+ btrfs_release_path(path);
+ continue;
+ }
if (ret)
break;
+ /*
+ * btrfs_duplicate_item() may have triggered a leaf
+ * split via setup_leaf_for_split(), so we must refresh
+ * our leaf pointer from the path.
+ */
+ leaf = path->nodes[0];
item_size = btrfs_item_size(leaf, path->slots[0]);
extent = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_stripe_extent);
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.18] btrfs: replace ASSERT with proper error handling in stripe lookup fallback
[not found] <20260505095149.512052-1-sashal@kernel.org>
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-5.10] btrfs: handle unexpected free-space-tree key types Sasha Levin
` (6 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, David Sterba, Sasha Levin, clm, linux-btrfs,
linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit 653361585d251fbca0e19ac58b04ba95dd01e378 ]
After falling back to the previous item in btrfs_delete_raid_extent(),
the code uses ASSERT(found_start <= start) to verify the found extent
actually precedes our target range. If the B-tree state is unexpected
(e.g. no overlapping extent exists), this triggers a kernel BUG/panic
in debug builds, or silently continues with wrong data otherwise.
Replace the ASSERT with a proper bounds check that returns -ENOENT if
the found extent does not actually overlap with the start position.
Signed-off-by: robbieko <robbieko@synology.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: Subsystem `btrfs`; action verb `replace`; intent is to
replace an assertion in `btrfs_delete_raid_extent()` with real error
handling for stripe lookup fallback.
Step 1.2 Record: Tags in commit
`653361585d251fbca0e19ac58b04ba95dd01e378`: `Signed-off-by: robbieko
<robbieko@synology.com>`, `Reviewed-by: David Sterba
<dsterba@suse.com>`, `Signed-off-by: David Sterba <dsterba@suse.com>`.
No `Fixes:`, no `Reported-by:`, no `Tested-by:`, no `Link:`, no `Cc:
stable`.
Step 1.3 Record: The commit says that after fallback to the previous
item, `ASSERT(found_start <= start)` can BUG/panic when B-tree state is
unexpected, and non-assert builds can continue with wrong stripe data.
Root cause described: the previous item found may not actually overlap
the requested deletion range.
Step 1.4 Record: This is not hidden cleanup. It is explicitly a bug fix:
it converts an invariant-only check into a runtime bounds check
returning `-ENOENT`.
## Phase 2: Diff Analysis
Step 2.1 Record: One file changed: `fs/btrfs/raid-stripe-tree.c`, 4
insertions, 1 deletion. One function changed:
`btrfs_delete_raid_extent()`. Scope: single-file surgical fix.
Step 2.2 Record: Before, fallback loaded the previous key, computed
`found_start` and `found_end`, then asserted only `found_start <=
start`. After, it returns `-ENOENT` and exits the delete loop if
`found_start > start` or `found_end <= start`. This affects the stripe
extent deletion lookup path after `btrfs_search_slot()` chooses an item
after the deletion start and the code backs up to a candidate previous
item.
Step 2.3 Record: Bug category is logic/correctness with data-integrity
implications. Broken mechanism: the fallback candidate was assumed to
overlap the deletion start. The fix verifies both start and end bounds
before later code can truncate, split, or delete a stripe extent.
Step 2.4 Record: Fix quality is high: the check is local, easy to reason
about, and preserves existing error propagation. Regression risk is low,
but not zero: returning `-ENOENT` changes a previous silent/no-op path
into transaction abort at the caller. That is appropriate because the
caller already aborts on `btrfs_delete_raid_extent()` errors and the
condition means the stripe mapping lookup is inconsistent for the
deletion being performed.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` shows the fallback block and
`ASSERT(found_start <= start)` were introduced by `76643119045eed`
(`btrfs: fix deletion of a range spanning parts two RAID stripe
extents`), first contained in `v6.14-rc1`. The broader partial deletion
machinery was introduced by `6aea95ee318890`, first contained in
`v6.13-rc1`.
Step 3.2 Record: No `Fixes:` tag is present, so there was no tagged
introducer to follow. Blame identifies the direct introducer.
Step 3.3 Record: Recent `master` history shows this was patch 4 in a
six-patch raid-stripe-tree deletion fix set: preceding fixes include
copying `devid`, fixing leaf-boundary lookup, and fixing
`btrfs_previous_item()` `min_objectid`; following fixes handle `-EAGAIN`
and missing return checks. The commit applies cleanly to the current
`stable/linux-7.0.y` checkout by itself, but it is best considered with
the neighboring raid-stripe-tree deletion fixes.
Step 3.4 Record: Author `robbieko` has multiple adjacent `fs/btrfs/raid-
stripe-tree.c` fixes in `master`. Reviewer/committer David Sterba is
listed as Btrfs maintainer in `MAINTAINERS`. Johannes Thumshirn, who
reviewed other patches in the series, has substantial prior raid-stripe-
tree history in the same file.
Step 3.5 Record: No new helper, structure, API, or external dependency
is introduced. Syntactically standalone: `git apply --check` of the
candidate patch succeeded on the current `stable/linux-7.0.y` checkout.
Semantically, it complements the surrounding lookup fixes.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c 653361585d251...` found the original
submission at `https://patch.msgid.link/20260413065249.2320122-5-
robbieko@synology.com`. `b4 dig -a -C` showed only v1. The thread was a
six-patch series titled `btrfs: fix multiple bugs in raid-stripe-tree
deletion path`.
Step 4.2 Record: `b4 dig -w` showed the original recipients were
`robbieko` and `linux-btrfs@vger.kernel.org`. In-thread
review/maintainer discussion involved David Sterba and Johannes
Thumshirn. David added the series to `for-next`.
Step 4.3 Record: No `Reported-by:` or `Link:` tag exists for an external
bug report. No syzbot or bugzilla report was present in the commit or
mbox.
Step 4.4 Record: Related patches found in the same series:
`513f8a52eed88`, `2aef5cb1dcf9b`, `1871ae78ffa5c`, `fe0cdfd7118d8`, and
`a8d58a7c02009`. The cover letter states all six fix bugs in raid-
stripe-tree deletion/partial deletion paths.
Step 4.5 Record: No stable-specific nomination was found in the mbox.
WebFetch attempts to lore/stable and lore/all were blocked by Anubis, so
external stable-list search could not be independently verified.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: Modified function: `btrfs_delete_raid_extent()`.
Step 5.2 Record: Callers found by search: production caller
`do_free_extent_accounting()` in `fs/btrfs/extent-tree.c`, plus Btrfs
raid-stripe-tree selftests. `do_free_extent_accounting()` calls
`btrfs_delete_raid_extent()` for data extents and aborts the transaction
on error.
Step 5.3 Record: Key callees in `btrfs_delete_raid_extent()` include
`btrfs_find_chunk_map()`, `btrfs_need_stripe_tree_update()`,
`btrfs_search_slot()`, `btrfs_previous_item()`, `btrfs_del_item()`,
`btrfs_duplicate_item()`, and `btrfs_partially_delete_raid_extent()`.
Step 5.4 Record: Reachability verified: file extent removal paths call
`btrfs_free_extent()`, delayed refs call `__btrfs_free_extent()`, and
when refs reach zero `do_free_extent_accounting()` calls
`btrfs_delete_raid_extent()`. `btrfs_fallocate()` calls
`btrfs_punch_hole()` for `FALLOC_FL_PUNCH_HOLE`, which calls
`btrfs_replace_file_extents()`, which calls `btrfs_drop_extents()`,
which calls `btrfs_free_extent()`. So users with write access to files
on an affected Btrfs filesystem can reach this path via hole punching;
other data extent deletion paths also reach it.
Step 5.5 Record: Similar nearby issue pattern found in the same series:
multiple small fixes to `btrfs_delete_raid_extent()` and
`btrfs_partially_delete_raid_extent()` addressing missed entries, wrong
previous-item bounds, stale leaf pointer, missing `devid`, and unchecked
return values.
## Phase 6: Stable Tree Analysis
Step 6.1 Record: The directly blamed fallback code is first in
`v6.14-rc1`; merge-base checks show it is not in `v6.13`, but is in
`v6.14`, `v6.15`, `v6.16`, and `v7.0`. It is therefore relevant to
stable trees based on `v6.14+`, including the current
`stable/linux-7.0.y` checkout.
Step 6.2 Record: Backport difficulty is low. `git apply --check` of the
candidate patch onto current `stable/linux-7.0.y` succeeded. Neighboring
series patches also applied cleanly in the same check.
Step 6.3 Record: Local stable refs `stable/linux-6.16.y` and
`stable/linux-7.0.y` do not contain the candidate or the adjacent April
2026 raid-stripe-tree deletion fixes checked by subject/ancestor tests.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: Subsystem is Btrfs filesystem, specifically raid-
stripe-tree. Criticality: important, because it is filesystem
data/extent mapping code, but affected population is feature-specific
rather than universal.
Step 7.2 Record: Subsystem activity is high. Recent history in
`fs/btrfs/raid-stripe-tree.c` shows many fixes and follow-up selftests.
The feature is also exposed only under `CONFIG_BTRFS_EXPERIMENTAL` sysfs
feature attributes in this tree, so impact is limited to systems using
that feature.
## Phase 8: Impact And Risk Assessment
Step 8.1 Record: Affected users are Btrfs users with `RAID_STRIPE_TREE`
enabled and stripe-tree updates needed for data block group profiles
covered by `BTRFS_RST_SUPP_BLOCK_GROUP_MASK`.
Step 8.2 Record: Trigger conditions: deleting/freeing data extents on
such filesystems when stripe lookup fallback selects a non-overlapping
candidate. Verified reachable through file hole punching and delayed-ref
extent free paths. I did not verify a concrete reproducer for the exact
bad B-tree state.
Step 8.3 Record: Failure mode severity is high. With
`CONFIG_BTRFS_ASSERT`, `ASSERT()` calls `BUG()`, so this can crash the
kernel. Without that assertion code generated, the later deletion logic
can operate on a non-overlapping stripe extent, which is a filesystem
mapping corruption risk. If the previous candidate ends before the
target, the old code could also silently stop with success.
Step 8.4 Record: Benefit is high for affected users because it prevents
panic or wrong stripe-tree mutation in filesystem deletion code. Risk is
low because the patch is a four-line validation check in one function
and changes invalid lookup state into an error returned to an existing
transaction-abort path.
## Phase 9: Final Synthesis
Step 9.1 Record: Evidence for backporting: real filesystem correctness
bug, possible kernel BUG in assert builds, possible wrong stripe mapping
mutation in non-assert builds, one-file minimal patch, maintainer review
by David Sterba, merged by Linus via Btrfs fixes pull, applies cleanly
to current stable checkout, affected code exists in `v6.14+`. Evidence
against: feature-specific and experimental; no concrete external bug
report or reproducer found; part of a six-patch series, so stable
maintainers should consider taking the nearby deletion fixes too.
Unresolved: no successful WebFetch of lore/stable search due Anubis;
exact real-world frequency not verified.
Step 9.2 Record: Stable rules checklist:
1. Obviously correct and tested: mostly yes by inspection and maintainer
review; no explicit `Tested-by`.
2. Fixes a real bug: yes, invalid stripe lookup fallback handling in
deletion path.
3. Important issue: yes for affected users, because panic and filesystem
mapping corruption are serious.
4. Small and contained: yes, 4 insertions/1 deletion in one function.
5. No new features/APIs: yes.
6. Can apply to stable: yes on current `stable/linux-7.0.y`; relevant
for `v6.14+` trees.
Step 9.3 Record: No exception category applies. This is not a device ID,
quirk, DT, build, or documentation patch.
Step 9.4 Record: Decision is to backport. The limited affected
population does not outweigh the severity and low risk: this is a tiny
filesystem correctness fix for code already present in recent stable
trees.
## Verification
- [Phase 1] `git show --format=fuller --stat 653361585d251...`:
confirmed subject, message, tags, reviewer, and 4 insertions/1
deletion.
- [Phase 2] `git show 653361585d251... -- fs/btrfs/raid-stripe-tree.c`:
confirmed exact hunk replacing `ASSERT(found_start <= start)` with
`found_start > start || found_end <= start` check returning `-ENOENT`.
- [Phase 3] `git blame -L 114,146 -- fs/btrfs/raid-stripe-tree.c`:
confirmed fallback block introduced by `76643119045eed`.
- [Phase 3] `git show 76643119045eed`: confirmed it added the range-
spanning fallback logic.
- [Phase 3] `git describe --contains 76643119045eed`: confirmed first
containment at `v6.14-rc1`.
- [Phase 3] `git show 6aea95ee318890`: confirmed earlier partial
deletion implementation and its ASSERT-related context.
- [Phase 3] `git log master --oneline -30 -- fs/btrfs/raid-stripe-
tree.c`: confirmed related series commits before and after candidate.
- [Phase 3] `git apply --check` using the candidate diff: confirmed
clean application on current `stable/linux-7.0.y`.
- [Phase 4] `b4 dig -c 653361585d251...`: found original lore patch URL.
- [Phase 4] `b4 dig -a -C`: found v1 only.
- [Phase 4] `b4 dig -w`: confirmed original recipients.
- [Phase 4] Saved and read b4 mbox: confirmed six-patch series, David
Sterba maintainer discussion, David’s “Added to for-next”, Johannes’
question about `ENOENT` vs `EUCLEAN`, and David’s acceptance of
`ENOENT`.
- [Phase 5] `rg btrfs_delete_raid_extent`: confirmed production caller
in `do_free_extent_accounting()` and selftests.
- [Phase 5] Read `fs/btrfs/extent-tree.c`: confirmed errors from
`btrfs_delete_raid_extent()` abort transaction.
- [Phase 5] Read `fs/btrfs/file.c`: confirmed `btrfs_fallocate()` hole
punching can reach extent replacement/drop code and
`btrfs_free_extent()`.
- [Phase 5] Read `fs/btrfs/messages.h`: confirmed `ASSERT()` calls
`BUG()` when `CONFIG_BTRFS_ASSERT` is enabled and compiles away
otherwise.
- [Phase 6] `git merge-base --is-ancestor` checks: confirmed blamed code
is in `v6.14+` and candidate is not in local stable refs checked.
- [Phase 7] `rg MAINTAINERS`: confirmed David Sterba is a Btrfs
maintainer.
- [Phase 7] `rg RAID_STRIPE_TREE fs/btrfs/sysfs.c`: confirmed raid-
stripe-tree feature attribute is under `CONFIG_BTRFS_EXPERIMENTAL`.
- [Phase 8] Read `fs/btrfs/raid-stripe-tree.h`: confirmed
`btrfs_need_stripe_tree_update()` limits affected data profiles and
requires `RAID_STRIPE_TREE`.
- UNVERIFIED: exact real-world frequency and a concrete reproducer for
the bad fallback state.
- UNVERIFIED: lore/stable search results, because WebFetch was blocked
by Anubis.
**YES**
fs/btrfs/raid-stripe-tree.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index dd924048c6659..a2e9ac2d97988 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -151,7 +151,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
btrfs_item_key_to_cpu(leaf, &key, slot);
found_start = key.objectid;
found_end = found_start + key.offset;
- ASSERT(found_start <= start);
+ if (found_start > start || found_end <= start) {
+ ret = -ENOENT;
+ break;
+ }
}
if (key.type != BTRFS_RAID_STRIPE_KEY)
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-5.10] btrfs: handle unexpected free-space-tree key types
[not found] <20260505095149.512052-1-sashal@kernel.org>
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: replace ASSERT with proper error handling in stripe lookup fallback Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.6] btrfs: apply first key check for readahead when possible Sasha Levin
` (5 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: David Sterba, Johannes Thumshirn, Sasha Levin, clm, linux-btrfs,
linux-kernel
From: David Sterba <dsterba@suse.com>
[ Upstream commit 4d95b9efd783adca472e957b2f576983e789b839 ]
Replace the conditional assertions with proper error handling and
transaction abort if we find an unexpected key type in the free space
tree.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: subsystem `btrfs`, action verb `handle`, intent:
replace assertions with real error handling for unexpected free-space-
tree key types.
Step 1.2 Record: tags found: `Reviewed-by: Johannes Thumshirn
<johannes.thumshirn@wdc.com>`, `Signed-off-by: David Sterba
<dsterba@suse.com>`. No `Fixes:`, `Reported-by:`, `Tested-by:`, `Link:`,
or `Cc: stable`.
Step 1.3 Record: the commit says unexpected free-space-tree key types
currently hit conditional assertions; the fix logs an error, returns
`-EUCLEAN`, and aborts the transaction. No user report, stack trace, or
affected version is stated.
Step 1.4 Record: yes, this is a hidden bug fix. `ASSERT(0)` is not
runtime handling in normal non-`CONFIG_BTRFS_ASSERT` builds, so the
unexpected-key branch previously did not return an error or advance
iteration.
## Phase 2: Diff Analysis
Step 2.1 Record: one file changed: `fs/btrfs/free-space-tree.c`, 15
insertions and 3 deletions. Modified functions:
`btrfs_convert_free_space_to_bitmaps()`,
`btrfs_convert_free_space_to_extents()`,
`btrfs_remove_block_group_free_space()`. Scope: single-file surgical
fix.
Step 2.2 Record: each hunk changes `else { ASSERT(0); }` after
recognized free-space-tree item types into `btrfs_err()`, `ret =
-EUCLEAN`, `btrfs_abort_transaction()`, and exit. Affected paths are
transaction-time conversion between free-space extents/bitmaps and
block-group free-space removal.
Step 2.3 Record: bug category is logic/corruption error handling. With
assertions disabled, the unexpected branch leaves `path->slots[0]`
unchanged and continues the inner `while (path->slots[0] > 0)`, which
can loop indefinitely. With assertions enabled, it can `BUG()`. The fix
converts both cases to a controlled filesystem-corruption error and
transaction abort.
Step 2.4 Record: fix quality is high: minimal, consistent with
surrounding transaction-abort handling, no new API, no data structure
change. Regression risk is low; the only changed behavior is for
unexpected on-disk key types.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` shows the affected `ASSERT(0)` branches
were introduced by `a5ed91828518ab` (“Btrfs: implement the free space
B-tree”), first contained in `v4.5-rc1`. Later nearby lines changed, but
the bad branches are old.
Step 3.2 Record: no `Fixes:` tag, so no tagged introducing commit to
follow. Blame identifies `a5ed91828518ab` as the source of these
branches.
Step 3.3 Record: recent file history shows related free-space-tree
churn, but this patch is standalone. The current stable `7.0` tree
accepts the patch with `git apply --check`. Older stable tags contain
the same logical branches but may need context/name adjustment.
Step 3.4 Record: author David Sterba is listed as a Btrfs maintainer in
`MAINTAINERS`; recent history shows many Btrfs commits from him.
Step 3.5 Record: no functional prerequisite was found. The patch uses
existing `btrfs_err()`, `-EUCLEAN`, and `btrfs_abort_transaction()`
paths.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c 4d95b9efd783a` found the lore submission at
`https://patch.msgid.link/23bf53315a59a3acc0abdf4f4d8f4c9336c936e1.17761
80388.git.dsterba@suse.com`. It was `v1`, patch `3/6`.
Step 4.2 Record: `b4 dig -w` shows original recipients were David Sterba
and `linux-btrfs@vger.kernel.org`. The saved mbox contains Johannes
Thumshirn’s “Looks good to me” and `Reviewed-by`.
Step 4.3 Record: no reporter or bug-report link exists in the commit or
thread.
Step 4.4 Record: series title was “Debugging macro and kmalloc_obj*
cleanups”. Cover letter explicitly says this patch “updates error
handling” for “impossible” conditions. No dependency on other patches
was found.
Step 4.5 Record: stable lore WebFetch was blocked by Anubis. Web search
found the original patch discussion, but no stable-specific request or
rejection.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: modified functions:
`btrfs_convert_free_space_to_bitmaps()`,
`btrfs_convert_free_space_to_extents()`,
`btrfs_remove_block_group_free_space()`.
Step 5.2 Record: conversion functions are called from
`update_free_space_extent_count()`, which is reached by free-space-tree
add/remove operations. `btrfs_remove_block_group_free_space()` is called
from block-group removal and relocation paths.
Step 5.3 Record: key callees include `btrfs_search_prev_slot()`,
`btrfs_item_key_to_cpu()`, `btrfs_del_items()`,
`btrfs_search_free_space_info()`, and now `btrfs_abort_transaction()`.
Step 5.4 Record: the affected paths are reachable during Btrfs
allocation/freeing, relocation, balance/remap, and block-group removal.
Trigger requires an unexpected free-space-tree key type in the relevant
block-group key range; I did not verify an unprivileged direct trigger.
Step 5.5 Record: similar `ASSERT(0)` patterns exist elsewhere in older
Btrfs free-space-tree code, but this patch specifically fixes the three
branches where the loop otherwise makes no progress.
## Phase 6: Stable Tree Analysis
Step 6.1 Record: the affected logic exists in stable-era tags checked:
`v5.15`, `v6.1`, `v6.6`, `v6.12`, `v6.19`, and `v7.0`. It originated in
`v4.5-rc1`.
Step 6.2 Record: clean apply verified on current `stable/linux-7.0.y`.
For older stable trees, function names differ before `v6.19`
(`convert_free_space_to_bitmaps()` etc.), so minor backport adjustment
is expected.
Step 6.3 Record: current branch search found no existing fix with the
same “unexpected free space tree key type” message.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: subsystem is Btrfs filesystem, criticality IMPORTANT
because it affects users of a production filesystem and can impact
transaction progress and filesystem integrity handling.
Step 7.2 Record: Btrfs is active; recent `fs/btrfs` history includes
multiple fixes and the candidate was merged via the Btrfs maintainer
tree.
## Phase 8: Impact And Risk
Step 8.1 Record: affected users are Btrfs users with the free-space-tree
feature enabled and malformed/unexpected free-space-tree entries.
Step 8.2 Record: trigger is not every boot or every operation; it
requires unexpected free-space-tree key types encountered during
conversion/removal. It can be hit by mounted filesystem state or
corruption; unprivileged trigger was not verified.
Step 8.3 Record: failure mode is severe: non-assert builds can spin in
the inner loop because the slot is not decremented; assert builds can
`BUG()`. Severity: HIGH to CRITICAL depending on build/configuration.
Step 8.4 Record: benefit is high for affected systems because it
prevents a hang/BUG and cleanly aborts a corrupt transaction. Risk is
low because the patch only affects an invalid/corrupt branch and is 15
added lines in one file.
## Phase 9: Final Synthesis
Step 9.1 Record: evidence for backporting: old bug present since
`v4.5-rc1`, affects active stable trees, fixes hang/BUG behavior, small
and contained, authored by Btrfs maintainer, reviewed. Evidence against:
no user report, no `Fixes:` or stable tag, trigger appears to require
corrupted/unexpected on-disk state, older trees need minor backport
context adjustment.
Step 9.2 Record: stable checklist: obviously correct: yes by code
inspection; tested: no explicit `Tested-by`. Real bug: yes, verified
non-progress branch. Important issue: yes, possible hang/BUG.
Small/contained: yes. No new features/APIs: yes. Applies to stable:
clean on `7.0`, minor adjustments likely for older trees.
Step 9.3 Record: no automatic exception category applies; this is not a
device ID, quirk, DT, build, or documentation change.
Step 9.4 Record: decision is YES. The key technical point is that this
is not just replacing a debug assertion: in production builds the
assertion compiles away, leaving a no-progress loop on unexpected free-
space-tree item types. The fix is small and turns a hang/BUG into normal
Btrfs corruption handling.
## Verification
- Phase 1: Parsed `git show --format=fuller` for commit
`4d95b9efd783adca472e957b2f576983e789b839`; confirmed tags and absence
of reporter/fixes/stable tags.
- Phase 2: Inspected full diff; confirmed 15 insertions, 3 deletions,
one file, three functions.
- Phase 2: Read `fs/btrfs/messages.h`; confirmed `ASSERT()` calls
`BUG()` only under `CONFIG_BTRFS_ASSERT`, otherwise compiles away via
`BUILD_BUG_ON_INVALID()`.
- Phase 3: Ran `git blame` on all three changed regions; confirmed
`ASSERT(0)` branches came from `a5ed91828518ab`.
- Phase 3: Ran `git describe --contains a5ed91828518ab`; confirmed first
contained around `v4.5-rc1`.
- Phase 3: Checked `MAINTAINERS`; confirmed David Sterba is Btrfs
maintainer.
- Phase 4: Ran `b4 dig -c`, `-a`, `-w`; confirmed v1 patch 3/6,
recipients, and lore URL.
- Phase 4: Saved and read mbox; confirmed patch text, cover-letter
context, and Johannes Thumshirn `Reviewed-by`.
- Phase 4: WebFetch to lore/stable was blocked by Anubis; WebSearch
found original patch mirror and no stable-specific discussion.
- Phase 5: Used `rg` and file reads to trace callers through
`update_free_space_extent_count()`, free-space add/remove, block-group
removal, relocation, and extent-tree allocation/freeing paths.
- Phase 6: Scripted checks against `v5.15`, `v6.1`, `v6.6`, `v6.12`,
`v6.19`, `v7.0`, and `master`; confirmed the affected assertions exist
in stable-era code and the fix message only in `master`.
- Phase 6: Ran `git apply --check` for the candidate patch on current
`stable/linux-7.0.y`; it applies cleanly.
- Phase 8: Verified `EUCLEAN` maps to filesystem corruption via
`include/uapi/asm-generic/errno.h` (`EFSCORRUPTED EUCLEAN`).
- Unverified: no runtime test, no kernel build, no proof of unprivileged
trigger, and no direct check that every older stable branch applies
without manual adjustment.
**YES**
fs/btrfs/free-space-tree.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c
index 9efd1ec90f031..472b3060e5ac3 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -259,7 +259,11 @@ int btrfs_convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
- ASSERT(0);
+ btrfs_err(fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ goto out;
}
}
@@ -405,7 +409,11 @@ int btrfs_convert_free_space_to_extents(struct btrfs_trans_handle *trans,
nr++;
} else {
- ASSERT(0);
+ btrfs_err(fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ goto out;
}
}
@@ -1518,7 +1526,11 @@ int btrfs_remove_block_group_free_space(struct btrfs_trans_handle *trans,
nr++;
path->slots[0]--;
} else {
- ASSERT(0);
+ btrfs_err(trans->fs_info, "unexpected free space tree key type %u",
+ found_key.type);
+ ret = -EUCLEAN;
+ btrfs_abort_transaction(trans, ret);
+ return ret;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.6] btrfs: apply first key check for readahead when possible
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-5.10] btrfs: handle unexpected free-space-tree key types Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix wrong min_objectid in btrfs_previous_item() call Sasha Levin
` (4 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: Qu Wenruo, David Sterba, Sasha Levin, clm, linux-btrfs,
linux-kernel
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit a86a283430e1a44907b142c4f53e1f3ad24e87ae ]
Currently for tree block readahead we never pass a
btrfs_tree_parent_check with @has_first_key set.
Without @has_first_key set, btrfs will skip the following extra
checks:
- Header generation check
This is a minor one.
- Empty leaf/node checks
This is more serious, for certain trees like the csum tree, they are
allowed to be empty, thus an empty leaf can pass the tree checker.
But if there is a parent node for such an empty leaf, it indicates
corruption.
Without @has_first_key set, we can no longer detect such a problem.
In fact there is already a fuzzed image report that a corrupted csum
leaf which has zero nritems but still has a parent node can trigger
a BUG_ON() during csum deletion.
However there are only two call sites of btrfs_readahead_tree_block():
- Inside relocate_tree_blocks()
At this call site we are trying to grab the first key of the tree
block, thus we are not able to pass a @first_key parameter.
- Inside btrfs_readahead_node_child()
This is the more common call site, where we have the parent node and
want to readahead the child tree blocks.
In this case we can easily grab the node key and pass it for checks.
Add a new parameter @first_key to btrfs_readahead_tree_block() and pass
the node key to it inside btrfs_readahead_node_child().
This should plug the gap in empty leaf detection during readahead.
Link: https://lore.kernel.org/linux-btrfs/20260409071255.3358044-1-gality369@gmail.com/
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Record 1.1: Subsystem is `btrfs`; action is `apply` / `pass existing
first key`; intent is to enable existing parent/first-key validation for
tree-block readahead where the parent node is available.
Record 1.2: Tags found:
- `Link: https://lore.kernel.org/linux-
btrfs/20260409071255.3358044-1-gality369@gmail.com/`
- `Reviewed-by: David Sterba <dsterba@suse.com>`
- `Signed-off-by: Qu Wenruo <wqu@suse.com>`
- `Signed-off-by: David Sterba <dsterba@suse.com>`
- No `Fixes:`, `Reported-by:`, `Tested-by:`, or `Cc:
stable@vger.kernel.org` tag in the final commit.
Record 1.3: The commit describes a real corruption-detection gap:
readahead builds a `btrfs_tree_parent_check` without `has_first_key`, so
checks that require the parent slot key are skipped. The stated failure
mode is a fuzzed corrupt csum-tree leaf with zero items but a parent
node later reaching csum deletion and triggering a `BUG_ON()`.
Record 1.4: This is a hidden bug fix, not a feature. It adds no new
behavior for valid filesystems; it makes an existing metadata integrity
check run during readahead when the caller already has the parent key.
## Phase 2: Diff Analysis
Record 2.1: Final committed diff changes 3 files: `fs/btrfs/extent_io.c`
+12/-2, `fs/btrfs/extent_io.h` +2/-1, `fs/btrfs/relocation.c` +1/-1;
total +15/-4. Modified functions are `btrfs_readahead_tree_block()`,
`btrfs_readahead_node_child()`, and the call in
`relocate_tree_blocks()`. Scope is small and Btrfs-local.
Record 2.2: Before, `btrfs_readahead_tree_block()` always initialized
parent-check data with level/transid only. After, it optionally copies a
caller-provided `first_key` and sets `has_first_key`.
`btrfs_readahead_node_child()` now derives the key from the parent node
slot and passes it. The relocation caller passes `NULL` because it lacks
the first key at that point.
Record 2.3: Bug category is filesystem metadata validation / corruption
handling. Mechanism: missing parent first-key information let readahead
read and mark a corrupt child block valid under weaker checks. Passing
the parent slot key enables existing first-key/empty-child validation
paths.
Record 2.4: Fix quality is good: small, direct, no locking changes, no
public API changes, no unrelated refactor. Regression risk is low; the
new validation applies only where the parent node already provides the
expected key. Legitimate empty roots are not children of a parent slot
with a first key.
## Phase 3: Git History Investigation
Record 3.1: `git blame` shows the current readahead helper was
introduced by `bfb484d922a3` (`btrfs: cleanup extent buffer readahead`,
described as `v5.11-rc1~144^2~112`), owner/level plumbing by
`3fbaf25817f7`, and the parent-check struct initialization in this
helper by `947a629988f1` (`v6.2-rc1~143^2~39`).
`btrfs_verify_level_key()` empty-child validation exists in the local
stable tags examined, including `v5.15`, `v6.1`, and newer.
Record 3.2: No `Fixes:` tag is present, so there was no direct fixes
target to follow for this commit.
Record 3.3: Recent file history shows related Btrfs metadata/readahead
validation work, including `f04c6475c2db` (`btrfs: revalidate cached
tree blocks on the uptodate path`) and `908ab5634751` (`btrfs: remove
atomic parameter from btrfs_buffer_uptodate()`). The candidate itself is
standalone on `master`, but older stable trees have API differences.
Record 3.4: Qu Wenruo has many recent `fs/btrfs` commits; David Sterba
is listed in `MAINTAINERS` as Btrfs maintainer and reviewed/committed
this patch.
Record 3.5: Dependency/backport finding: the patch applies cleanly to
the current `v7.0.3` working tree with offsets. `v6.6`, `v6.12`, and
`v7.0` have the `btrfs_tree_parent_check` readahead infrastructure.
`v5.15`/`v6.1` have older `read_extent_buffer_pages()` interfaces, so
they would need a tailored backport rather than the exact diff.
## Phase 4: Mailing List And External Research
Record 4.1: `b4 dig -c a86a283430e1a` failed exact patch-id matching,
then found the candidate by author/subject at
`49ae0f6badb787c1111daff252f034b7ae94f257.1775991651.git.wqu@suse.com`.
`b4 am` fetched the candidate patch and showed 3 thread messages.
Record 4.2: `b4 dig -w` mis-associated the related earlier patch thread,
so I did not rely on it for candidate recipients. The candidate mbox
shows it was sent to `linux-btrfs@vger.kernel.org`; David Sterba replied
with `Reviewed-by`.
Record 4.3: The linked bug thread contains a concrete fuzzed-image
crash: `kernel BUG at fs/btrfs/ctree.c:3388`, call chain through
`push_leaf_left()`, `btrfs_del_items()`, `btrfs_del_csums()`, delayed
refs, transaction commit, and `sync`. Qu replied that detecting the
empty non-root leaf earlier during extent-buffer validation was
preferable.
Record 4.4: Related patch context: the linked patch proposed checking
`push_leaf_left()` directly. Qu rejected that as too late and followed
with this broader readahead validation coverage patch. No newer revision
of this candidate was found; the final commit incorporated David’s minor
review by dropping the unnecessary trailing comma from the submitted
diff.
Record 4.5: WebFetch of the stable lore search was blocked by Anubis, so
stable-list discussion could not be verified through WebFetch. No
stable-specific rationale against this patch was found locally.
## Phase 5: Code Semantic Analysis
Record 5.1: Modified functions: `btrfs_readahead_tree_block()` and
`btrfs_readahead_node_child()`.
Record 5.2: Callers of `btrfs_readahead_node_child()` in the local tree
are Btrfs tree search/balance readahead in `ctree.c`, tree deletion
walking in `extent-tree.c`, chunk-tree read at mount in `volumes.c`, and
send-tree traversal in `send.c`. `relocate_tree_blocks()` calls
`btrfs_readahead_tree_block()` directly.
Record 5.3: Key callees are `btrfs_node_key_to_cpu()`,
`btrfs_node_blockptr()`, `btrfs_node_ptr_generation()`,
`btrfs_find_create_tree_block()`, `btrfs_buffer_uptodate()`, and
`read_extent_buffer_pages_nowait()`.
Record 5.4: Reachability is real for Btrfs users: metadata readahead
occurs during tree searches, balancing, send traversal, chunk-tree mount
processing, and snapshot/drop-tree walking. The concrete bug report
reaches a crash via filesystem operation and `sync` on a corrupted
mounted image.
Record 5.5: Similar pattern exists in normal tree reads:
`read_block_for_search()` already builds a parent check with
`has_first_key = true`. This patch aligns readahead with that existing
checked read path.
## Phase 6: Cross-Referencing And Stable Tree Analysis
Record 6.1: The affected readahead helper exists from `v5.11` onward.
Local tags show `v5.15`, `v6.1`, `v6.6`, `v6.12`, and `v7.0` contain the
readahead path; `v6.6+` contain the same parent-check structure in this
area.
Record 6.2: Backport difficulty: clean for current `v7.0.3` by `git
apply --check`; likely minor/manual for `v6.6` and `v6.12`; non-trivial
for `v5.15`/`v6.1` due older metadata read APIs.
Record 6.3: No equivalent fix with the same subject was found in the
checked stable working tree. Related validation infrastructure already
exists, so this patch fills a coverage gap rather than introducing the
checker.
## Phase 7: Subsystem And Maintainer Context
Record 7.1: Subsystem is `fs/btrfs`, a production filesystem.
Criticality is IMPORTANT to CORE for Btrfs users because metadata
corruption handling can mean kernel crash or filesystem transaction
abort behavior.
Record 7.2: Btrfs is actively maintained; recent logs show ongoing Btrfs
commits from Qu Wenruo and David Sterba, and `MAINTAINERS` lists David
Sterba as maintainer.
## Phase 8: Impact And Risk Assessment
Record 8.1: Affected users are Btrfs users, especially systems
encountering corrupted metadata or fuzzed/untrusted images.
Record 8.2: Trigger requires a corrupt tree block with an empty non-root
child reachable through parent-node readahead. The crash report shows a
reachable path through Btrfs csum deletion and `sync`; unprivileged
creation/mounting of such an image was not verified.
Record 8.3: Failure mode is severe: the linked report shows a kernel
`BUG`/Oops during Btrfs metadata operations. Severity: CRITICAL for
affected systems.
Record 8.4: Benefit is high because it turns a missed corruption case
into earlier detection. Risk is low because the patch is small and only
supplies existing verifier data to existing verifier code.
## Phase 9: Final Synthesis
Record 9.1: Evidence for backporting: fixes a real fuzzed corruption
crash path, reviewed by Btrfs maintainer, tiny Btrfs-only diff, no new
feature/API, clean on `v7.0.3`, aligns readahead with normal parent-key
validation. Evidence against: older stable trees need tailored
backports; no `Tested-by`; WebFetch stable-list search was blocked.
Unresolved: exact applicability to every older LTS branch without
writing/testing dedicated backports.
Record 9.2: Stable rules:
1. Obviously correct and tested: mostly yes by inspection and maintainer
review; no explicit `Tested-by`.
2. Fixes a real bug: yes, linked fuzzed image crash and Btrfs
corruption-detection gap.
3. Important issue: yes, kernel BUG/Oops on filesystem metadata path.
4. Small and contained: yes, 15 insertions / 4 deletions in Btrfs.
5. No new features/APIs: yes.
6. Can apply to stable: yes for current `v7.0.y`; likely minor/tailored
for other modern stable trees; older LTS needs more care.
Record 9.3: No automatic exception category such as device ID, quirk,
DT, build, or docs. This is a filesystem bug fix.
Record 9.4: Decision: backport. The benefit of earlier metadata
corruption detection and avoiding a documented Btrfs BUG outweighs the
low risk of passing an existing parent key into existing checks.
## Verification
- Phase 1: Parsed `git show -s a86a283430e1a`; confirmed subject, body,
tags, author, reviewer, and lack of `Fixes:`/`Tested-by`.
- Phase 2: Used `git show --stat --numstat` and full patch; confirmed
files, line counts, and function changes.
- Phase 3: Used `git blame -L :btrfs_readahead_tree_block`,
`:btrfs_readahead_node_child`, and `:btrfs_verify_level_key`;
confirmed historical origins and validation code.
- Phase 3: Used `git log master --oneline -- fs/btrfs/...` and author
logs; confirmed related Btrfs history and author activity.
- Phase 4: Used `b4 dig -c`, `b4 dig -a`, `b4 am`, and `b4 mbox`;
confirmed candidate thread, related bug thread, maintainer review, and
absence of substantive objections beyond a minor comma cleanup.
- Phase 4: WebFetch of lore pages was blocked by Anubis; b4 mbox
provided the mailing-list content instead.
- Phase 5: Used `rg` and code reads for callers in `ctree.c`, `extent-
tree.c`, `volumes.c`, and `send.c`; confirmed reachability through
Btrfs metadata operations.
- Phase 6: Used `git grep` on `v5.15`, `v6.1`, `v6.6`, `v6.12`, `v7.0`;
confirmed code presence and API differences.
- Phase 6: Ran `git apply --check` of the candidate diff on current
`v7.0.3`; patch applies with offsets.
- Phase 7: Checked `MAINTAINERS`; David Sterba is Btrfs maintainer.
- Phase 8: Read the linked bug mbox; confirmed the kernel BUG/Oops stack
through `btrfs_del_csums()` and `sync`.
**YES**
fs/btrfs/extent_io.c | 14 ++++++++++++--
fs/btrfs/extent_io.h | 3 ++-
fs/btrfs/relocation.c | 2 +-
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 5f97a3d2a8d72..83feb96b82673 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4593,7 +4593,8 @@ int try_release_extent_buffer(struct folio *folio)
* to read the block we will not block on anything.
*/
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
- u64 bytenr, u64 owner_root, u64 gen, int level)
+ u64 bytenr, u64 owner_root, u64 gen, int level,
+ const struct btrfs_key *first_key)
{
struct btrfs_tree_parent_check check = {
.level = level,
@@ -4602,6 +4603,11 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
struct extent_buffer *eb;
int ret;
+ if (first_key) {
+ memcpy(&check.first_key, first_key, sizeof(struct btrfs_key));
+ check.has_first_key = true;
+ }
+
eb = btrfs_find_create_tree_block(fs_info, bytenr, owner_root, level);
if (IS_ERR(eb))
return;
@@ -4629,9 +4635,13 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
*/
void btrfs_readahead_node_child(struct extent_buffer *node, int slot)
{
+ struct btrfs_key node_key;
+
+ btrfs_node_key_to_cpu(node, &node_key, slot);
btrfs_readahead_tree_block(node->fs_info,
btrfs_node_blockptr(node, slot),
btrfs_header_owner(node),
btrfs_node_ptr_generation(node, slot),
- btrfs_header_level(node) - 1);
+ btrfs_header_level(node) - 1,
+ &node_key);
}
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 8d05f1a58b7c3..6f7e3ead1dbaa 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -264,7 +264,8 @@ static inline void wait_on_extent_buffer_writeback(struct extent_buffer *eb)
}
void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
- u64 bytenr, u64 owner_root, u64 gen, int level);
+ u64 bytenr, u64 owner_root, u64 gen, int level,
+ const struct btrfs_key *first_key);
void btrfs_readahead_node_child(struct extent_buffer *node, int slot);
/* Note: this can be used in for loops without caching the value in a variable. */
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 2519cdb401eda..ff31266a44a4d 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -2610,7 +2610,7 @@ int relocate_tree_blocks(struct btrfs_trans_handle *trans,
if (!block->key_ready)
btrfs_readahead_tree_block(fs_info, block->bytenr,
block->owner, 0,
- block->level);
+ block->level, NULL);
}
/* Get first keys */
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.18] btrfs: fix wrong min_objectid in btrfs_previous_item() call
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.6] btrfs: apply first key check for readahead when possible Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: check return value of btrfs_partially_delete_raid_extent() Sasha Levin
` (3 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, Johannes Thumshirn, David Sterba, Sasha Levin, clm,
linux-btrfs, linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit 1871ae78ffa5ce7c0458e9ba5867958c1753e425 ]
When found_start > start and slot == 0, btrfs_previous_item() is called
with min_objectid=start to find the previous stripe extent. However, the
previous stripe extent we are looking for has objectid < start (it starts
before our deletion range), so passing start as min_objectid prevents
finding it.
Fix by passing 0 as min_objectid to allow finding any preceding stripe
extent regardless of its objectid.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Record 1.1: Subsystem `btrfs`; action verb `fix`; claimed intent is
correcting the `min_objectid` argument to `btrfs_previous_item()` in the
RAID stripe-tree deletion path.
Record 1.2: Tags found: `Reviewed-by: Johannes Thumshirn
<johannes.thumshirn@wdc.com>`, `Signed-off-by: robbieko
<robbieko@synology.com>`, `Reviewed-by: David Sterba
<dsterba@suse.com>`, `Signed-off-by: David Sterba <dsterba@suse.com>`.
No `Fixes:`, `Reported-by:`, `Tested-by:`, `Link:`, or `Cc:
stable@vger.kernel.org` tags were present.
Record 1.3: The commit describes a real lookup bug: when `found_start >
start` and `slot == 0`, the code tries to find the previous RAID stripe
extent, but passes `min_objectid=start`. `btrfs_previous_item()` stops
when it sees an item with `objectid < min_objectid`, so it cannot return
the previous extent that starts before `start`.
Record 1.4: This is not hidden cleanup. It is an explicit
logic/correctness fix for a failed previous-item lookup.
## Phase 2: Diff Analysis
Record 2.1: One file changed: `fs/btrfs/raid-stripe-tree.c`, 1 insertion
and 1 deletion. Modified function: `btrfs_delete_raid_extent()`. Scope:
single-file, one-line surgical fix.
Record 2.2: Before: `btrfs_previous_item(stripe_root, path, start,
BTRFS_RAID_STRIPE_KEY)` would reject any candidate with `objectid <
start`. After: `min_objectid=0` allows searching back to earlier stripe
extents.
Record 2.3: Bug category: logic/correctness bug in B-tree item lookup.
Mechanism verified in `btrfs_previous_item()`: it breaks when
`found_key.objectid < min_objectid` before returning a matching type, so
`min_objectid=start` prevents the intended previous extent from being
found.
Record 2.4: Fix quality is high: one argument change, no API changes, no
new feature. Regression risk is low, but not zero: the same series has
the immediately following patch `653361585d251` adding a proper overlap
check after this fallback, so stable backports should consider the
surrounding RAID stripe-tree deletion fixes too.
## Phase 3: Git History Investigation
Record 3.1: `git blame` shows the buggy call was introduced by
`76643119045ee` (`btrfs: fix deletion of a range spanning parts two RAID
stripe extents`), first contained around `v6.14-rc1`. The broader RAID
stripe tree code was introduced by `ca41504efda6`, first contained
around `v6.7-rc1`.
Record 3.2: No `Fixes:` tag is present, so there was no tag target to
follow.
Record 3.3: Recent file history shows this commit is patch 3 in a six-
patch RAID stripe-tree deletion bugfix series: `513f8a52eed88`,
`2aef5cb1dcf9b`, `1871ae78ffa5c`, `653361585d251`, `fe0cdfd7118d8`, and
`a8d58a7c02009`. This commit applies standalone to `v7.0.3`, but it is
part of a related correctness series.
Record 3.4: Author `robbieko` had several same-day Btrfs RAID stripe-
tree fixes in `fs/btrfs`. Committer/reviewer David Sterba is the Btrfs
maintainer.
Record 3.5: No hard prerequisite is needed for this one-line change to
apply. `git apply --check` against the current `stable/linux-7.0.y`
checkout succeeded. Semantic companion patches exist and should be
considered, especially the next ASSERT-to-error-handling fix.
## Phase 4: Mailing List And External Research
Record 4.1: `b4 dig -c 1871ae78ffa5c` found the original submission at `
https://patch.msgid.link/20260413065249.2320122-4-
robbieko@synology.com`, titled `[PATCH 3/6] btrfs: fix wrong
min_objectid in btrfs_previous_item() call`.
Record 4.2: `b4 dig -w` showed original recipients: `robbieko
<robbieko@synology.com>` and `linux-btrfs@vger.kernel.org`. The mbox
shows Johannes Thumshirn reviewed patch 3 with “Looks good” and
`Reviewed-by`.
Record 4.3: No external bug report, syzbot report, or user report was
linked.
Record 4.4: The cover letter says the series fixes six bugs in
`fs/btrfs/raid-stripe-tree.c`, all in stripe extent deletion and partial
deletion paths. Patch 3 is specifically this wrong `min_objectid` fix.
Record 4.5: `WebFetch` for lore and stable searches was blocked by
Anubis. Local `b4` mbox inspection found no stable-specific nomination
or objection.
## Phase 5: Code Semantic Analysis
Record 5.1: Modified function: `btrfs_delete_raid_extent()`.
Record 5.2: Verified callers: production caller is
`do_free_extent_accounting()` in `fs/btrfs/extent-tree.c`; tests also
call it from `fs/btrfs/tests/raid-stripe-tree-tests.c`.
Record 5.3: Key callees include `btrfs_search_slot()`,
`btrfs_previous_item()`, `btrfs_partially_delete_raid_extent()`, and
`btrfs_del_item()`. The affected path is the stripe extent deletion path
for Btrfs RAID stripe tree.
Record 5.4: Verified call chain: `__btrfs_free_extent()` calls
`do_free_extent_accounting()` when data extent refs drop to zero; that
calls `btrfs_delete_raid_extent()`. If `btrfs_delete_raid_extent()`
returns an error, `do_free_extent_accounting()` aborts the transaction.
I did not fully trace from VFS syscall entry, so unprivileged
triggerability is not relied on for the decision.
Record 5.5: Similar nearby bugfixes were found in the same series,
indicating this area had multiple deletion-path correctness bugs.
## Phase 6: Stable Tree Analysis
Record 6.1: The buggy `btrfs_previous_item(..., start, ...)` call exists
in release tags `v6.14`, `v6.14.11`, `v6.15`, `v6.15.11`, `v6.16`,
`v6.17`, `v6.18`, `v6.19`, `v7.0`, and current `v7.0.3`. It is absent
from `v6.13`, `v6.12`, `v6.6`, and `v6.1`.
Record 6.2: Backport difficulty is low for `v7.0.3`; `git apply --check`
succeeded. Older affected stable trees likely need only minor context
adjustment if their surrounding code differs.
Record 6.3: I did not find an alternate already-applied fix in the
checked release tags; `master` contains the corrected `min_objectid=0`
call.
## Phase 7: Subsystem And Maintainer Context
Record 7.1: Subsystem: Btrfs filesystem, specifically RAID stripe-tree
support. Criticality: important but feature-specific, not universal.
Record 7.2: `fs/btrfs` is actively maintained. Recent history shows
multiple April 2026 Btrfs fixes and the RAID stripe-tree deletion series
merged by David Sterba.
## Phase 8: Impact And Risk
Record 8.1: Affected users are Btrfs users with the `RAID_STRIPE_TREE`
incompat feature enabled and data block group profiles covered by
`BTRFS_RST_SUPP_BLOCK_GROUP_MASK` (`DUP`, `RAID0`, `RAID1` variants,
`RAID10`).
Record 8.2: Trigger condition is freeing/deleting a data extent range
that spans stripe extents where the next found stripe extent is at slot
0 and the needed previous stripe extent starts before `start`. Verified
from code flow; frequency in real workloads is not quantified.
Record 8.3: Failure mode: the old code can fail to find the needed
previous stripe extent, return `-ENOENT`, and cause
`do_free_extent_accounting()` to abort the transaction. Severity: high
for affected filesystems, because transaction abort is a serious
filesystem failure.
Record 8.4: Benefit is high for affected Btrfs RAID stripe-tree users.
Risk is low: one-line contained fix, reviewed by Btrfs developers, no
API change. Main concern is that this is part of a six-patch correctness
series, so stable maintainers should evaluate adjacent fixes as well.
## Phase 9: Final Synthesis
Record 9.1: Evidence for backporting: real Btrfs deletion-path bug;
verified wrong argument against `btrfs_previous_item()` semantics; bug
exists in `v6.14+` release lines; failure can abort Btrfs transactions;
fix is one line and reviewed by Johannes Thumshirn and David Sterba.
Evidence against: no reported user/syzbot case and feature-specific
impact; companion patches in same area should be considered. Unresolved:
exact real-world frequency and exact backport conflicts for every
affected stable branch were not fully checked.
Record 9.2 stable rules: obviously correct: yes, verified by code
semantics and reviews. Fixes a real bug: yes, incorrect lookup bound.
Important issue: yes for affected Btrfs filesystems, because it can
abort transactions. Small and contained: yes, one line in one function.
No new features/APIs: yes. Applies to stable: verified clean on current
`v7.0.3`; likely low difficulty for affected `v6.14+`.
Record 9.3: No exception category applies; this is a filesystem bug fix,
not a device ID, quirk, DT, build, or documentation change.
Record 9.4: Decision: backport. The patch is small, technically
justified, and fixes a serious correctness problem in a stable-visible
Btrfs feature. Prefer reviewing/backporting the surrounding RAID stripe-
tree deletion fixes too, but this commit itself is stable material.
## Verification
- Phase 1: Parsed commit `1871ae78ffa5c`; confirmed tags and absence of
`Fixes:`, `Reported-by:`, `Tested-by`, `Link`, and stable Cc.
- Phase 2: Inspected diff; confirmed exactly 1-line argument change in
`btrfs_delete_raid_extent()`.
- Phase 2: Read `btrfs_previous_item()`; confirmed it stops once
`found_key.objectid < min_objectid`.
- Phase 3: Ran `git blame`; confirmed buggy call introduced by
`76643119045ee`.
- Phase 3: Ran `git describe --contains`; confirmed `76643119045ee` is
first contained around `v6.14-rc1`.
- Phase 3: Reviewed recent file history; confirmed this commit is part
of a six-patch RAID stripe-tree deletion fix series.
- Phase 3: Ran `git apply --check`; confirmed the patch applies to
current `v7.0.3` checkout.
- Phase 4: Ran `b4 dig -c`, `-a`, and `-w`; confirmed lore message ID,
series context, and original recipients.
- Phase 4: Saved/read the `b4` mbox; confirmed cover letter says six
bugs are fixed and patch 3 fixes this `min_objectid` issue.
- Phase 4: Read mbox reply; confirmed Johannes Thumshirn gave `Reviewed-
by` for patch 3.
- Phase 4: `WebFetch` to lore/stable was blocked by Anubis; no web-
search result was used as evidence.
- Phase 5: Searched callers; confirmed production caller path through
`do_free_extent_accounting()` and tests.
- Phase 5: Read `do_free_extent_accounting()`; confirmed nonzero return
from `btrfs_delete_raid_extent()` aborts the transaction.
- Phase 6: Checked release tags; confirmed buggy code exists in `v6.14+`
through `v7.0.3`, absent in `v6.13`, `v6.12`, `v6.6`, and `v6.1`.
- Phase 7: Reviewed `fs/btrfs` recent history; confirmed active
subsystem and maintainer merge context.
- Phase 8: Read `btrfs_need_stripe_tree_update()`; confirmed affected
configurations are RAID stripe-tree data block groups with supported
profiles.
- UNVERIFIED: Exact real-world frequency of the trigger.
- UNVERIFIED: Full VFS syscall-to-trigger trace and unprivileged
triggerability.
- UNVERIFIED: Clean application to every affected stable branch older
than current `v7.0.3`.
**YES**
fs/btrfs/raid-stripe-tree.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 2987cb7c686ea..d2b8995febec9 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -123,7 +123,7 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
*/
if (found_start > start) {
if (slot == 0) {
- ret = btrfs_previous_item(stripe_root, path, start,
+ ret = btrfs_previous_item(stripe_root, path, 0,
BTRFS_RAID_STRIPE_KEY);
if (ret) {
if (ret > 0)
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.18] btrfs: check return value of btrfs_partially_delete_raid_extent()
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix wrong min_objectid in btrfs_previous_item() call Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix raid stripe search missing entries at leaf boundaries Sasha Levin
` (2 subsequent siblings)
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, Johannes Thumshirn, David Sterba, Sasha Levin, clm,
linux-btrfs, linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit a8d58a7c0200904ff24ca7f0d7c147017e25aa99 ]
btrfs_partially_delete_raid_extent() returns an error code (e.g.
-ENOMEM from kzalloc(), or errors from btrfs_del_item/btrfs_insert_item()),
but all three call sites in btrfs_delete_raid_extent() discard the
return value, silently losing errors and potentially leaving the stripe
tree in an inconsistent state.
Fix by capturing the return value into ret at all three call sites and
breaking out of the loop on error where appropriate.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Backport Analysis
### Phase 1: Commit Message Forensics
Record 1.1: Subsystem `btrfs`; action verb `check`; intent is to
propagate errors from `btrfs_partially_delete_raid_extent()` instead of
silently treating failed stripe-tree updates as success.
Record 1.2: Tags present: `Reviewed-by: Johannes Thumshirn
<johannes.thumshirn@wdc.com>`, `Signed-off-by: robbieko
<robbieko@synology.com>`, `Signed-off-by: David Sterba
<dsterba@suse.com>`. No `Fixes:`, no `Cc: stable`, no `Reported-by`.
Record 1.3: The body describes ignored `-ENOMEM`, `btrfs_del_item()`,
and `btrfs_insert_item()` errors, with the failure mode being silently
lost errors and possible RAID stripe tree inconsistency.
Record 1.4: This is a hidden bug fix despite the “check return value”
wording: it fixes error propagation and prevents filesystem metadata
update failures from being reported as success.
### Phase 2: Diff Analysis
Record 2.1: One file changed: `fs/btrfs/raid-stripe-tree.c`, 12
additions and 7 deletions. Modified function:
`btrfs_delete_raid_extent()`. Scope: single-file surgical error-handling
fix.
Record 2.2: Before, three calls to
`btrfs_partially_delete_raid_extent()` discarded the return value.
After, all three store it in `ret`; the middle loop case additionally
breaks immediately on error before advancing `start`/`length`.
Record 2.3: Bug category: error-path/correctness fix. The helper can
fail before modifying the tree (`kzalloc()`), during deletion, or during
insertion; ignoring those failures can leave the caller deleting more
extents or returning success after a failed partial update.
Record 2.4: Fix quality is high: it only propagates existing errors
through the existing `ret` path. Regression risk is low; the behavior
change is that real failures now abort/return instead of being hidden.
### Phase 3: Git History
Record 3.1: `git blame` shows `btrfs_partially_delete_raid_extent()` was
introduced by `6aea95ee318890` and changed to return errors by
`dc14ba10781bd`. The ignored call sites come from the partial
deletion/hole-punching work around `a678543e609df`, `50cae2ca69561`, and
`6aa0e7cc569eb`.
Record 3.2: No `Fixes:` tag is present, so there was no tagged
introducer to follow. History shows the relevant bug only exists once
`dc14ba10781bd` made the helper return `int`.
Record 3.3: Recent master history shows this is patch 6 of a six-patch
RAID stripe tree deletion bug-fix series. The candidate applies cleanly
to the current 7.0.y checkout without requiring the preceding five
patches for context.
Record 3.4: The author has multiple adjacent btrfs RAID stripe tree
fixes in master; David Sterba committed the patch, and Johannes
Thumshirn reviewed it.
Record 3.5: Dependency: target tree must have the `int`-returning helper
from `dc14ba10781bd`. Verified present in v6.14+ and absent in
v6.12/v6.13, so older trees without that helper form are not applicable.
### Phase 4: Mailing List And External Research
Record 4.1: `b4 dig -c a8d58a7c02009` found the original submission at `
https://patch.msgid.link/20260413065249.2320122-7-
robbieko@synology.com`. `b4 dig -a` found a single v1 series.
Record 4.2: `b4 dig -w` showed the patch was sent to `linux-
btrfs@vger.kernel.org`; direct recipients were limited, but the
subsystem list was included.
Record 4.3: No external bug report or syzbot link exists for this
specific patch.
Record 4.4: The cover letter states all six patches fix bugs in RAID
stripe tree deletion paths. Johannes requested tests for the series;
patch 6 itself received “Looks good” and `Reviewed-by`.
Record 4.5: Lore `WebFetch` was blocked by Anubis, but the yhbt mirror
and local `b4` mbox were readable. I found no stable-specific discussion
or explicit stable nomination.
### Phase 5: Code Semantic Analysis
Record 5.1: Modified function: `btrfs_delete_raid_extent()`.
Record 5.2: Callers found: `do_free_extent_accounting()` calls
`btrfs_delete_raid_extent()` for data extents; btrfs sanity tests also
call it.
Record 5.3: Key callees: `btrfs_partially_delete_raid_extent()` calls
`kzalloc()`, `btrfs_del_item()`, and `btrfs_insert_item()`.
`btrfs_delete_raid_extent()` also uses B-tree search/delete helpers.
Record 5.4: Reachability verified through delayed reference processing:
`run_one_delayed_ref()` -> `run_delayed_data_ref()` ->
`__btrfs_free_extent()` -> `do_free_extent_accounting()` ->
`btrfs_delete_raid_extent()`. This is reachable from normal Btrfs extent
freeing and transaction commit paths.
Record 5.5: Similar pattern search found only these three helper call
sites, and the patch fixes all of them.
### Phase 6: Stable Tree Analysis
Record 6.1: The buggy code exists in trees containing `dc14ba10781bd`:
verified v6.14, v6.15, v6.16, v6.17, v6.18, v6.19, and current 7.0.y
lineage. It is not applicable to v6.12/v6.13 as checked.
Record 6.2: Backport difficulty is low for the current 7.0.y checkout:
`git apply --check` for the candidate patch succeeded cleanly.
Record 6.3: Searches for this subject and “silently losing errors”
between v6.14 and v6.19 found no already-applied equivalent fix.
### Phase 7: Subsystem Context
Record 7.1: Subsystem is Btrfs filesystem metadata, specifically RAID
stripe tree support. Criticality: important to critical for users of
Btrfs filesystems with `RAID_STRIPE_TREE` enabled.
Record 7.2: The file has active recent maintenance and multiple bug
fixes, which indicates the area is actively being stabilized rather than
being a feature-only churn area.
### Phase 8: Impact And Risk
Record 8.1: Affected users are Btrfs users with the RAID stripe tree
incompat feature and supported RAID/DUP data profiles.
Record 8.2: Trigger is extent deletion/freeing where a stripe extent is
partially deleted and the helper hits allocation or B-tree operation
failure. User reachability depends on write access to such a mounted
filesystem; I verified ordinary filesystem extent-freeing paths, not a
standalone reproducer.
Record 8.3: Failure mode is hidden filesystem metadata update failure
and possible RAID stripe tree inconsistency. Severity: HIGH, with
data/metadata integrity risk.
Record 8.4: Benefit is high because errors propagate to transaction
abort handling instead of being hidden. Risk is low because the patch is
small, local, and only changes failure handling.
### Phase 9: Final Synthesis
Record 9.1: Evidence for backporting: real error propagation bug;
filesystem metadata consistency impact; small single-file patch; all
call sites fixed; reviewed by Johannes Thumshirn; committed by David
Sterba; applies cleanly to current 7.0.y. Evidence against: no explicit
stable tag, no external bug report, no direct test tag, and only
relevant to RAID stripe tree users.
Record 9.2: Stable checklist: obviously correct, yes; fixes a real bug,
yes; important issue, yes due filesystem metadata consistency; small and
contained, yes; no new features/APIs, yes; can apply to stable, yes for
current 7.0.y and likely v6.14+ trees with the helper.
Record 9.3: No special exception category applies; this is a normal bug
fix.
Record 9.4: The technical merit supports backporting to stable trees
that contain the `int`-returning `btrfs_partially_delete_raid_extent()`
implementation. Do not backport to trees where the helper is still
`void`.
## Verification
- Phase 1: Parsed `git show --format=fuller --stat --patch
a8d58a7c02009`; confirmed tags and message.
- Phase 2: Inspected the diff; confirmed one file, `12+ / 7-`, and three
ignored return values fixed.
- Phase 3: Ran `git blame` on helper and call-site ranges; identified
relevant introducer/history commits.
- Phase 3: Checked related file history on current tree and master;
found the six-patch deletion-path series.
- Phase 3/6: Ran `git apply --check` with the candidate patch against
current checkout; it applies cleanly.
- Phase 4: Ran `b4 dig -c`, `-a`, `-w`, and saved/read the mbox;
verified v1 submission, review, and no patch-specific objections.
- Phase 4: WebFetch to lore was blocked by Anubis; yhbt mirror fetch
succeeded and matched the b4 thread.
- Phase 5: Used code search and file reads to trace
`btrfs_delete_raid_extent()` through `do_free_extent_accounting()` and
delayed refs.
- Phase 6: Used `git merge-base --is-ancestor` to verify v6.14+ contains
the helper returning errors; v6.12/v6.13 do not.
- Phase 8: Verified `do_free_extent_accounting()` aborts the transaction
on nonzero return from `btrfs_delete_raid_extent()`.
**YES**
fs/btrfs/raid-stripe-tree.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 5909ad35a1b07..86ddc3ecb4060 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -213,8 +213,9 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
/* The "left" item. */
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
- btrfs_partially_delete_raid_extent(trans, path, &key,
- diff_start, 0);
+ ret = btrfs_partially_delete_raid_extent(trans, path,
+ &key,
+ diff_start, 0);
break;
}
@@ -230,8 +231,11 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_start < start) {
u64 diff_start = start - found_start;
- btrfs_partially_delete_raid_extent(trans, path, &key,
- diff_start, 0);
+ ret = btrfs_partially_delete_raid_extent(trans, path,
+ &key,
+ diff_start, 0);
+ if (ret)
+ break;
start += (key.offset - diff_start);
length -= (key.offset - diff_start);
@@ -254,9 +258,10 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
if (found_end > end) {
u64 diff_end = found_end - end;
- btrfs_partially_delete_raid_extent(trans, path, &key,
- key.offset - length,
- length);
+ ret = btrfs_partially_delete_raid_extent(trans, path,
+ &key,
+ key.offset - length,
+ length);
ASSERT(key.offset - diff_end == length);
break;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.18] btrfs: fix raid stripe search missing entries at leaf boundaries
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: check return value of btrfs_partially_delete_raid_extent() Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: copy devid in btrfs_partially_delete_raid_extent() Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0] btrfs: abort transaction in do_remap_reloc_trans() on failure Sasha Levin
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, Johannes Thumshirn, David Sterba, Sasha Levin, clm,
linux-btrfs, linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit 2aef5cb1dcf9b3e1be3895a6477dc065e618aab8 ]
In btrfs_delete_raid_extent(), the search key uses offset=0. When the
target stripe entry is the first item on a leaf, btrfs_search_slot()
may land on the previous leaf and decrementing the slot from nritems
still points to the wrong entry, causing the stripe extent to be
silently missed.
Fix this by searching with offset=(u64)-1 instead. Since no real stripe
entry has this offset, btrfs_search_slot() always returns 1 with the
slot pointing past the last matching objectid entry. Then unconditionally
decrement the slot with a proper slots[0]==0 early-exit check to handle
the case where no matching entry exists.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Decision Summary
Backport this to stable trees that contain the
`btrfs_delete_raid_extent()` `offset = 0` search logic, verified locally
in `v6.13` through `v7.0`. It is a small Btrfs filesystem metadata
correctness fix: a leaf-boundary search miss can leave a RAID stripe-
tree entry undeleted, and that tree is used later to derive read-side
physical stripe mappings.
The main caveat is scope: RAID stripe tree support is behind
`CONFIG_BTRFS_EXPERIMENTAL`, so the affected population is config and
filesystem-feature specific. Still, for those users, the benefit
outweighs the low patch risk.
## Phase Walkthrough
Phase 1: Commit Message Forensics
- Step 1.1 Record: subsystem `btrfs`; action verb `fix`; intent is to
prevent RAID stripe-tree deletion from missing entries at B-tree leaf
boundaries.
- Step 1.2 Record: tags are `Reviewed-by: Johannes Thumshirn
<johannes.thumshirn@wdc.com>`, `Signed-off-by: robbieko
<robbieko@synology.com>`, `Signed-off-by: David Sterba
<dsterba@suse.com>`. No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc:
stable`, or `Link:` tags.
- Step 1.3 Record: the described bug is that searching with `offset = 0`
can land on the previous leaf when the target stripe item is the first
item in the next leaf; the existing decrement then inspects the wrong
entry and silently misses the stripe extent. No affected kernel
versions are stated in the message.
- Step 1.4 Record: this is not hidden cleanup; it is an explicit
correctness bug fix.
Phase 2: Diff Analysis
- Step 2.1 Record: one file changed, `fs/btrfs/raid-stripe-tree.c`,
+15/-3 in `btrfs_delete_raid_extent()`. Scope is single-function
surgical.
- Step 2.2 Record: before, the delete loop searched `(objectid=start,
type=RAID_STRIPE, offset=0)` and only decremented the slot when the
slot was at `nritems`. After, it searches with `offset=(u64)-1`,
checks `slots[0] == 0`, then always decrements to the last candidate
item.
- Step 2.3 Record: bug category is logic/correctness in B-tree search
positioning. The fix uses Btrfs key ordering by `objectid`, then
`type`, then `offset`, and `btrfs_bin_search()` semantics where a
missing key returns the insertion slot.
- Step 2.4 Record: fix quality is good for valid filesystem state:
small, local, no API changes. Regression risk is low. One review
concern exists: David Sterba noted that an exact corrupt
`offset=(u64)-1` key should ideally be handled as `-EUCLEAN`; that is
robustness against corrupted/fuzzed images, not the normal valid-state
bug being fixed.
Phase 3: Git History Investigation
- Step 3.1 Record: blame shows the delete function was introduced by
`ca41504efda646` in `v6.7`, but the specific `key.offset = 0` logic
and `nritems` decrement pattern were introduced by `6aea95ee318890`
(`btrfs: implement partial deletion of RAID stripe extents`), first
contained in `v6.13`.
- Step 3.2 Record: no `Fixes:` tag, so no tagged original commit to
follow. Blame nevertheless identifies `6aea95ee318890` as the relevant
introducer.
- Step 3.3 Record: related recent commits in master are a six-patch
deletion-path fix series: copy missing devid, this leaf-boundary
search fix, wrong `btrfs_previous_item()` min objectid, ASSERT-to-
error handling, `-EAGAIN`/stale leaf handling, and return-value
checking.
- Step 3.4 Record: author `robbieko` authored all six related RAID
stripe-tree deletion fixes in that series. I did not verify them as a
subsystem maintainer; David Sterba committed the series and Johannes
reviewed this patch.
- Step 3.5 Record: candidate applies standalone to the current `7.0.3`
worktree via `git apply --check`; companion patches are related fixes
but not prerequisites for this hunk.
Phase 4: Mailing List And External Research
- Step 4.1 Record: `b4 dig -c 2aef5cb1dcf9b` found the original
submission at `https://patch.msgid.link/20260413065249.2320122-3-
robbieko@synology.com`. `b4 dig -a` found only v1 of the six-patch
series.
- Step 4.2 Record: `b4 dig -w` showed original recipients were
`robbieko` and `linux-btrfs@vger.kernel.org`. The thread later
includes Johannes Thumshirn and David Sterba review/maintainer
feedback.
- Step 4.3 Record: no separate bug report or syzbot report was linked.
- Step 4.4 Record: series context confirms this is patch 2/6 in “fix
multiple bugs in raid-stripe-tree deletion path.” Johannes asked for
tests for the conditions; Johannes also gave `Reviewed-by` on this
patch. David later said the series was added to `for-next`.
- Step 4.5 Record: direct lore stable search was blocked by Anubis; web
search did not find stable-specific discussion. This remains
unverified.
Phase 5: Code Semantic Analysis
- Step 5.1 Record: modified function is `btrfs_delete_raid_extent()`.
- Step 5.2 Record: callers are `do_free_extent_accounting()` in
`fs/btrfs/extent-tree.c` and RAID stripe-tree selftests.
`do_free_extent_accounting()` is reached when a data extent’s refs
drop to zero in `__btrfs_free_extent()`.
- Step 5.3 Record: key callees include `btrfs_search_slot()`,
`btrfs_item_key_to_cpu()`, `btrfs_del_item()`,
`btrfs_previous_item()`, and partial deletion helpers.
- Step 5.4 Record: user reachability is through Btrfs extent
deletion/accounting paths; `file.c` calls `btrfs_free_extent()` while
dropping file extents. Exact VFS entrypoints were not fully traced,
but the path is filesystem-operation reachable on RST-enabled
filesystems.
- Step 5.5 Record: similar verified patterns include
`btrfs_search_prev_slot()` checking `slot == 0` before decrementing.
`zoned.c` also demonstrates the Btrfs pattern of treating impossible
exact matches as `-EUCLEAN`, matching David’s review concern.
Phase 6: Stable Tree Analysis
- Step 6.1 Record: `v6.6` lacks this file/feature; `v6.12` has
`key.offset = length`; `v6.13` through `v7.0` have `key.offset = 0`
plus the vulnerable `nritems` decrement. Candidate is in `v7.1-rc2`,
not in `v7.0`.
- Step 6.2 Record: backport difficulty is clean for current `7.0.3` by
`git apply --check`; older affected trees appear to have the same
local search pattern, but exact apply was not checked on separate
worktrees.
- Step 6.3 Record: no alternate stable fix for the same subject was
found locally; stable-list search was blocked, so external stable
history is partially unverified.
Phase 7: Subsystem Context
- Step 7.1 Record: subsystem is Btrfs filesystem, specifically RAID
stripe tree. Criticality is important for users of that filesystem
feature, but not universal.
- Step 7.2 Record: file history shows active development and several
recent bug fixes in the same deletion path, indicating this code is
relatively new and still being hardened.
Phase 8: Impact And Risk
- Step 8.1 Record: affected population is config-specific and feature-
specific: Btrfs filesystems using `RAID_STRIPE_TREE`, which is
supported only when `CONFIG_BTRFS_EXPERIMENTAL` is enabled.
- Step 8.2 Record: trigger is deleting/freeing data extents where the
matching stripe item is first in a leaf. Commonness of the leaf-
boundary condition is data-layout dependent. User triggering is
partially verified via file extent deletion paths, subject to
filesystem permissions and the RST feature being enabled.
- Step 8.3 Record: failure mode is stale/missed RAID stripe-tree
deletion. Severity is high for affected users because
`btrfs_get_raid_extent_offset()` is used for read mapping and sets
`stripe->physical` from stripe-tree contents.
- Step 8.4 Record: benefit is medium-high for affected RST users; risk
is low because the change is +15/-3, one function, no ABI/API change,
and accepted by Btrfs maintainers.
Phase 9: Final Synthesis
- Step 9.1 Record: evidence for backporting: real metadata correctness
bug, verified affected stable code in `v6.13`-`v7.0`, small fix,
reviewed by Johannes, committed by David, clean apply to current
stable worktree. Evidence against: experimental/config-specific
feature, no `Reported-by`/`Tested-by`, no explicit stable nomination,
companion fixes in same area, and one unaddressed corrupt-image
robustness comment.
- Step 9.2 Record: stable rules: obviously correct for valid state yes;
fixes real bug yes; important issue yes for RST metadata/read mapping
correctness; small and contained yes; no new feature/API yes; applies
to current stable tree yes.
- Step 9.3 Record: no exception category like device ID, quirk, DT,
build, or docs applies.
- Step 9.4 Record: decision is YES, limited to stable trees containing
the `offset = 0` deletion search logic.
## Verification
- Phase 1: Parsed `git show 2aef5cb1dcf9b` and confirmed tags, subject,
message, and +15/-3 diff.
- Phase 2: Read `fs/btrfs/raid-stripe-tree.c` and confirmed the exact
modified code in `btrfs_delete_raid_extent()`.
- Phase 3: Ran blame around the changed lines; confirmed
`6aea95ee318890` introduced `offset = 0`, and tag containment starts
at `v6.13`.
- Phase 3: Inspected `ca41504efda646` and confirmed the function existed
earlier with a different `offset = length` search.
- Phase 4: `b4 dig -c 2aef5cb1dcf9b` found the patch thread; `-a` found
only v1; `-w` showed original recipients.
- Phase 4: Saved and searched the mbox; confirmed Johannes’ `Reviewed-
by`, test request, David’s `EUCLEAN` robustness comment, and David’s
“Added to for-next”.
- Phase 5: Used code search and reads to trace
`btrfs_delete_raid_extent()` from `do_free_extent_accounting()` and
`__btrfs_free_extent()`, with file deletion paths calling
`btrfs_free_extent()`.
- Phase 5: Verified read-side RST use: `set_io_stripe()` calls
`btrfs_get_raid_extent_offset()` for reads, and that function sets
`stripe->physical` from the stripe-tree item.
- Phase 6: Checked historical tags: `v6.12` uses `offset = length`;
`v6.13`-`v7.0` use `offset = 0` and the vulnerable slot handling.
- Phase 6: Ran `git apply --check` for the upstream patch against
current `7.0.3`; it succeeded.
- UNVERIFIED: Direct lore stable search was blocked by Anubis, so
stable-list discussion could not be confirmed.
- UNVERIFIED: Exact apply status on every older affected stable tree was
not checked in separate worktrees.
**YES**
fs/btrfs/raid-stripe-tree.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index d2b8995febec9..dd924048c6659 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -95,14 +95,26 @@ int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 le
while (1) {
key.objectid = start;
key.type = BTRFS_RAID_STRIPE_KEY;
- key.offset = 0;
+ key.offset = (u64)-1;
ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1);
if (ret < 0)
break;
- if (path->slots[0] == btrfs_header_nritems(path->nodes[0]))
- path->slots[0]--;
+ /*
+ * Search with offset=(u64)-1 ensures we land on the correct
+ * leaf even when the target entry is the first item on a leaf.
+ * Since no real entry has offset=(u64)-1, ret is always 1 and
+ * slot points past the last entry with objectid==start (or
+ * past the end of the leaf if that entry is the last item).
+ * Back up one slot to find the actual entry.
+ */
+ if (path->slots[0] == 0) {
+ /* No entry with objectid <= start exists. */
+ ret = 0;
+ break;
+ }
+ path->slots[0]--;
leaf = path->nodes[0];
slot = path->slots[0];
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0-6.18] btrfs: copy devid in btrfs_partially_delete_raid_extent()
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix raid stripe search missing entries at leaf boundaries Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0] btrfs: abort transaction in do_remap_reloc_trans() on failure Sasha Levin
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: robbieko, Johannes Thumshirn, David Sterba, Sasha Levin, clm,
linux-btrfs, linux-kernel
From: robbieko <robbieko@synology.com>
[ Upstream commit 513f8a52eed880ea525dbb139b2127bd9bb793f1 ]
When btrfs_partially_delete_raid_extent() rebuilds a truncated/shifted
stripe extent into newitem, the loop copies the physical address for
each stride but forgets to copy the devid. The resulting item written
back to the stripe tree has zeroed-out devids, corrupting the stripe
mapping.
Fix this by reading the devid with btrfs_raid_stride_devid() and
writing it into the new item with btrfs_set_stack_raid_stride_devid()
before copying the physical address.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: robbieko <robbieko@synology.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: subsystem `btrfs`; action verb `copy`; claimed intent
is to preserve `devid` when `btrfs_partially_delete_raid_extent()`
rebuilds a truncated or shifted RAID stripe extent.
Step 1.2 Record: tags present are `Reviewed-by: Johannes Thumshirn
<johannes.thumshirn@wdc.com>`, `Signed-off-by: robbieko
<robbieko@synology.com>`, `Reviewed-by: David Sterba
<dsterba@suse.com>`, `Signed-off-by: David Sterba <dsterba@suse.com>`.
No `Fixes:`, `Reported-by:`, `Tested-by:`, `Link:`, or `Cc:
stable@vger.kernel.org` tag was present. David Sterba is listed as a
Btrfs maintainer in `MAINTAINERS`.
Step 1.3 Record: the body says the function rebuilds a stripe extent
into `newitem`, copies each stride’s physical address, but forgets to
copy each stride’s device id. Because `newitem` is allocated with
`kzalloc()`, omitted devid fields become zero. The described failure
mode is corrupted stripe mapping. No explicit affected kernel version is
stated.
Step 1.4 Record: this is not hidden behind cleanup wording; it is a
direct correctness fix for persistent Btrfs RAID stripe tree metadata.
## Phase 2: Diff Analysis
Step 2.1 Record: one file changed, `fs/btrfs/raid-stripe-tree.c`, with 3
insertions in `btrfs_partially_delete_raid_extent()`. Scope is a single-
file surgical fix.
Step 2.2 Record: before, the copy loop populated only
`newitem->strides[i].physical`; after, it reads `devid` from the old
stride using `btrfs_raid_stride_devid()` and stores it in the stack item
with `btrfs_set_stack_raid_stride_devid()` before copying the physical
address. The affected path is partial deletion/truncation/shift of RAID
stripe extents.
Step 2.3 Record: bug category is filesystem metadata correctness/data
corruption. Mechanism: `kzalloc()` zeroes the rebuilt item, and the old
code only writes the physical address, leaving device ids as zero. Later
lookup code in `btrfs_get_raid_extent_offset()` searches for a stride
whose stored devid matches `stripe->dev->devid`; zeroed devids can fail
that match and return `-ENODATA`.
Step 2.4 Record: the fix is obviously local and correct: it copies the
missing field from the old item to the rebuilt item. Regression risk is
very low: it adds no new behavior, no locking, no API changes, and
preserves existing physical-address handling.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` on the pre-fix function showed the rebuild-
and-reinsert logic came from `dc14ba10781bd` and the partial-delete
function originated from `6aea95ee31889`. The specific zeroed-devid bug
was introduced by `dc14ba10781bd`, first contained in `v6.14-rc1`.
Step 3.2 Record: no `Fixes:` tag exists. I manually inspected
`dc14ba10781bd`; it replaced in-place key modification with allocation
of a new item and copied only physical addresses, omitting devids. That
commit fixed a prior kernel BUG but introduced this missing-field copy.
Step 3.3 Record: recent file history shows this patch is part of a
cluster of RAID stripe tree deletion fixes: search boundary fixes,
`btrfs_previous_item()` min-objectid fix, ASSERT-to-error handling,
stale leaf pointer handling, and return-value checking. This commit is
standalone; it does not depend on later patches, though the related
patches may be independently worth stable review.
Step 3.4 Record: author `robbieko` has multiple related Btrfs fixes in
the same file around the same time. Committer/reviewer David Sterba is a
Btrfs maintainer per `MAINTAINERS`.
Step 3.5 Record: no prerequisite commit beyond the buggy rebuild-and-
reinsert implementation was identified for affected trees. The patch
applies cleanly to the current `v7.0.3` stable worktree with `git apply
--check`.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c 513f8a52eed88` found the original submission
at `https://patch.msgid.link/20260413065249.2320122-2-
robbieko@synology.com`. `b4 dig -a` showed only v1. WebFetch of lore was
blocked by Anubis, so I used `b4 dig -m` and read the mbox locally. The
thread includes David Sterba saying the series was added to for-next. No
NAK was found in the fetched thread.
Step 4.2 Record: `b4 dig -w` showed original recipients were `robbieko`
and `linux-btrfs@vger.kernel.org`. The mbox showed Johannes Thumshirn
replied and asked for tests for the series conditions; the committed
patch later carries his `Reviewed-by`.
Step 4.3 Record: no external bug report, syzbot report, or bugzilla link
was present. The cover letter and patch text both describe corrupted
stripe mappings.
Step 4.4 Record: this is patch 1/6 in a series titled `btrfs: fix
multiple bugs in raid-stripe-tree deletion path`. The other five patches
address separate bugs in the same deletion path. Patch 1 is not a
preparatory change; it fixes a complete missing-field copy on its own.
Step 4.5 Record: WebFetch search of lore stable was blocked by Anubis.
Local stable branch inspection found no equivalent devid-copy fix in
`stable/linux-7.0.y`.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: modified function is
`btrfs_partially_delete_raid_extent()`.
Step 5.2 Record: callers are the three partial-deletion cases in
`btrfs_delete_raid_extent()`: hole punch splitting a stripe extent,
front truncation, and tail truncation. `btrfs_delete_raid_extent()` is
called from Btrfs extent free accounting for data extents.
Step 5.3 Record: relevant callees are `kzalloc()`,
`btrfs_raid_stride_devid()`, `btrfs_set_stack_raid_stride_devid()`,
`btrfs_raid_stride_physical()`,
`btrfs_set_stack_raid_stride_physical()`, `btrfs_del_item()`, and
`btrfs_insert_item()`.
Step 5.4 Record: reachability is through Btrfs data extent
deletion/freeing and transaction paths. Lookup impact is through read
mapping: `btrfs_map_block()` calls `set_io_stripe()`, which calls
`btrfs_get_raid_extent_offset()` for reads when RAID stripe tree updates
are needed. If the zeroed devid does not match the real device id,
lookup returns `-ENODATA`.
Step 5.5 Record: similar correct pattern exists in
`btrfs_insert_one_raid_extent()`, which stores both devid and physical
address for each stride. The broken partial-delete rebuild copied only
physical address.
## Phase 6: Cross-Referencing And Stable Tree Analysis
Step 6.1 Record: latest checked tags show `v6.12.85` has the file but
not the affected partial-delete rebuild code; `v6.15.11`, `v6.16.12`,
`v6.17.13`, `v6.18.26`, `v6.19.14`, and `v7.0.3` contain the buggy loop
with physical copy but no devid copy. `v6.6` has no `fs/btrfs/raid-
stripe-tree.c`.
Step 6.2 Record: expected backport difficulty is low for affected trees.
The patch applies cleanly to current `v7.0.3`; older affected trees
before the `AUTO_KFREE` cleanup still have the same loop and should need
at most context adjustment.
Step 6.3 Record: no equivalent devid-copy fix was found in
`stable/linux-7.0.y`; current stable code still lacks
`btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid)`.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: subsystem is Btrfs filesystem code under `fs/btrfs`.
Criticality is IMPORTANT: it is filesystem metadata and I/O mapping, but
gated to filesystems using the RAID stripe tree incompat feature.
Step 7.2 Record: subsystem activity is high; file history shows many
recent RAID stripe tree deletion fixes. This does not reduce stable
suitability because the affected buggy code is already present in
several stable tags.
## Phase 8: Impact And Risk Assessment
Step 8.1 Record: affected users are Btrfs users with `RAID_STRIPE_TREE`
enabled and data profiles supported by
`btrfs_need_stripe_tree_update()`.
Step 8.2 Record: trigger is partial deletion of RAID stripe extents,
such as data extent freeing/truncation/hole-related deletion paths.
User-triggerability depends on having an affected Btrfs RAID stripe tree
filesystem; the exact unprivileged trigger was not separately reproduced
here.
Step 8.3 Record: failure mode is corrupted RAID stripe mapping metadata
with zeroed devids. Verified read-side code relies on devid matching and
returns `-ENODATA` when no matching devid is found. Severity is HIGH to
CRITICAL for affected filesystems because it can persistently break
logical-to-physical mapping.
Step 8.4 Record: benefit is high for affected Btrfs RST users because it
prevents persistent mapping corruption. Risk is very low because the
change is 3 lines, local, and copies an existing field without changing
control flow.
## Phase 9: Final Synthesis
Step 9.1 Record: evidence for backporting: real filesystem metadata
corruption, tiny surgical fix, reviewed by Btrfs developers including
maintainer David Sterba, affects current stable trees with the buggy
rebuild loop, and applies cleanly to `v7.0.3`. Evidence against: affects
only the RAID stripe tree feature, and no `Tested-by` or external bug
report was present. Unresolved: I did not runtime-test a reproducer, and
lore WebFetch was blocked, though b4 retrieved the thread mbox.
Step 9.2 Stable rules checklist:
1. Obviously correct and tested: obviously correct by inspection; no
explicit `Tested-by`.
2. Fixes a real bug: yes, missing copied devid causes zeroed devids in
rebuilt stripe items.
3. Important issue: yes, filesystem mapping corruption.
4. Small and contained: yes, 3 inserted lines in one function.
5. No new features or APIs: yes.
6. Can apply to stable trees: yes for `v7.0.3`; likely clean or minor
context for affected `v6.15+` stable trees.
Step 9.3 Record: no special exception category is needed; this is a
normal filesystem corruption fix.
Step 9.4 Decision: backport to stable trees that contain the rebuild-
and-reinsert version of `btrfs_partially_delete_raid_extent()` without
the devid copy, notably checked affected tags `v6.15.11` through
`v7.0.3`. Do not apply to trees where the affected code is absent, such
as checked `v6.12.85` and `v6.6`.
## Verification
- [Phase 1] Parsed commit `513f8a52eed88` with `git show
--pretty=fuller`; confirmed subject, body, tags, and 3-line diff.
- [Phase 1] Checked `MAINTAINERS` with `rg`; confirmed David Sterba is a
Btrfs maintainer.
- [Phase 2] Read `fs/btrfs/raid-stripe-tree.c`; confirmed `kzalloc()`
allocation, old physical-only copy, and read-side devid matching.
- [Phase 3] Ran `git blame 513f8a52eed88^` on the changed function;
identified relevant history from `6aea95ee31889`, `dc14ba10781bd`, and
cleanup commits.
- [Phase 3] Ran `git show dc14ba10781bd`; confirmed the buggy new-item
rebuild was introduced there and first appears in `v6.14-rc1`.
- [Phase 3] Ran recent file and author logs; confirmed related same-file
fixes and that this patch is standalone.
- [Phase 4] Ran `b4 dig -c`, `-a`, `-w`, and `-m`; found the lore
thread, single v1, original recipients, series context, and maintainer
acceptance into for-next.
- [Phase 4] WebFetch lore and stable search were blocked by Anubis; b4
mbox provided the usable mailing-list content.
- [Phase 5] Used `rg` and file reads to trace callers:
`btrfs_delete_raid_extent()` from extent free accounting, and read
mapping through `btrfs_map_block()`/`set_io_stripe()`/`btrfs_get_raid_
extent_offset()`.
- [Phase 6] Checked stable tags with `git show <tag>:fs/btrfs/raid-
stripe-tree.c`; confirmed affected code in `v6.15.11`, `v6.16.12`,
`v6.17.13`, `v6.18.26`, `v6.19.14`, and `v7.0.3`, absent affected code
in `v6.12.85`, and no file in `v6.6`.
- [Phase 6] Ran `git apply --check` for the upstream patch against
current `v7.0.3`; it applies cleanly.
- [Phase 8] Verified failure mechanism in code: zeroed devids fail the
`devid != stripe->dev->devid` match and lead to `-ENODATA`.
**YES**
fs/btrfs/raid-stripe-tree.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index a2e9ac2d97988..5909ad35a1b07 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -45,8 +45,11 @@ static int btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans,
for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) {
struct btrfs_raid_stride *stride = &extent->strides[i];
+ u64 devid;
u64 phys;
+ devid = btrfs_raid_stride_devid(leaf, stride);
+ btrfs_set_stack_raid_stride_devid(&newitem->strides[i], devid);
phys = btrfs_raid_stride_physical(leaf, stride) + frontpad;
btrfs_set_stack_raid_stride_physical(&newitem->strides[i], phys);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH AUTOSEL 7.0] btrfs: abort transaction in do_remap_reloc_trans() on failure
[not found] <20260505095149.512052-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: copy devid in btrfs_partially_delete_raid_extent() Sasha Levin
@ 2026-05-05 9:51 ` Sasha Levin
8 siblings, 0 replies; 9+ messages in thread
From: Sasha Levin @ 2026-05-05 9:51 UTC (permalink / raw)
To: patches, stable
Cc: Mark Harmstone, Johannes Thumshirn, David Sterba, Sasha Levin,
clm, linux-btrfs, linux-kernel
From: Mark Harmstone <mark@harmstone.com>
[ Upstream commit 73db0fad673af844772de964eebecae60eda0496 ]
If one of the calls made by do_remap_reloc_trans() fails, we can leave
the remap tree in an inconsistent state. Abort the transaction if this
happens, to prevent the corrupt state from reaching the disk.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Mark Harmstone <mark@harmstone.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: subsystem `btrfs`; action verb `abort`; claimed intent
is to abort the transaction from `do_remap_reloc_trans()` failure paths
so an inconsistent remap tree cannot be committed.
Step 1.2 Record: tags found in the actual public patch are `Reviewed-by:
Johannes Thumshirn`, `Signed-off-by: Mark Harmstone`, and `Signed-off-
by: David Sterba`. No `Fixes:`, `Reported-by:`, `Tested-by:`, `Link:`,
or `Cc: stable` tag was present in the fetched patch. Notable pattern:
reviewed by a Btrfs developer and committed by David Sterba.
Step 1.3 Record: the body describes a real corruption-prevention bug:
failures in `do_remap_reloc_trans()` can leave the remap tree
inconsistent, and aborting the transaction prevents that state from
reaching disk. No stack trace, reproducer, or explicit affected versions
were in the message. Root cause, as verified from code, is that the
function can return through `fail` after transactional remap/free-space
mutations without marking the transaction aborted.
Step 1.4 Record: this is not a hidden cleanup; it is an explicit
filesystem consistency fix. The subject and body both describe
preventing corrupt on-disk state.
## Phase 2: Diff Analysis
Step 2.1 Record: one file changed, `fs/btrfs/relocation.c`, with +10/-4.
One function modified: `do_remap_reloc_trans()`. Scope is a single-
function surgical filesystem fix.
Step 2.2 Record: before the patch, four failure paths jumped to `fail`,
released local references, freed the reserved extent, unlocked
`remap_mutex`, and ended the transaction without aborting it. After the
patch, those paths call `btrfs_abort_transaction(trans, ret)` before
cleanup. The `add_remap_entry()` failure path also stops attempting
`btrfs_add_to_free_space_tree()` recovery and aborts instead.
Step 2.3 Record: bug category is filesystem metadata consistency / data
corruption prevention. `add_remap_entry()` was verified to delete or
shorten identity remap entries before adding new remap and backref
items; if a later insertion fails, returning normally can leave a
partially updated remap tree. `btrfs_abort_transaction()` was verified
to mark the transaction aborted and set filesystem error state,
preventing normal commit of that partial state.
Step 2.4 Record: the fix is minimal and consistent with Btrfs
transaction rules. `transaction.c` says after abort, call-site recovery
should be limited to freeing local allocations and passing the error up;
the patch does exactly that. Regression risk is low but not zero: the
filesystem will now abort/remount error on these rare failures instead
of attempting to continue, but that is the correct trade-off for
avoiding persistent metadata corruption.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` shows the changed error paths were
introduced by `fd6594b1446cc` (`btrfs: replace identity remaps with
actual remaps when doing relocations`), authored by Mark Harmstone in
Jan 2026 and merged for the 7.0 cycle. First containing tag verified as
`v7.0-rc1~232^2~74`.
Step 3.2 Record: no `Fixes:` tag is present, so there was no explicit
tag to follow. Independent blame identifies `fd6594b1446cc` as the
introducer, and that commit exists in `stable/linux-7.0.y` but not older
checked stable branches.
Step 3.3 Record: recent local history for `fs/btrfs/relocation.c` shows
several remap-tree fixes around the same code, including block-group
reference, NULL root checks, transaction handle leak, and remap-tree
setup fixes. The candidate itself is standalone; no prerequisite was
found for the shown hunk to apply to `stable/linux-7.0.y`.
Step 3.4 Record: the author, Mark Harmstone, authored the remap-tree
relocation code and several nearby Btrfs fixes. David Sterba committed
both the introducer and the candidate in the Btrfs development tree.
Step 3.5 Record: related nearby commit `942bcf6d1884` fixes a separate
`bytes_may_use` leak in the same function. It is not a prerequisite for
this abort fix; the candidate patch applies cleanly to current
`stable/linux-7.0.y` in a dry-run.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c a41c84ba2f51303b7dca2ccf426d99c4a3a757b3`
failed because the commit object is not present in this local clone. Web
research found the original v2 thread at `https://yhbt.net/lore/linux-
btrfs/3a0c1b94-4404-4726-aafe-809c425707fc@wdc.com/T/`. The thread shows
v2 and notes the change from aborting at the end to aborting in place so
line numbers are logged properly.
Step 4.2 Record: `b4 dig -w` also failed for the same nonlocal commit
reason. The fetched lore mirror shows recipients `linux-btrfs` and Boris
Burkov, and a review reply from Johannes Thumshirn with `Reviewed-by`.
Step 4.3 Record: no separate bug report, syzbot report, or Bugzilla link
was found in the commit or lore thread. Severity comes from the patch
description and verified code mechanism: possible persistent remap-tree
inconsistency.
Step 4.4 Record: lore shows this patch as a standalone `[PATCH v2]`, not
a numbered multi-patch series. Web search found a separate same-function
accounting leak fix, but no dependency relationship.
Step 4.5 Record: stable-specific search did not find a usable stable
discussion; direct lore stable fetches were blocked by Anubis. No
evidence of a known objection or rejection was found.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: modified function is `do_remap_reloc_trans()`.
Step 5.2 Record: caller chain verified as `btrfs_ioctl_balance()` ->
`btrfs_balance()` -> `__btrfs_balance()` -> `btrfs_relocate_chunk()` ->
`btrfs_relocate_block_group()` -> `do_remap_reloc()` ->
`do_remap_reloc_trans()`. Other verified callers of
`btrfs_relocate_chunk()` include device shrink, block-group reclaim, and
zoned repair paths. Balance ioctl requires `CAP_SYS_ADMIN`.
Step 5.3 Record: key callees include
`btrfs_add_block_group_free_space()`, `copy_remapped_data()`,
`btrfs_remove_from_free_space_tree()`, `add_remap_entry()`,
`btrfs_free_reserved_extent()`, and `btrfs_end_transaction()`.
`add_remap_entry()` calls `btrfs_del_item()`,
`btrfs_set_item_key_safe()`, `add_remap_item()`,
`btrfs_insert_empty_item()`, and `add_remap_backref_item()`.
Step 5.4 Record: the buggy path is reachable from privileged userspace
via Btrfs balance and from kernel maintenance paths such as
reclaim/shrink. It is only active when
`should_relocate_using_remap_tree()` is true: filesystem has the
`REMAP_TREE` incompat feature and the block group is not system or
metadata-remap.
Step 5.5 Record: similar local patterns support aborting.
`move_existing_remap()` aborts the transaction on error before
ending/committing, and `start_block_group_remapping()` aborts on remap-
tree setup failures. `transaction.h` explicitly says to call
`btrfs_abort_transaction()` as early as possible.
## Phase 6: Cross-Referencing And Stable Tree Analysis
Step 6.1 Record: `stable/linux-7.0.y` contains `do_remap_reloc_trans()`.
`stable/linux-6.19.y`, `stable/linux-6.18.y`, `stable/linux-6.12.y`, and
`stable/linux-6.6.y` do not contain this function or remap-tree support
in the checked paths. The bug is therefore relevant to 7.0.y, not older
stable branches checked.
Step 6.2 Record: dry-run `git apply --check` of the candidate hunk
succeeded against current `stable/linux-7.0.y`, so expected backport
difficulty is clean for 7.0.y.
Step 6.3 Record: local `stable/linux-7.0.y` does not already contain the
candidate subject, and the current file still has the pre-fix failure
paths.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: subsystem is Btrfs filesystem code under `fs/btrfs`,
criticality IMPORTANT. It is not universal core code, but filesystem
metadata corruption is a high-severity stable concern for affected Btrfs
users.
Step 7.2 Record: subsystem activity is high in this area; local history
shows many Btrfs remap-tree commits and fixes in the 7.0 cycle. This is
recently introduced code, but it is already present in the 7.0 stable
tree.
## Phase 8: Impact And Risk Assessment
Step 8.1 Record: affected population is config/filesystem-specific:
users running kernels with Btrfs experimental/remap-tree support and
filesystems using the `REMAP_TREE` incompat feature, during
relocation/balance/shrink/reclaim paths.
Step 8.2 Record: trigger conditions are failures from the remap
relocation sequence after reservation and during free-space/remap-
tree/data-copy operations. Verified user trigger via balance requires
`CAP_SYS_ADMIN`; unprivileged trigger was not verified.
Step 8.3 Record: failure mode is potential persistent filesystem
metadata inconsistency / corruption of the remap tree. Severity is
CRITICAL for affected users because the commit’s stated goal is to
prevent corrupt state from reaching disk and code inspection confirms
partial remap-tree mutations can occur before error returns.
Step 8.4 Record: benefit is high for affected 7.0.y users because it
prevents committing inconsistent filesystem metadata. Risk is low: one
function, 10 additions and 4 removals, no API changes, and behavior only
changes rare error paths to abort the transaction.
## Phase 9: Final Synthesis
Step 9.1 Record: evidence for backporting is strong: real filesystem
consistency bug, verified partial transactional mutations in
`add_remap_entry()`, small single-function fix, reviewed on linux-btrfs,
clean dry-run apply to `stable/linux-7.0.y`, and Btrfs transaction
documentation supports early abort. Evidence against is limited to scope
of affected users: remap-tree is experimental/config-specific and the
bug only exists in 7.0.y among checked stable branches. Unresolved: no
independent reproducer or user report was found, and direct lore/stable
search was partially blocked.
Step 9.2 Record: stable rules checklist:
1. Obviously correct and tested: yes for correctness by inspection;
reviewed by Johannes Thumshirn. No `Tested-by` found.
2. Fixes a real bug: yes, prevents inconsistent remap-tree state after
transactional failure paths.
3. Important issue: yes, potential on-disk filesystem corruption.
4. Small and contained: yes, one function in one file, +10/-4.
5. No new features/APIs: yes.
6. Can apply to stable: yes for `stable/linux-7.0.y`; not applicable to
older checked stable branches lacking the code.
Step 9.3 Record: no exception category like device ID, quirk, DT, build,
or docs applies. This is a normal serious filesystem bug fix.
Step 9.4 Decision: backport to stable trees that contain the remap-tree
relocation code, specifically 7.0.y based on the checked branches. Do
not try to apply it to older stable trees that lack
`do_remap_reloc_trans()`.
## Verification
- [Phase 1] Fetched public patch from GitHub commit
`a41c84ba2f51303b7dca2ccf426d99c4a3a757b3`; confirmed subject, body,
tags, and +10/-4 diff.
- [Phase 2] Read `fs/btrfs/relocation.c`; confirmed old failure paths
end the transaction without aborting.
- [Phase 2] Read `add_remap_entry()`; confirmed it can delete/shorten
identity remap state before later operations fail.
- [Phase 2] Read `transaction.h` and `transaction.c`; confirmed
`btrfs_abort_transaction()` records abort state and transaction abort
rules favor local cleanup only.
- [Phase 3] `git blame -L 5032,5049 -- fs/btrfs/relocation.c`: changed
lines introduced by `fd6594b1446cc`.
- [Phase 3] `git show --stat --format=fuller fd6594b1446cc --
fs/btrfs/relocation.c`: introducer is `btrfs: replace identity remaps
with actual remaps when doing relocations`, +326 lines.
- [Phase 3] `git describe --contains fd6594b1446cc`: first containing
point reported in the 7.0-rc1 range.
- [Phase 3] `git log --author='Mark Harmstone' -10 -- fs/btrfs`: author
has multiple nearby Btrfs/remap fixes.
- [Phase 4] `b4 dig -c`, `-a`, and `-w` failed because the candidate
commit object is not in this local clone.
- [Phase 4] Fetched lore mirror thread; confirmed `[PATCH v2]`, v2
change note, and `Reviewed-by` reply from Johannes Thumshirn.
- [Phase 4] Web searches found no usable stable-specific discussion;
direct lore stable fetch was blocked by Anubis.
- [Phase 5] `rg` and file reads traced callers from balance ioctl and
maintenance paths to `do_remap_reloc_trans()`.
- [Phase 5] Read `relocation.h`; confirmed remap-tree relocation
condition.
- [Phase 6] `git grep` on stable branches: function exists in
`stable/linux-7.0.y`; not found in checked `6.19.y`, `6.18.y`,
`6.12.y`, or `6.6.y`.
- [Phase 6] `git apply --check` of the candidate hunk succeeded against
current `stable/linux-7.0.y`.
- [Phase 6] `git log --grep` in `stable/linux-7.0.y` found no existing
candidate commit.
- UNVERIFIED: no runtime test, fstest, or reproducer was run.
- UNVERIFIED: direct canonical lore.kernel.org pages were blocked by
Anubis, so I used the available lore mirror and GitHub commit content.
The risk-benefit balance is clearly favorable for affected stable trees:
this is a small, reviewed, error-path-only Btrfs fix that prevents
potentially persistent filesystem metadata corruption.
**YES**
fs/btrfs/relocation.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 033f74fd6225c..2519cdb401eda 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -5031,21 +5031,27 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,
if (bg_needs_free_space) {
ret = btrfs_add_block_group_free_space(trans, dest_bg);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
goto fail;
+ }
}
ret = copy_remapped_data(fs_info, start, new_addr, length);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
goto fail;
+ }
ret = btrfs_remove_from_free_space_tree(trans, new_addr, length);
- if (ret)
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
goto fail;
+ }
ret = add_remap_entry(trans, path, src_bg, start, new_addr, length);
if (ret) {
- btrfs_add_to_free_space_tree(trans, new_addr, length);
+ btrfs_abort_transaction(trans, ret);
goto fail;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-05-05 9:53 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260505095149.512052-1-sashal@kernel.org>
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: handle -EAGAIN from btrfs_duplicate_item and refresh stale leaf pointer Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: replace ASSERT with proper error handling in stripe lookup fallback Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-5.10] btrfs: handle unexpected free-space-tree key types Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.6] btrfs: apply first key check for readahead when possible Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix wrong min_objectid in btrfs_previous_item() call Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: check return value of btrfs_partially_delete_raid_extent() Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: fix raid stripe search missing entries at leaf boundaries Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0-6.18] btrfs: copy devid in btrfs_partially_delete_raid_extent() Sasha Levin
2026-05-05 9:51 ` [PATCH AUTOSEL 7.0] btrfs: abort transaction in do_remap_reloc_trans() on failure Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox