Linux EXT4 FS development
 help / color / mirror / Atom feed
* [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:44 ` Sasha Levin
  2026-10-19 14:04   ` sashiko-bot
  2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh() Sasha Levin
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:44 UTC (permalink / raw)
  To: patches, stable
  Cc: Zhang Yi, Jan Kara, Theodore Ts'o, Sasha Levin, linux-ext4,
	linux-kernel

From: Zhang Yi <yi.zhang@huawei.com>

[ Upstream commit e1cf7b5f5c8ad1e00d00c50c61c3e8fdc79cd422 ]

ext4_load_tail_bh() returns a locked folio that callers immediately
mutate through folio_zero_range() and mark_buffer_dirty().  Use
FGP_WRITEBEGIN so that, on backing devices that require stable writes,
__filemap_get_folio() waits for writeback to finish before returning
the folio; on regular devices the wait is a no-op.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-2-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

I have enough to decide: this is a one-line stable-writes data-integrity
fix in a userspace-reachable ext4 tail-zeroing path, and the helper and
`FGP_WRITEBEGIN` both exist in this 7.3-rc4 tree.

===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================

**Step 1.1: PARSE THE SUBJECT LINE**

Record: **[ext4] [use] use FGP_WRITEBEGIN for tail block zeroing**

Subsystem prefix `ext4:`. Verb is “use” (correctness change of folio-get
flags, not a feature). Claimed intent: get the tail folio with the
write-begin flag set so writeback finishes before the folio is mutated.

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**

Verified from `git show e1cf7b5f5c8ad1e00d00c50c61c3e8fdc79cd422`:

- **Fixes:** none (expected for this review pipeline)
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** Jan Kara \<jack@suse.cz\> (ext4 co-maintainer)
- **Acked-by:** none
- **Link:** https://patch.msgid.link/20260714080044.4038124-2-
  yi.zhang@huaweicloud.com
- **Cc: stable:** none (expected; not a negative signal)
- **Signed-off-by:** Zhang Yi \<yi.zhang@huawei.com\> (author); Theodore
  Ts'o \<tytso@mit.edu\> (ext4 maintainer)

No syzbot, no kernel-test-robot, no multiple reporters.

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**

Record:

- **Bug:** `ext4_load_tail_bh()` returns a locked folio that callers
  immediately mutate with `folio_zero_range()` and
  `mark_buffer_dirty()`, without waiting for in-flight writeback.
- **Symptom/failure mode:** On backing devices that require stable
  writes, page-cache contents can change while DMA/writeback is in
  progress, which can corrupt the in-flight write or break integrity
  checksums. On ordinary devices the extra wait is a no-op.
- **Version information:** none in the message. History shows the helper
  landed in v7.1-rc1 and this fix in v7.3-rc1.
- **Root cause:** folio obtained with `FGP_LOCK | FGP_ACCESSED |
  FGP_CREAT` (no `FGP_STABLE` / `FGP_WRITE`).

**Step 1.4: DETECT HIDDEN BUG FIXES**

Record: **Yes, this is a real bug fix**, not cleanup. The cover letter
for the series (v4) states it explicitly: “Add patch 1 to use
FGP_WRITEBEGIN in ext4_load_tail_bh(), fixing a pre-existing stable-
writes bug exposed by patch 4's reordering.”

===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================

**Step 2.1: INVENTORY THE CHANGES**

Record:

- File: `fs/ext4/inode.c` — **1 insertion, 1 deletion**
- Function: `ext4_load_tail_bh()`
- Scope: **single-file surgical fix** (one flag expression)

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**

Record:

**Before:** `__filemap_get_folio(..., FGP_LOCK | FGP_ACCESSED |
FGP_CREAT, ...)`. Locks/creates the folio and marks it accessed. Does
**not** wait for writeback.

**After:** `__filemap_get_folio(..., FGP_WRITEBEGIN | FGP_ACCESSED,
...)`.

`FGP_WRITEBEGIN` is defined in `include/linux/pagemap.h` as:

`FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE`

Net additions: `FGP_WRITE` and `FGP_STABLE`. `FGP_STABLE` calls
`folio_wait_stable()` after the folio is locked (`mm/filemap.c`). That
waits for writeback only if `mapping_stable_writes()` is set.

Path affected: every caller of `ext4_load_tail_bh()` immediately zeros
the folio (`ext4_block_do_zero_range()`,
`ext4_block_journalled_zero_range()`). This is a **normal mutator
path**, not an error-only path.

**Step 2.3: IDENTIFY THE BUG MECHANISM**

Record:

- **Category:** memory-safety / data integrity (stable-pages race with
  writeback), plus a small GFP/idle-flag side effect from `FGP_WRITE`
- **Mechanism:** On `AS_STABLE_WRITES` mappings, in-flight writeback
  DMA’s from page cache. Zeroing the folio without `folio_wait_stable()`
  can mix old and new contents in the I/O. `FGP_WRITEBEGIN` is the
  established write-begin flag set that waits first.

**Step 2.4: ASSESS THE FIX QUALITY**

Record:

- **Quality:** obviously correct. Same flags every `->write_begin`
  implementation uses. `folio_wait_stable()` is a no-op when
  `mapping_stable_writes()` is false, so typical disks are unchanged.
- **Regression risk:** very low. Waiting while the folio is locked is
  the documented write-begin pattern (`folio_wait_stable` comment: if
  unlocked, writeback can restart). `FGP_ACCESSED | FGP_WRITEBEGIN`
  still takes the `FGP_ACCESSED` branch in `__filemap_get_folio()`, so
  idle-flag clearing does not change vs the old flags; `FGP_WRITE` only
  adds `__GFP_WRITE` on allocation.

===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================

**Step 3.1: BLAME THE CHANGED LINES**

Record:

- Current line is `e1cf7b5f5c8ad` (this commit).
- Same flags were already in `__ext4_block_zero_page_range()` before the
  helper was factored out (`3b312a6f510ca`, v7.1-rc1, “ext4: factor out
  journalled block zeroing range”).
- Folio conversion `9d3973de9a374` (“ext4: Convert
  __ext4_block_zero_page_range() to use a folio”, v6.4 era) replaced
  `find_or_create_page()` with `FGP_LOCK | FGP_ACCESSED | FGP_CREAT`.
  `find_or_create_page()` also did **not** wait for stable writeback, so
  the gap is older than the helper.
- Helper `ext4_load_tail_bh` first appeared in **v7.1-rc1**
  (`3b312a6f510ca`).

**Step 3.2: FOLLOW THE FIXES: TAG**

Record: **No Fixes: tag.** Not applicable. The immediate pre-image is
the helper as introduced in `3b312a6f510ca`, which copied the old flags.

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**

Record: This is **patch 1/9** of Zhang Yi’s series “ext4: fix unaligned
edge handling in FALLOC_FL_WRITE_ZEROES”, landed together around
2026-07-22:

1. `e1cf7b5f5c8ad` this commit
2. `2fff82f081401` skip tail zeroing for inline data
3. `705a3fd3bac16` check `ext4_get_block()` return
4. `b16e9d27a643a` move partial zeroing earlier in `ext4_zero_range()`
   (the reorder that **exposes** the stable-writes bug)
5–9. WRITE_ZEROES edge-handling / orphan-list work

This patch does **not** depend on 2–9. Later patches that increase tail-
zeroing (especially 4) depend on this one for correctness on stable-
write devices.

Related earlier commit `df0b5afc62f33` (“ext4: remove the redundant
folio_wait_stable()”) is a different path (`ext4_da_write_begin`); it
only shows that ext4 already treats `FGP_WRITEBEGIN` as implying the
stable wait.

**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**

Record: Zhang Yi is a regular, high-volume ext4 contributor (tail-
zeroing, WRITE_ZEROES, journal paths). This series was reviewed by Jan
Kara and applied by Ted Ts'o. Related commits in the same week are the
rest of the 1/9 series.

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**

Record:

- Prerequisite API: `FGP_WRITEBEGIN` from `e999a5c5a19cf` (“fs: Add
  FGP_WRITEBEGIN”), present since **v6.4-rc1**. Present in this tree.
- Prerequisite function: `ext4_load_tail_bh()` since **v7.1-rc1**.
  Present in this tree.
- **Can apply standalone:** yes. One flag change; no new helpers.

===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================

**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**

Record:

- `b4 dig -c e1cf7b5f5c8ad` → https://patch.msgid.link/20260714080044.40
  38124-2-yi.zhang@huaweicloud.com
- Series revisions: **v3** (2026-07-08) and **v4** (2026-07-14). Cover
  letter: v4 has **no code changes** vs v3; v2 **added this patch**.
- Cover letter quote (verified in saved mbox): “Add patch 1 to use
  FGP_WRITEBEGIN in ext4_load_tail_bh(), fixing a pre-existing stable-
  writes bug exposed by patch 4's reordering.”
- Ted Ts'o applied the series; patch 9 was dropped separately over
  error-handling concerns.
- No NAK on this patch. No reviewer asked for `Cc: stable` on patch 1
  (patches 7/8 in the same mbox do have `Cc: stable`, for WRITE_ZEROES-
  specific bugs).
- WebFetch of lore.kernel.org returned **403**; discussion recovered via
  `b4 dig -m /tmp/ext4-fgp.mbox`.

**Step 4.2: CHECK WHO REVIEWED THE PATCH**

`b4 dig -w` recipients included linux-ext4, linux-fsdevel, tytso,
adilger, Jan Kara, Ojaswin Mujoo, Ritesh Harjani, Huawei ext4
developers.

Record: **Jan Kara Reviewed-by** (in the patch); **Ted Ts'o** applied
it. Right maintainers were on the thread.

**Step 4.3: SEARCH FOR THE BUG REPORT**

Record: **No standalone bugzilla/syzbot report.** The bug was found
while reworking WRITE_ZEROES unaligned edges. Severity from the author:
pre-existing **stable-writes data-integrity** bug.

**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**

Record: Standalone as a fix. The rest of 1/9 is WRITE_ZEROES contract
work and two other pre-existing helper fixes (inline-data skip;
propagate `ext4_get_block()` errors). This commit does not require those
to be correct.

**Step 4.5: CHECK STABLE MAILING LIST HISTORY**

Record: lore.kernel.org/stable WebFetch returned **403**. No evidence in
the ext4 thread that this patch 1 was requested for stable or rejected
for stable. **UNVERIFIED** whether linux-stable@ discussed it.

===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================

**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**

Record: **`ext4_load_tail_bh()`** only.

**Step 5.2: TRACE CALLERS**

Verified in this tree:

- `ext4_block_do_zero_range()` → `folio_zero_range()` +
  `mark_buffer_dirty()`
- `ext4_block_journalled_zero_range()` → journal write access +
  `folio_zero_range()`
- Both from `ext4_block_zero_range()`
- That is used by:
  - `ext4_block_zero_eof()` — truncate (`ext4_truncate`), append
    (`ext4_write_checks` in `fs/ext4/file.c`), extent operations
    (`fs/ext4/extents.c`)
  - `ext4_zero_partial_blocks()` — punch hole / zero_range /
    WRITE_ZEROES (`ext4_punch_hole`, `ext4_zero_range`, extents
    WRITE_ZEROES)

Record: **Common filesystem operations**, process context, folio locked.
Not IRQ.

**Step 5.3: TRACE CALLEES**

Record: `__filemap_get_folio()` → on `FGP_STABLE`, `folio_wait_stable()`
→ `folio_wait_writeback()` if `mapping_stable_writes()`. Then
`create_empty_buffers` / `ext4_get_block` / `ext4_read_bh_lock` as
before.

**Step 5.4: FOLLOW THE CALL CHAIN**

Record: **Userspace-reachable** without privilege beyond write access to
an ext4 file: `truncate`,
`fallocate(PUNCH_HOLE|ZERO_RANGE|WRITE_ZEROES)`, append `write()`.
**HIGH** reachability.

**Step 5.5: SEARCH FOR SIMILAR PATTERNS**

Record: Other ext4 write paths already use `FGP_WRITEBEGIN`
(`fs/ext4/inline.c`, `fs/ext4/move_extent.c`) and/or explicit
`folio_wait_stable()` (`ext4_write_begin`, `ext4_page_mkwrite`). Tail-
block zeroing was the outlier.

===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================

**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**

Record:

- Local tree: **`git describe HEAD` = `v7.3-rc4-27-gf0100363d8c37`**,
  `VERSION=7 PATCHLEVEL=3 SUBLEVEL=0 EXTRAVERSION=-rc4`. Origin is
  torvalds/linux (mainline), detached HEAD.
- `ext4_load_tail_bh()` exists at `fs/ext4/inode.c` (currently already
  using `FGP_WRITEBEGIN | FGP_ACCESSED` because `e1cf7b5f5c8ad` **is an
  ancestor of HEAD**).
- Buggy pre-image (helper with `FGP_LOCK | FGP_ACCESSED | FGP_CREAT`)
  existed from **v7.1-rc1** (`3b312a6f510ca`) until this fix in
  **v7.3-rc1**.
- `FGP_WRITEBEGIN` exists here (`include/linux/pagemap.h:720`).

The pipeline instruction is to ignore “already selected” markers, not to
treat mainline already containing the original commit as a reason to
reject a backport-worthy fix. The code and prerequisites are in this
tree.

**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**

Record: **Clean apply** on this tree (one-line flag change;
`FGP_WRITEBEGIN` present). `git log --oneline -10 -- fs/ext4/inode.c`
shows normal ext4 churn; nothing that would conflict with this hunk.

**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**

Record: This exact change **is** HEAD’s current code (`git blame` on the
flags line is `e1cf7b5f5c8ad`). No alternate fix for the same stable-
writes hole in `ext4_load_tail_bh()`. Other `folio_wait_stable()` sites
in ext4 do not cover this helper.

===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================

**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**

Record: **Subsystem: fs/ext4. Criticality: IMPORTANT** (widely used
filesystem; data-integrity on stable-write devices). Not core mm/VFS,
but truncate/punch/zero are universal ext4 operations.

**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**

Record: **Actively developed** (WRITE_ZEROES series, iomap conversion,
journal/writeback fixes in 7.3). The helper itself is recent (v7.1) but
the missing stable wait is the same pattern as the older zero-page-range
code.

===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================

**Step 8.1: DETERMINE WHO IS AFFECTED**

Record: **ext4 users whose backing device requires stable writes**, i.e.
`bdev_stable_writes()`: integrity checksums (`CONFIG_BLK_DEV_INTEGRITY`)
**or** `BLK_FEAT_STABLE_WRITES`.

Verified setters of `BLK_FEAT_STABLE_WRITES` in this tree include NVMe
(when `data_digest` is enabled), RAID5 `skip_copy`, dm-integrity, zram,
RBD, iSCSI TCP, MMC, DRBD. Superblock then sets `SB_I_STABLE_WRITES` and
inode mappings get `AS_STABLE_WRITES`.

Not universal, but not a toy config: enterprise integrity, RAID, dm-
integrity, some NVMe.

**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**

Record:

- Trigger: tail/partial-block zeroing while that folio is under
  writeback.
- How common: truncate, punch, zero_range, append past EOF —
  **routine**. The race still needs concurrent writeback of that folio,
  so it is **timing-dependent**.
- Cover letter: patch 4’s reorder **widens** the window; the bug is
  still pre-existing without patch 4. This tree **already has patch 4**
  (`b16e9d27a643a`).
- Unprivileged users with write access **can** trigger the operations.

**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**

Record: **Failure mode: in-flight writeback sees torn folio contents /
integrity checksum mismatch.** **Severity: CRITICAL** (data corruption),
limited to stable-write devices. Not a panic path.

**Step 8.4: CALCULATE RISK-BENEFIT RATIO**

Record:

- **Benefit: high** for ext4 on stable-write devices (prevents silent
  data corruption on common ops). **Low** for everyone else (wait is a
  no-op).
- **Risk: very low** (1 line, standard flags, no API change, no new
  locking order).
- **Ratio: strongly favors applying.**

===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================

**Step 9.1: COMPILE THE EVIDENCE**

**FOR backporting:**

- Author and cover letter call it a **pre-existing stable-writes bug**.
- Mutating a folio under writeback on `AS_STABLE_WRITES` is a known
  class of **data corruption**.
- Reachable from truncate / fallocate / append.
- One-line, matches `FGP_WRITEBEGIN` used everywhere else.
- Reviewed by Jan Kara; applied by Ted Ts'o.
- `FGP_WRITEBEGIN` and `ext4_load_tail_bh()` both exist in this 7.3-rc4
  tree.
- This tree also has the later reorder (`b16e9d27a643a`) that
  **exposes** the race more.

**AGAINST backporting:**

- No Fixes tag, no user/syzbot report (not a valid NO by pipeline
  rules).
- Nested in a 9-patch WRITE_ZEROES series; later patches are feature-
  contract fixes. This patch is still self-contained.
- Author did not `Cc: stable` on patch 1 (other patches in the same
  series did).
- Bug existed in spirit since `find_or_create_page()`; field reports are
  absent, so the race may be rare without the v7.3 reorder.

**UNRESOLVED:**

- linux-stable@ archives could not be fetched (HTTP 403).
- Full v2 mailing-list review text for this hunk was not retrieved (lore
  403); Jan’s Reviewed-by on the committed patch is verified.

**Step 9.2: APPLY THE STABLE RULES CHECKLIST**

1. Obviously correct and tested? **PASS** — one flag change to the
   standard write-begin set; reviewed by Jan Kara; in mainline since
   v7.3-rc1.
2. Fixes a real bug that affects users? **PASS** — stable-writes devices
   (NVMe digest, RAID5 skip_copy, dm-integrity, zram, T10 PI, etc.).
3. Important issue? **PASS** — data corruption on in-flight writeback,
   not a crash, but explicitly in the stable rules list.
4. Small and contained? **PASS** — 1 line, one function.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — `FGP_WRITEBEGIN` and
   `ext4_load_tail_bh()` are here; the hunk is identical to what already
   landed.

**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**

Record: **None** (not a device ID, quirk, DT, build, or docs exception).
It qualifies as a normal data-integrity bug fix.

**Step 9.4: MAKE YOUR DECISION**

This tree is **Linux 7.3-rc4** (Linus mainline). The helper lives here,
`FGP_WRITEBEGIN` lives here, and callers still zero the folio
immediately. The change is a one-line restoration of the stable-write
wait that every other write-begin path already does. That is exactly the
kind of small, important data-integrity fix stable trees should take.
The surrounding WRITE_ZEROES series is not required for this hunk to be
correct.

### What the commit solves

`ext4_load_tail_bh()` was grabbing a locked folio without `FGP_STABLE`.
Callers then call `folio_zero_range()` and dirty the buffer. On devices
that set `AS_STABLE_WRITES` (integrity checksums or
`BLK_FEAT_STABLE_WRITES`), that can change page-cache bytes while
writeback DMA is still running. Switching to `FGP_WRITEBEGIN |
FGP_ACCESSED` waits for writeback first; elsewhere the wait is a no-op.

### Stable rules / risk vs benefit

Meets all six stable criteria. Benefit is preventing filesystem data
corruption on a real (if not universal) device class; risk is a single
established flag combination.

### Concerns

- Nested in a larger series, but this patch is standalone.
- No field report; the author found it while reordering zeroing. Still a
  concrete integrity bug, and this tree already contains the reorder
  that widens it.
- Lore stable-list search was blocked (403); that does not change the
  code-level conclusion.

Verification:
- [Phase 1] Parsed tags from `git show e1cf7b5f5c8ad`: Reviewed-by Jan
  Kara; Link msgid `...4038124-2...`; no Fixes/Reported-by/Cc:stable
- [Phase 1] Cover letter in `/tmp/ext4-fgp.mbox` msg 5: “pre-existing
  stable-writes bug exposed by patch 4's reordering”
- [Phase 2] Diff: 1 line in `ext4_load_tail_bh()`; flags
  `FGP_LOCK|FGP_ACCESSED|FGP_CREAT` → `FGP_WRITEBEGIN|FGP_ACCESSED`
- [Phase 2] `FGP_WRITEBEGIN` = `FGP_LOCK|FGP_WRITE|FGP_CREAT|FGP_STABLE`
  (`include/linux/pagemap.h:720`)
- [Phase 2] `__filemap_get_folio` calls `folio_wait_stable()` when
  `FGP_STABLE` (`mm/filemap.c:1986-1987`)
- [Phase 2] `folio_wait_stable()` only waits if
  `mapping_stable_writes()` (`mm/page-writeback.c:3105-3108`)
- [Phase 3] `git describe --contains --match 'v7.*' 3b312a6f510ca` →
  v7.1-rc1 (helper introduced)
- [Phase 3] `git describe --contains --match 'v7.*' e1cf7b5f5c8ad` →
  v7.3-rc1 (this fix)
- [Phase 3] `git merge-base --is-ancestor e1cf7b5f5c8ad HEAD` true;
  `3b312a6f510ca` also ancestor
- [Phase 3] `git show 9d3973de9a374`: folio conversion used the same
  non-stable flags; previously `find_or_create_page()`
- [Phase 3] `git show 3b312a6f510ca`: factor-out copied those flags into
  `ext4_load_tail_bh()`
- [Phase 4] `b4 dig -c e1cf7b5f5c8ad`: lore URL; v3 then v4; v4 no code
  change
- [Phase 4] `b4 dig -w`: linux-ext4, tytso, Jan Kara, adilger, Ojaswin,
  Ritesh on Cc
- [Phase 4] `b4 dig -m /tmp/ext4-fgp.mbox`: Ted applied 1–8; patch 9
  dropped; no NAK on patch 1
- [Phase 4] WebFetch lore.kernel.org 403 — UNVERIFIED stable-list
  discussion
- [Phase 5] Callers: `ext4_block_do_zero_range` /
  `ext4_block_journalled_zero_range` → `ext4_block_zero_range` →
  `ext4_block_zero_eof` / `ext4_zero_partial_blocks` (truncate, punch,
  zero_range, WRITE_ZEROES, append)
- [Phase 5] Other ext4 write paths already use `FGP_WRITEBEGIN` or
  `folio_wait_stable()`
- [Phase 6] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37; Makefile
  7.3.0-rc4
- [Phase 6] Current `fs/ext4/inode.c:4042-4043` already has
  `FGP_WRITEBEGIN | FGP_ACCESSED`
- [Phase 7] fs/ext4, important filesystem
- [Phase 8] `bdev_stable_writes()` = integrity csum OR
  `BLK_FEAT_STABLE_WRITES` (`include/linux/blkdev.h:1410-1414`)
- [Phase 8] `BLK_FEAT_STABLE_WRITES` set by nvme (data_digest), raid5
  skip_copy, dm-integrity, zram, rbd, iscsi_tcp, mmc, drbd
- [Phase 8] Failure: data corruption on stable-write devices; wait is
  no-op otherwise
- UNVERIFIED: linux-stable mailing list history (HTTP 403)
- UNVERIFIED: full v2 review mail body for this hunk (lore 403);
  Reviewed-by on the commit is verified

**YES**

 fs/ext4/inode.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2e3f7ba1a924b..c3fb5f16f6e39 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4092,7 +4092,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,
 	int err = 0;
 
 	folio = __filemap_get_folio(mapping, from >> PAGE_SHIFT,
-				    FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
+				    FGP_WRITEBEGIN | FGP_ACCESSED,
 				    mapping_gfp_constraint(mapping, ~__GFP_FS));
 	if (IS_ERR(folio))
 		return PTR_ERR(folio);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh()
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
  2026-10-19 13:44 ` [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing Sasha Levin
@ 2026-10-19 13:47 ` Sasha Levin
  2026-10-19 14:32   ` sashiko-bot
  2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info Sasha Levin
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:47 UTC (permalink / raw)
  To: patches, stable
  Cc: Zhang Yi, Jan Kara, Theodore Ts'o, Sasha Levin, linux-ext4,
	linux-kernel

From: Zhang Yi <yi.zhang@huawei.com>

[ Upstream commit 705a3fd3bac167f1dabe3d3bba46cd484c5528dd ]

ext4_load_tail_bh() ignores the return value of ext4_get_block(), so an
I/O or allocation failure is silently discarded. buffer_mapped(bh) stays
false and the function returns NULL, which callers such as
ext4_block_do_zero_range() treat as "nothing to do" and return success.
This can mask real failures during zero-range, truncate, or punch-hole
operations, potentially exposing stale data if the block was not
actually a hole and needed zeroing. So propagate the error to the
callers.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260714080044.4038124-4-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Local tree

This checkout is **v7.3-rc4** (`7.3.0-rc4`, HEAD `f0100363d8c37`).
`ext4_load_tail_bh()` exists here (since v7.1-rc1). The candidate
`705a3fd3bac16` is already an ancestor of HEAD (merged in v7.3-rc1). The
verdict is whether this fix belongs in **this** tree on technical merit,
not because it was already applied.

---

## Phase 1: Commit message forensics

**Step 1.1 — Subject**
- Record: **[ext4] [check] check return value of `ext4_get_block()` in
  `ext4_load_tail_bh()`**
- Verb “check” here means propagate a previously ignored error.

**Step 1.2 — Tags**
- Record:
  - `Signed-off-by: Zhang Yi <yi.zhang@huawei.com>` (author; ext4
    reviewer in MAINTAINERS)
  - `Reviewed-by: Jan Kara <jack@suse.cz>` (ext4 reviewer)
  - `Link: https://patch.msgid.link/20260714080044.4038124-4-
    yi.zhang@huaweicloud.com` (v4 3/9)
  - `Signed-off-by: Theodore Ts'o <tytso@mit.edu>` (ext4 maintainer)
  - No `Fixes:`, no `Cc: stable`, no `Reported-by`, no syzbot. Absence
    of those tags is expected for this review.

**Step 1.3 — Body**
- Record: **Bug:** `ext4_load_tail_bh()` ignores `ext4_get_block()`
  errors. On failure `buffer_mapped(bh)` stays false, the helper returns
  `NULL`, and callers such as `ext4_block_do_zero_range()` treat that as
  “hole / nothing to do” and return success.
- **Symptom:** Silent success of zero-range, truncate, or punch-hole
  while the tail block was not zeroed.
- **Failure mode:** Stale data can later be exposed if the block was not
  a hole.
- **Root cause:** Error conflated with “unmapped hole”.
- **No version range** in the message.

**Step 1.4 — Hidden bug fix?**
- Record: **Not hidden.** It is an explicit error-propagation / stale-
  data fix. Cover letter later confirms patches 2 and 3 were “pre-
  existing fixes … originally going to be sent separately,” then folded
  into the WRITE_ZEROES series.

---

## Phase 2: Diff analysis

**Step 2.1 — Inventory**
- Record: **One file**, `fs/ext4/inode.c`: **+3 / −1**. One function:
  `ext4_load_tail_bh()`. Surgical, single-file.

**Step 2.2 — Flow**
- Record: **Before:** unmapped bh → `ext4_get_block(..., create=0)`
  return ignored → if still unmapped, `goto unlock` with `err == 0` →
  `return NULL`.
- **After:** negative return sets `err` and `goto unlock` → existing
  `return err ? ERR_PTR(err) : NULL`.
- Path: mapping lookup on the tail block during partial-block zeroing
  (error path only).

**Step 2.3 — Bug mechanism**
- Record: **Logic / correctness (ignored error → false success).**
  Category closest to “return value checking / missing error handling.”
  Not UAF, leak, or race.
- Mechanism: I/O or allocation failure from `ext4_get_block()` is
  treated as a hole, so truncate/punch/zero-range skip tail zeroing and
  still succeed.

**Step 2.4 — Fix quality**
- Record: **Obviously correct.** Callers already do `IS_ERR_OR_NULL(bh)`
  / `PTR_ERR_OR_ZERO(bh)` (present since the helper was factored out).
  Unlock/put already runs on the `unlock` path. Regression risk is low
  **in this tree** because parent `2fff82f081401` skips inline-data EOF
  zeroing (otherwise append writes on inline files could see `-ERANGE`).
  No API change.

---

## Phase 3: Git history

**Step 3.1 — Blame**
- Record: Ignored `ext4_get_block()` call dates to **`d863dc3614e489`
  (2013, Lukas Czerner)** inside `__ext4_block_zero_page_range`. Helper
  **`ext4_load_tail_bh`** was factored out in **`3b312a6f510ca` (“ext4:
  factor out journalled block zeroing range”, Zhang Yi, 2026-03)** and
  kept the same ignored return. First in this lineage: **v7.1-rc1**.

**Step 3.2 — Fixes: tag**
- Record: **None.** Introducing commit for the helper is
  `3b312a6f510ca`, ancestor of this HEAD. The ignored-return bug is
  older than the helper.

**Step 3.3 — File history**
- Record: Same v4 series around this commit:
  1. `e1cf7b5f5c8ad` FGP_WRITEBEGIN
  2. `2fff82f081401` skip inline-data tail zeroing **(prerequisite)**
  3. **`705a3fd3bac16` this fix**
  4. `b16e9d27a643a` move partial zeroing earlier
  5. `012e6a2c9ff4d` comment-only return-semantics clarification
  6–9. WRITE_ZEROES edge handling (some of those have `Cc: stable`)
- This patch is **standalone** given (2). (5) is comments only; 6–9 are
  WRITE_ZEROES, not required for this error check.

**Step 3.4 — Author**
- Record: **Zhang Yi** is an ext4 **Reviewer** in MAINTAINERS; 178 ext4
  commits in this tree. Not a drive-by.

**Step 3.5 — Dependencies**
- Record: Needs `ext4_load_tail_bh()` + `ERR_PTR` return +
  `IS_ERR_OR_NULL` callers — all present since `3b312a6f510ca` (v7.1).
  Needs **`2fff82f081401`** so inline-data append does not start
  failing. Both are in this tree. **Applies standalone on top of that
  parent.**

---

## Phase 4: Mailing list

**Step 4.1 — Original discussion**
- Record: `b4 dig -c 705a3fd3bac16` → **https://patch.msgid.link/2026071
  4080044.4038124-4-yi.zhang@huaweicloud.com**
- Series: **[PATCH v4 0/9] ext4: fix unaligned edge handling in
  FALLOC_FL_WRITE_ZEROES**
- Revisions: v1 → v4. v4 vs v3: **no code change** on this patch; v3
  collected Jan’s R-b.
- Cover letter: patches 2 and 3 were **pre-existing fixes folded in**,
  not WRITE_ZEROES-only prep.
- No NAK found on this patch. Ted merged it.

**Step 4.2 — Recipients (`b4 dig -w`)**
- Record: `linux-ext4`, `linux-fsdevel`, **tytso@mit.edu**,
  **jack@suse.cz**, adilger, libaokun, ojaswin, ritesh.list —
  maintainers/reviewers were on Cc. Jan reviewed; Ted committed.

**Step 4.3 — Bug report**
- Record: **No external bugzilla/syzbot report.** Issue found by code
  inspection (author). Severity is argued in the commit: silent success
  + possible stale data.

**Step 4.4 — Series**
- Record: 9 patches. This one is independently useful. Sibling patches
  7–9 carry `Cc: stable` for WRITE_ZEROES; this one does not. That is
  **not** used as a NO vote (tags are expected to be absent here).

**Step 4.5 — stable@**
- Record: **UNVERIFIED.** lore.kernel.org WebFetch returned 403; no
  separate stable-thread confirmation. `b4 dig` matched the ext4 thread.

---

## Phase 5: Semantic / call graph

**Step 5.1 — Functions**
- Record: **`ext4_load_tail_bh`** only.

**Step 5.2 — Callers**
- Record (this tree):
  - `ext4_block_do_zero_range()` → `IS_ERR_OR_NULL` / `PTR_ERR_OR_ZERO`
  - `ext4_block_journalled_zero_range()` → same
  - via `ext4_block_zero_range()`:
    - `ext4_block_zero_eof()` — truncate (`ext4_truncate`), setattr
      grow, append (`ext4_write_checks` in `fs/ext4/file.c`)
    - `ext4_zero_partial_blocks()` — punch-hole (`ext4_punch_hole`),
      `ext4_zero_range()` / WRITE_ZEROES in `fs/ext4/extents.c`

**Step 5.3 — Callees**
- Record: `__filemap_get_folio`, `ext4_get_block` (lookup only),
  `ext4_read_bh_lock`, folio lock/put.

**Step 5.4 — Reachability**
- Record: **Yes, from userspace:** `truncate`/`ftruncate`, `fallocate`
  (punch/zero/WRITE_ZEROES), append `write`. Unprivileged processes on
  their own files can hit the path. The **error** itself needs
  `ext4_get_block()` failure (I/O error, ENOMEM, corruption), not a
  normal happy path.

**Step 5.5 — Similar patterns**
- Record: Same ignored return lived in `__ext4_block_zero_page_range`
  since 2013. No second copy of this exact bug in current
  `ext4_load_tail_bh`.

---

## Phase 6: This checkout

**Step 6.1 — Buggy code here?**
- Record: **Yes.** Helper is in `fs/ext4/inode.c` (~4033). Introduced
  **v7.1-rc1** (`3b312a6f510ca`). This 7.3-rc4 tree has that code. The
  ignored-return bug existed until `705a3fd3bac16` (v7.3-rc1).

**Step 6.2 — Backport difficulty**
- Record: **Clean apply** onto the parent in this tree
  (`2fff82f081401`). Three lines. Later `b4e409c18c797` removed fs-layer
  fscrypt decrypt from this function; that is after/around the same
  merge window and does not change the get_block check.

**Step 6.3 — Related fixes already here?**
- Record: Prerequisite `2fff82f081401` is in HEAD. Follow-up
  `012e6a2c9ff4d` is comments only. No competing alternate fix.

---

## Phase 7: Subsystem

**Step 7.1**
- Record: **ext4 (`fs/ext4`)** — **IMPORTANT** (default Linux
  filesystem; data integrity).

**Step 7.2**
- Record: **Active** in 7.3 (WRITE_ZEROES series, iomap, fastcommit,
  etc.). Helper itself is recent (7.1) but the ignored-return pattern is
  old.

---

## Phase 8: Impact and risk

**Step 8.1 — Who**
- Record: **Filesystem-specific:** ext4 users doing truncate, punch-
  hole, zero-range, append, WRITE_ZEROES.

**Step 8.2 — Trigger**
- Record: Partial-block zeroing **plus** `ext4_get_block()` failure.
  Uncommon (I/O error / ENOMEM / bad metadata). Unprivileged users can
  invoke the operations; they cannot usually force get_block failure
  except under memory/IO pressure.

**Step 8.3 — Failure mode**
- Record: **Stale data / false success** on truncate/punch/zero-range.
  Not a panic. **Severity: HIGH** for a filesystem (classic “truncate
  succeeded but tail not zeroed → later extend exposes old data”). Not
  CRITICAL (no oops/deadlock).

**Step 8.4 — Ratio**
- Record: **Benefit: high** for ext4 data integrity on error paths.
  **Risk: very low** (3 lines, existing ERR_PTR path, Jan + Ted).
  Prerequisite for inline data is already in this tree.

---

## Phase 9: Synthesis

**Step 9.1 — Evidence**

**For:**
- Real correctness bug: mapping lookup failure reported as success.
- Concrete data-integrity outcome on truncate/punch/zero-range.
- Userspace-reachable (common ext4 ops).
- 3-line, obviously correct; callers already handle `ERR_PTR`.
- Reviewed by Jan Kara, merged by Ted Ts'o; author is an ext4 reviewer.
- Cover letter: intended as a standalone pre-existing fix.
- Buggy helper **is in this 7.3 tree** (since 7.1).
- Prerequisite inline-data skip **is in this tree**.

**Against:**
- Error-path only; no syzbot/user `Reported-by`.
- Bundled in a 9-patch WRITE_ZEROES series (mitigated: explicitly called
  out as a separate pre-existing fix).
- Trigger requires get_block failure (rare).

**Unresolved:** stable@ archive (lore 403); full v1 review text beyond
the on-commit `Reviewed-by`.

**Step 9.2 — Stable rules**
1. Obviously correct and tested? **PASS** (trivial check; R-b Jan; in
   7.3-rc1)
2. Real bug affecting users? **PASS** (false success + possible stale
   data)
3. Important (crash/security/corruption/deadlock)? **PASS** (stale data
   / integrity, HIGH)
4. Small and contained? **PASS** (+3/−1, one function)
5. No new features/APIs? **PASS**
6. Can apply to this tree? **PASS** (helper + callers + prerequisite
   present)

**Step 9.3 — Exceptions**
- Record: **None** (not a device ID/quirk/DT/build/doc exception).
  Ordinary bugfix.

**Step 9.4 — Decision**
This is a small, reviewed ext4 integrity fix for code that exists in
this 7.3-rc4 tree. Callers already propagate `ERR_PTR`. The inline-data
prerequisite is present, so the change does not turn append-on-inline-
data into `-ERANGE`. It meets stable criteria for **this** tree.

---

## Why it matters here

On this 7.3 tree, `ext4_load_tail_bh()` is the shared tail-zero helper
for truncate, punch-hole, fallocate zero/WRITE_ZEROES, and post-EOF
append. Ignoring `ext4_get_block()` makes a failed extent lookup look
like a hole, so those operations can succeed without zeroing a mapped
tail. Later grow/read can then expose stale bytes. Checking the return
and using the existing `ERR_PTR` path is the right, minimal fix.

Risk is low: three lines, no locking/API change, prerequisite
`2fff82f081401` already in this checkout.

---

## Verification

- **[Phase 1]** Parsed commit
  `705a3fd3bac167f1dabe3d3bba46cd484c5528dd`: Zhang Yi, R-b Jan Kara,
  SOB Ted Ts'o, Link msgid `…4038124-4…`. No Fixes/Cc:stable/Reported-
  by.
- **[Phase 2]** `git show 705a3fd3bac16`: +3/−1 in `ext4_load_tail_bh`;
  `err = ext4_get_block(...); if (err < 0) goto unlock`.
- **[Phase 2]** Confirmed unlock already returns `err ? ERR_PTR(err) :
  NULL` before the patch (`git show 705a3fd3bac16^:fs/ext4/inode.c`).
- **[Phase 2]** Callers at the fix: `IS_ERR_OR_NULL` / `PTR_ERR_OR_ZERO`
  (`git grep` on `705a3fd3bac16`).
- **[Phase 3]** `git blame 705a3fd3bac16^` around the call:
  `d863dc3614e489` (2013).
- **[Phase 3]** `git log -S ext4_load_tail_bh -- fs/ext4/inode.c` →
  `3b312a6f510ca`; `git describe --contains` → **v7.1-rc1**.
- **[Phase 3]** `git merge-base --is-ancestor 3b312a6f510ca HEAD` true;
  `705a3fd3bac16` ancestor of HEAD true; **not** in v7.2; **in**
  v7.3-rc1.
- **[Phase 3]** Parent `2fff82f081401` documents `-ERANGE` on inline
  data if this check is added without the skip; that skip is in HEAD.
- **[Phase 4]** `b4 dig -c 705a3fd3bac16` → v4 3/9 lore URL; `-a` showed
  v3 and v4; `-w` listed ext4 maintainers.
- **[Phase 4]** Cover letter (mbox): “Fold in two pre-existing fixes
  (now patches 2 and 3)”.
- **[Phase 4]** WebFetch lore/msgid.link: **403**. Stable-list search:
  **UNVERIFIED**.
- **[Phase 5]** Grep callers: `ext4_block_do_zero_range`,
  `ext4_block_journalled_zero_range` → `ext4_block_zero_eof` /
  `ext4_zero_partial_blocks` → truncate, setattr, punch-hole,
  zero_range, `file.c` append.
- **[Phase 5]** Truncate: `ext4_truncate` → `ext4_block_zero_eof`; on
  error `goto out_trace` (does **not** keep shrinking after a failed
  zero). Punch-hole/`ext4_zero_range` return the error.
- **[Phase 6]** `git describe HEAD` = `v7.3-rc4-27-gf0100363d8c37`;
  `make kernelversion` = `7.3.0-rc4`.
- **[Phase 6]** Buggy helper present in this tree since v7.1;
  prerequisite and this commit both ancestors of HEAD.
- **[Phase 7]** MAINTAINERS: Zhang Yi is `R:` on EXT4; Jan Kara is `R:`;
  Ted is `M:`.
- **[Phase 8]** Failure mode verified from commit text + truncate/punch
  callers, not from a live repro (no reproducer in the message).
- **UNVERIFIED:** Whether `ext4_get_block` can return an error while
  leaving `BH_Mapped` set (fix still correct: any `err < 0` is
  propagated). No live I/O-error repro.

The patch is a small, reviewed ext4 integrity fix for code that exists
in this 7.3 tree, with callers already wired for `ERR_PTR` and the
inline-data prerequisite present.

**YES**

 fs/ext4/inode.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9a5c08650bd1e..2e3f7ba1a924b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4119,7 +4119,9 @@ static int __ext4_block_zero_page_range(handle_t *handle,
 	}
 	if (!buffer_mapped(bh)) {
 		BUFFER_TRACE(bh, "unmapped");
-		ext4_get_block(inode, iblock, bh, 0);
+		err = ext4_get_block(inode, iblock, bh, 0);
+		if (err < 0)
+			goto unlock;
 		/* unmapped? It's a hole - nothing to do */
 		if (!buffer_mapped(bh)) {
 			BUFFER_TRACE(bh, "still unmapped");
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
  2026-10-19 13:44 ` [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing Sasha Levin
  2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh() Sasha Levin
@ 2026-10-19 13:49 ` Sasha Levin
  2026-10-19 14:53   ` sashiko-bot
  2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode Sasha Levin
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:49 UTC (permalink / raw)
  To: patches, stable
  Cc: Junzhe Yu, Theodore Ts'o, Sasha Levin, linux-ext4,
	linux-kernel

From: Junzhe Yu <junzheyu1@gmail.com>

[ Upstream commit 8f3901fbb40745046e513226ad84e8b84492632d ]

Resend: previous attempt was rejected by vger for containing HTML.

==================================================================

ext4_mark_group_bitmap_corrupted() already treats a NULL return from
ext4_get_group_info() as "nothing to do", but ext4_get_group_info()
indexes s_group_info without checking whether the array exists.

During mount, fast-commit replay runs inside jbd2_journal_load() from
ext4_load_and_init_journal(), which is before ext4_mb_init() allocates
s_group_info. Replaying an FC UNLINK for an inode whose bitmap bit is
already clear takes:

   ext4_fc_replay_unlink -> iput -> ext4_evict_inode -> ext4_free_inode
     -> ext4_mark_group_bitmap_corrupted -> ext4_get_group_info

and faults on the NULL s_group_info base. Userspace only mounts a dirty
ext4 image; this is a supported recovery path.

Return NULL when s_group_info (or the per-block grp_info row) is unset
so the existing caller check is effective during early mount.

Tested on Linux v6.6.145 KASAN: crafted FC-unlink image previously
triggered KASAN null-ptr-deref / panic in ext4_get_group_info; with this
patch, mount succeeds (EXT4 "bit already cleared" may still log). Also
observed on v6.6.144; still present on torvalds/linux as of
f5098b6bae76 (2026-07-26).

A self-contained Docker/QEMU reproducer (craft + mount + patch verify) is
available on request.

Signed-off-by: Yu Junzhe <junzheyu1@gmail.com>
Link: https://patch.msgid.link/65c955b0-716b-4599-b925-59c2782e38b4@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Phase 1: Commit message forensics

**Step 1.1 — Subject**
Record: **[ext4] [guard / prevent] NULL `s_group_info` dereference in
`ext4_get_group_info`**. “Guard against” is a bug-fix verb: add a
missing safety check.

**Step 1.2 — Tags**
Record:
- `Signed-off-by: Yu Junzhe <junzheyu1@gmail.com>` (author)
- `Link: https://patch.msgid.link/65c955b0-716b-4599-b925-
  59c2782e38b4@gmail.com`
- `Signed-off-by: Theodore Ts'o <tytso@mit.edu>` (ext4 maintainer
  applied it)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
  by:`, or `Cc: stable` (absence is expected in this pipeline)
- Upstream SHA after maintainer application:
  `8f3901fbb40745046e513226ad84e8b84492632d`

**Step 1.3 — Body**
Record:
- **Bug:** `ext4_get_group_info()` indexes `s_group_info` without
  checking that the array exists.
- **Symptom:** KASAN null-ptr-deref / panic in `ext4_get_group_info`
  while mounting a dirty ext4 image that needs fast-commit UNLINK
  replay.
- **Path:** `ext4_fc_replay_unlink` → `iput` → `ext4_evict_inode` →
  `ext4_free_inode` → `ext4_mark_group_bitmap_corrupted` →
  `ext4_get_group_info`
- **Root cause:** FC replay runs inside `jbd2_journal_load()` from
  `ext4_load_and_init_journal()`, **before** `ext4_mb_init()` allocates
  `s_group_info`.
- **Author testing:** KASAN on v6.6.145 (also seen on v6.6.144); still
  present on torvalds/linux as of `f5098b6bae76` (2026-07-26). Mount
  succeeds with the patch.

**Step 1.4 — Hidden bug fix?**
Record: Not hidden. This is an explicit NULL-deref fix. The “already-
cleared bitmap bit” path looks like a recovery edge case, but it is a
real oops on a supported mount/recovery path.

## Phase 2: Diff analysis

**Step 2.1 — Inventory**
Record:
- File: `fs/ext4/balloc.c` only (`+4 / -0`)
- Function: `ext4_get_group_info()`
- Scope: **single-file surgical fix**

**Step 2.2 — Code flow**
Record (verified against local `fs/ext4/balloc.c`):

Before:
```
if (group >= s_groups_count) return NULL;
indexv/indexh = ...
grp_info = sbi_array_rcu_deref(..., s_group_info, indexv);  //
NULL[index] if array missing
return grp_info[indexh];
```

After:
```
if (group >= s_groups_count) return NULL;
if (!s_group_info) return NULL;          // new
... deref row ...
if (!grp_info) return NULL;              // new
return grp_info[indexh];
```

This is an early-mount / missing-table path, not a new feature path.

**Step 2.3 — Bug mechanism**
Record: **NULL pointer dereference (memory safety)**.
`sbi_array_rcu_deref()` does
`rcu_dereference(sbi->s_group_info)[index]`. `sbi` is `kzalloc`’d, so
`s_group_info` is NULL until `ext4_mb_alloc_groupinfo()` /
`rcu_assign_pointer`. The per-row check covers `ext4_mb_add_groupinfo()`
error paths that set `group_info[idx] = NULL`.

**Step 2.4 — Fix quality**
Record: Obviously correct. Matches the existing contract
(`ext4_get_group_info()` may return NULL;
`ext4_mark_group_bitmap_corrupted()` already does `if (!grp || !gdp)
return;`). Four `unlikely()` lines, no API/lock/data-structure change.
Regression risk is very low: after `ext4_mb_init()`, `s_group_info` is
non-NULL and these checks are no-ops. Returning NULL instead of oopsing
cannot be worse for callers that already handle NULL.

## Phase 3: Git history

**Step 3.1 — Blame**
Record: Current function body in this tree is from the 6.4-era change
“allow `ext4_get_group_info()` to fail” (this history: `b4319e457d6e3`;
mainline `5354b2af34064`, 2023-05-13) plus `fa285d799d1d5` (“drop
`ext4_error()` from `ext4_get_group_info()`”). Those commits taught the
helper to return NULL for a bad group number and taught callers to check
NULL — but they never checked the array pointer itself.

**Step 3.2 — Fixes: tag**
Record: None. Reachability comes from fast-commit replay, added in
`6866d7b3f2bb4` (“ext4 / jbd2: add fast commit initialization”,
`tags/v5.10-rc1~59^2~7`). Journal load still runs before
`ext4_mb_init()` in this tree.

**Step 3.3 — File history**
Record: Recent `fs/ext4/balloc.c` commits here are unrelated
(capability-check reorder, fault-injection race, kunit stubs). No
prerequisite series. Standalone 1/1 patch.

**Step 3.4 — Author**
Record: Yu Junzhe is not the ext4 maintainer. Theodore Ts’o applied it
by hand after noting mangled whitespace, then posted “Applied, thanks!”
with commit `8f3901fbb407`.

**Step 3.5 — Dependencies**
Record: None. The helper, `s_group_info`, FC replay, and the caller NULL
check all exist in this checkout. Applies standalone.

## Phase 4: Mailing list / external

**Step 4.1 — Original discussion**
Record:
- Lore/msgid: https://patch.msgid.link/65c955b0-716b-4599-b925-
  59c2782e38b4@gmail.com
- Direct lore WebFetch: **403** (could not read lore HTML)
- Openwall/LKML mirrors and `b4` succeeded
- `b4 dig -a`: **v1 only** (no v2/v3)
- Thread: author submission; tytso note about gmail whitespace (still
  applied); tytso “Applied, thanks!” — **no NAK**
- No reviewer `Cc: stable` in the thread (tytso also did not add it when
  committing)

**Step 4.2 — Recipients (`b4 dig -w`)**
Record: Junzhe Yu, Theodore Ts’o, Andreas Dilger, linux-ext4, linux-
kernel. Both ext4 maintainers were on the original To/Cc.

**Step 4.3 — Bug report**
Record: No syzbot/bugzilla link. Author reports KASAN on a crafted FC-
unlink image and offers a Docker/QEMU reproducer. I did not run that
reproducer (UNVERIFIED empirically; the code path is verified).

**Step 4.4 — Series**
Record: Standalone `[PATCH]` 1/1. Related-in-time FC-replay crashes
(writeback rwsem not initialized, RO mount replay) are separate bugs,
not prerequisites.

**Step 4.5 — Stable list**
Record: lore.kernel.org/stable WebFetch returned **403**. No stable-list
discussion found via search. No evidence it was rejected for stable.

## Phase 5: Semantic / call-chain analysis

**Step 5.1 — Functions**
Record: `ext4_get_group_info()` only. (No semcode MCP in this
environment; used `git grep` + reads.)

**Step 5.2 — Callers**
Record: Many, across `fs/ext4/{balloc,ialloc,mballoc,super}.c`. Almost
all already handle NULL (`if (!grp)` / `if (!grinfo)`), because of the
6.4 “allow to fail” work. The crashing caller is
`ext4_mark_group_bitmap_corrupted()` in `fs/ext4/super.c`, which already
returns on NULL.

**Step 5.3 — Callees**
Record: `sbi_array_rcu_deref()` →
`rcu_dereference(s_group_info)[indexv]`. That is the NULL deref.

**Step 5.4 — Reachability**
Record: User-reachable: mount an ext4 filesystem with a journal that
still has fast-commit UNLINK tags, when the inode bitmap bit is already
clear. `ext4_fc_init()` installs `j_fc_replay_callback` even if fast
commit is currently off, so leftover FC blocks still replay. Mount of a
dirty ext4 image is a normal recovery path (crash, unclean unmount, or
an untrusted image). Typically needs mount privilege, but the failure is
a **kernel oops**, not a userspace error.

Verified mount order in this tree (`fs/ext4/super.c`):
1. `ext4_load_and_init_journal()` → `ext4_load_journal()` →
   `jbd2_journal_load()` (FC replay)
2. much later: `ext4_mb_init()` (allocates `s_group_info`)

Verified free path: `ext4_free_inode()` skips the group-info corruption
check under `EXT4_FC_REPLAY`, then on `!cleared` still calls
`ext4_error` + `ext4_mark_group_bitmap_corrupted()`.

**Step 5.5 — Similar patterns**
Record: `ext4_count_free_clusters()` already does `if
(EXT4_SB(sb)->s_group_info)` before calling `ext4_get_group_info()`.
Bitmap validators skip work under `EXT4_FC_REPLAY`. The hole is
specifically the helper used by `ext4_mark_group_bitmap_corrupted()`.

## Phase 6: This checkout (6.12.y)

**Step 6.1 — Does the buggy code exist here?**
Record: **Yes.** Local tree is **6.12.111** (`pending-6.12`; `git
describe` was `p-6.12-3-g88406e77611c6` at start).
`ext4_get_group_info()` in `fs/ext4/balloc.c` still has only the
`s_groups_count` check. `git merge-base --is-ancestor 8f3901fbb407 HEAD`
→ **not an ancestor**. `git grep` for the new `!s_group_info` guard →
**not present**. Fast commit and the journal-before-mballoc order
**are** present.

**Step 6.2 — Backport difficulty**
Record: **Clean apply.** Local function text matches the upstream hunk
context exactly. Confirmed by reading the function and by comparing to
`git show 8f3901fbb407`.

**Step 6.3 — Related fixes already here?**
Record: The “allow to fail” / drop-`ext4_error` work is here
(`b4319e457d6e3`, `fa285d799d1d5`). That is why the caller already
treats NULL as success-noop — and why this four-line guard is
sufficient. No alternate fix for this crash is in the tree.
`origin/master` has `8f3901fbb407` as the latest `balloc.c` change; no
follow-up revert/amend on that function.

## Phase 7: Subsystem context

**Step 7.1**
Record: **ext4 (fs/ext4). Criticality: IMPORTANT** (default Linux
filesystem; not quite mm/VFS core, but production-critical).

**Step 7.2**
Record: Actively maintained (tytso/Dilger, linux-ext4). The hole is old
(FC since 5.10 + helper NULL contract since 6.4), not a brand-new
subsystem.

## Phase 8: Impact and risk

**Step 8.1 — Who is affected**
Record: Anyone mounting an ext4 filesystem that still has fast-commit
journal data to replay (crash recovery, or a crafted/dirty image). That
is a large, real population — not an obscure driver.

**Step 8.2 — Trigger**
Record: Mount-time FC UNLINK replay when the inode bitmap bit is already
clear. Not every boot, but a **supported recovery path**. Unprivileged
users cannot usually mount; a user who can mount a malicious ext4 image
(containers, loop, removable media with automount) can panic the kernel.

**Step 8.3 — Failure mode**
Record: **NULL deref → KASAN report / oops / panic during mount.**
Severity: **CRITICAL** (host crash while recovering a dirty filesystem).

**Step 8.4 — Risk/benefit**
Record: **Benefit: high** (prevents oops on ext4 recovery). **Risk: very
low** (4 lines, existing NULL contract, hot path unchanged after
`ext4_mb_init()`). Ratio strongly favors backport.

Note: `ext4_error("bit already cleared...")` can still log or remount-ro
depending on `errors=`; the author states mount succeeds with this
patch. That `ext4_error` is pre-existing, not introduced here.

## Phase 9: Synthesis

**Step 9.1 — Evidence**

FOR:
- Real NULL deref on a supported ext4 mount/recovery path
- KASAN-confirmed; author tested the patch
- Call path and journal-before-`mb_init` order verified in **this** 6.12
  tree
- 4-line, obviously correct guard; callers already handle NULL
- Ext4 maintainer applied it upstream (`8f3901fbb407`); it is on
  `origin/master`
- No dependencies; applies cleanly
- Ext4 is widely used; FC exists since 5.10

AGAINST:
- No `Fixes:` / `Cc: stable` (expected; not a negative)
- Trigger is an FC replay edge (already-cleared bit), not every mount
- I did not run the author’s QEMU reproducer
- tytso did not nominate stable in the apply mail

UNRESOLVED:
- Empirical reproducer not run here
- lore.kernel.org HTML and stable-list search returned HTTP 403 (thread
  recovered via b4/openwall)

**Step 9.2 — Stable rules**
1. Obviously correct and tested? **PASS** (KASAN + maintainer apply;
   logic matches existing NULL contract)
2. Real bug affecting users? **PASS** (oops on dirty-ext4 mount / FC
   replay)
3. Important (crash/security/corruption/deadlock)? **PASS** — kernel
   oops/panic, severity CRITICAL
4. Small and contained? **PASS** — +4 lines, one function
5. No new features/APIs? **PASS**
6. Can apply to this tree? **PASS** — buggy code present, clean context

**Step 9.3 — Exceptions**
Record: Not an ID/quirk/DT/docs exception. It is a normal crash fix.

**Step 9.4 — Decision**
This tree is 6.12.y. The bug exists here; the fix is a four-line NULL
guard with no prerequisites. It should be backported.

---

### What this solves for stable users

Mounting a dirty ext4 filesystem with leftover fast-commit UNLINK
records can take `ext4_free_inode()` →
`ext4_mark_group_bitmap_corrupted()` **before** mballoc has allocated
`s_group_info`. The helper then does `NULL[index]` and oopses. The patch
makes the helper return NULL so the existing caller check is a no-op and
mount/recovery can continue.

### Risk vs benefit

Benefit is a real mount-time crash fix on the default Linux filesystem.
Risk is a pair of `unlikely()` NULL returns in a helper that is already
allowed to fail. After `ext4_mb_init()`, behavior is unchanged.

### Concerns

None that block backport. No missing commits, no API change, no follow-
up on `origin/master` that reworks this function.

---

Verification:
- [Phase 1] Parsed subject/tags/body from the candidate message and from
  `git show 8f3901fbb407`
- [Phase 1] Confirmed no Fixes/Cc:stable; maintainer SOB present
- [Phase 2] Diff is +4 lines in `ext4_get_group_info()`; local function
  matches the hunk
- [Phase 2] `sbi_array_rcu_deref` indexes `s_group_info` without a NULL
  check (`fs/ext4/ext4.h`)
- [Phase 2] `ext4_mark_group_bitmap_corrupted()` already returns if
  `!grp` (`fs/ext4/super.c`)
- [Phase 3] Blame: helper NULL-for-bad-group from `b4319e457d6e3` /
  `fa285d799d1d5` in this history
- [Phase 3] Fast commit added in `6866d7b3f2bb4` (v5.10-rc1); present
  here
- [Phase 3] `git log --grep` on `fs/ext4/`: this subject is **not** in
  HEAD
- [Phase 4] `b4 am` / `b4 dig -c 8f3901fbb407`: thread at msgid
  `65c955b0-716b-4599-b925-59c2782e38b4@gmail.com`; v1 only
- [Phase 4] `b4 dig -w`: tytso + Dilger + linux-ext4 on the original
  mail
- [Phase 4] tytso applied as `8f3901fbb407`; noted whitespace but no NAK
- [Phase 4] lore.kernel.org WebFetch: 403; used openwall + b4 mbox
  instead
- [Phase 5] Callers of `ext4_get_group_info` grepped; crashing caller
  checks NULL
- [Phase 5] `ext4_free_inode()` FC_REPLAY skip + “bit already cleared” →
  `ext4_mark_group_bitmap_corrupted()` verified
- [Phase 5] Mount order: `jbd2_journal_load` in `ext4_load_journal()`
  before `ext4_mb_init()` verified
- [Phase 5] `sbi = kzalloc` zeroes `s_group_info`; assigned later via
  `rcu_assign_pointer` in mballoc
- [Phase 6] `make kernelversion` / Makefile: **6.12.111**; branch
  `pending-6.12`
- [Phase 6] `git merge-base --is-ancestor 8f3901fbb407 HEAD` → not in
  this tree
- [Phase 6] Same SHA **is** an ancestor of `origin/master`; no later
  balloc.c follow-up on that fix
- [Phase 6] Clean apply context present in local `ext4_get_group_info()`
- [Phase 8] Failure mode: NULL deref oops on mount/recovery, severity
  CRITICAL
- UNVERIFIED: Did not run the author’s crafted-image/QEMU reproducer
- UNVERIFIED: Could not search lore.kernel.org/stable HTML (HTTP 403)

**YES**

 fs/ext4/balloc.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index c9329ed5c094e..08556dd45760d 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -331,9 +331,13 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
 
 	if (unlikely(group >= EXT4_SB(sb)->s_groups_count))
 		return NULL;
+	if (unlikely(!EXT4_SB(sb)->s_group_info))
+		return NULL;
 	indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
 	indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
 	grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
+	if (unlikely(!grp_info))
+		return NULL;
 	return grp_info[indexh];
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
                   ` (2 preceding siblings ...)
  2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info Sasha Levin
@ 2026-10-19 13:50 ` Sasha Levin
  2026-10-19 14:55   ` sashiko-bot
  2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned Sasha Levin
  2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit Sasha Levin
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:50 UTC (permalink / raw)
  To: patches, stable
  Cc: Yun Zhou, Jan Kara, Theodore Ts'o, Sasha Levin, linux-ext4,
	linux-kernel

From: Yun Zhou <yun.zhou@windriver.com>

[ Upstream commit 2c0e4fb511f97467dafc91b6afb3414100289081 ]

An inode being evicted will never need its extra isize expanded.  Set
EXT4_STATE_NO_EXPAND before ext4_mark_inode_dirty() in ext4_evict_inode()
to make this explicit and prevent any unnecessary work in
ext4_try_to_expand_extra_isize().

This also provides defense-in-depth for the s_writepages_rwsem deadlock
during mount-time orphan cleanup, ensuring the expand path is blocked
for inodes under eviction regardless of how they are reached.

Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260623061903.2148767-2-yun.zhou@windriver.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

I have the series context, Jan Kara’s review, and the syzbot stack.
Compiling the nine-phase analysis and the backport verdict for this
tree.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: PARSE THE SUBJECT LINE**

Record: **[ext4] [set] set EXT4_STATE_NO_EXPAND in ext4_evict_inode**

- Subsystem: `ext4`
- Action verb: **set** (the body also uses “prevent” and “ensuring … is
  blocked”)
- Claimed intent: mark an inode under eviction so extra-isize expansion
  is skipped

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**

Record:
- **Reviewed-by:** Jan Kara `<jack@suse.cz>` (ext4 reviewer / long-time
  maintainer)
- **Link:** `https://patch.msgid.link/20260623061903.2148767-2-
  yun.zhou@windriver.com` (patch **2/2**)
- **Signed-off-by:** Yun Zhou `<yun.zhou@windriver.com>` (author)
- **Signed-off-by:** Theodore Ts'o `<tytso@mit.edu>` (ext4 maintainer;
  merged)
- **No Fixes:** tag on the committed version (expected for this review
  pipeline)
- **No Cc: stable** (expected)
- **No Reported-by / Closes** on this revision (those tags live on patch
  1/2)

Notable: this is explicitly patch **2/2** of a two-patch series.

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**

Record:
- **Bug description:** An evicted inode never needs extra isize
  expanded. Doing that work is unnecessary and can participate in the
  `s_writepages_rwsem` deadlock during mount-time orphan cleanup.
- **Symptom/failure mode:** Circular lock dependency / deadlock
  (`s_writepages_rwsem` → jbd2 handle → `xattr_sem` →
  `s_writepages_rwsem`).
- **Version information:** none in this commit; sibling patch 1/2 has
  `Fixes: c8585c6fcaf2` (v4.7-rc1).
- **Author’s root-cause framing:** skip expansion by setting
  `EXT4_STATE_NO_EXPAND` before `ext4_mark_inode_dirty()` in
  `ext4_evict_inode()`. Described as making the invariant explicit
  **and** as defense-in-depth for the mount-time orphan deadlock.

**Step 1.4: DETECT HIDDEN BUG FIXES**

Record: **Yes — this is a hidden/downplayed deadlock-path fix, not mere
cleanup.**

The committed text says “unnecessary work” and “defense-in-depth”. The
**v1** of this exact one-line change was titled *“skip extra isize
expansion on inode eviction to avoid deadlock”*, carried the syzbot
`Reported-by`/`Closes`/`Fixes:` tags, and the syzbot stack is
`ext4_orphan_cleanup` → `evict` → **`ext4_evict_inode`** →
`__ext4_mark_inode_dirty` → `ext4_try_to_expand_extra_isize`. The tags
moved to patch 1/2 (`!SB_ACTIVE`) after Jan Kara asked for the real
lock-order fix; this line remained as the eviction-path closer.

---

## PHASE 2: DIFF ANALYSIS - LINE BY LINE

**Step 2.1: INVENTORY THE CHANGES**

Record:
- **Files:** `fs/ext4/inode.c` — **+1 / −0**
- **Function:** `ext4_evict_inode()`
- **Scope:** single-file, one-line surgical change

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**

Record:
- **Before:** deletion path sets `i_size = 0`, then calls
  `ext4_mark_inode_dirty()`. That calls `__ext4_mark_inode_dirty()` → if
  `i_extra_isize < s_want_extra_isize`,
  `ext4_try_to_expand_extra_isize()`, which may take `xattr_sem`, move
  xattrs, and `iput()` EA inodes.
- **After:** `ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND)` runs
  first. `ext4_try_to_expand_extra_isize()` already returns `-EOVERFLOW`
  when that flag is set (check present since 2017), so expansion is
  skipped for this and later `ext4_mark_inode_dirty()` calls in the same
  eviction.
- **Path:** deletion path only (after the `i_nlink` / `is_bad_inode`
  early outs; not the cache-drop `no_delete` path).

**Step 2.3: IDENTIFY THE BUG MECHANISM**

Record:
- **Category:** deadlock / lock-ordering (plus skipping pointless
  expansion that can `iput` EA inodes under a jbd2 handle).
- **Mechanism:** mount-time orphan cleanup (`!SB_ACTIVE`) of a deleted
  inode (`i_nlink == 0`) hits `ext4_evict_inode` → expand extra isize →
  `ext4_xattr_block_set` → `iput(ea_inode)` → `write_inode_now()` →
  `s_writepages_rwsem`, while a jbd2 handle and `xattr_sem` are held.
  Setting `EXT4_STATE_NO_EXPAND` removes that edge for every inode under
  eviction.

**Step 2.4: ASSESS THE FIX QUALITY**

Record:
- **Quality:** obviously correct. An inode being deleted cannot benefit
  from extra isize. The flag’s save/restore in `ext4_write_lock_xattr` /
  `ext4_write_unlock_xattr` keeps it set (`*save == 1` → do not clear).
- **Regression risk:** very low. One inode-state bit on an inode that is
  about to be freed. No API, locking, or on-disk format change.
- **Red flags:** none (1 line, one function). It is patch 2/2 but does
  **not** depend on patch 1’s `!SB_ACTIVE` check.

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: BLAME THE CHANGED LINES**

Record:
- Added line: commit **`2c0e4fb511f97`** (this change, 2026-06-23).
- Surrounding `inode->i_size = 0` / `ext4_mark_inode_dirty()`: Dave
  Kleikamp 2006 / Ted Ts’o **`bc965ab3f2b4b7`** (2008). Extra-isize
  expansion from dirtying: **`6dd4ee7cab7e3`** (2007).
  `EXT4_STATE_NO_EXPAND` early-out in `ext4_try_to_expand_extra_isize`:
  **`cf0a5e818fe216`** (2017, from **`2e81a4eeedcaa`** in 2016).
- This path has been in-tree for many years; not a newly introduced
  subsystem.

**Step 3.2: FOLLOW THE FIXES: TAG**

Record: **No Fixes: tag on this commit.** Sibling **`7461c60b9c6a8`**
(patch 1/2, parent of this commit) has `Fixes: c8585c6fcaf2` (“ext4: fix
races between changing inode journal mode and ext4_writepages”,
2016-04-25, **v4.7-rc1**). That commit is an ancestor of this tree. It
introduced `s_writepages_rwsem` (originally `s_journal_flag_rwsem`),
which is the lock in the cycle.

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**

Record:
- **`7461c60b9c6a8`** — skip expansion when `!SB_ACTIVE` (primary mount-
  time fix).
- **`2c0e4fb511f97`** — this commit (eviction-path flag).
- **`4f48af3dc7554` / `a54778243e88f`** — later deferred `iput` for EA
  inodes (Jan Kara’s deeper lock-order fix; larger).
- This change is **standalone**: it only uses `ext4_set_inode_state()`
  and a flag check that has existed since 2017. It is part of a series
  but is not patch-X-that-needs-Y to compile or run.

**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**

Record: Yun Zhou is a regular ext4 contributor (orphan/xattr/deadlock
work in this area), not the maintainer. Ted Ts’o merged it; Jan Kara
reviewed it. Related author commits: the `!SB_ACTIVE` skip, then
deferred EA `iput` helpers.

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**

Record: **No hard prerequisites beyond code that is already old.** Needs
`EXT4_STATE_NO_EXPAND` and the test at the top of
`ext4_try_to_expand_extra_isize()` (2016–2017). Does **not** need patch
1. Applies as a single insertion before the existing
`ext4_mark_inode_dirty()` call.

---

## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH

**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**

Record:
- **b4 dig:** `[PATCH 2/2] ext4: set EXT4_STATE_NO_EXPAND in
  ext4_evict_inode` — `https://patch.msgid.link/20260623061903.2148767-
  2-yun.zhou@windriver.com`
- **Revisions:** evolved from standalone v1 (2026-06-11) through v5–v8
  of a larger xattr-iput series, then a simplified 2-patch series that
  Ted applied. Applied version is that final 2/2.
- **v6/v8 cover letter (author):** “Patch 2 is a belt-and-suspenders
  semantic improvement: an inode under eviction never needs extra isize
  expansion.” “v1 … Only fixes the syzbot reproducer, not the underlying
  lock ordering violation.”
- **Jan Kara (2026-06-11) on the original identical change:** agrees
  expansion is pointless in `ext4_evict_inode`; says it **does not fix
  the real lock-order bug**, only the particular syzbot reproducer. No
  NAK of this line; he wanted a deeper fix as well.
- **No NAK** of setting the flag. Ted merged it with Jan’s Reviewed-by.

**Step 4.2: CHECK WHO REVIEWED THE PATCH**

Record (b4 dig -w): `tytso@mit.edu`, `adilger.kernel@dilger.ca`,
`libaokun@linux.alibaba.com`, `jack@suse.cz`, `ojaswin@linux.ibm.com`,
`ritesh.list@gmail.com`, `yi.zhang@huawei.com`, `linux-
ext4@vger.kernel.org`. Subsystem maintainers/reviewers were on To/Cc.
Jan Kara reviewed; Ted merged.

**Step 4.3: SEARCH FOR THE BUG REPORT**

Record:
- Syzbot: `https://syzkaller.appspot.com/bug?extid=5d19358d7eb30ffb0cc5`
  — **possible deadlock in wait_transaction_locked**, prio:high, C
  repro, Denial-of-service via filesystem mount.
- Stack (verified): `ext4_orphan_cleanup` → `evict` →
  **`ext4_evict_inode`** → `__ext4_mark_inode_dirty` →
  `ext4_try_to_expand_extra_isize` → `ext4_expand_extra_isize_ea` →
  `ext4_xattr_block_set` → `iput` → `write_inode_now` →
  `ext4_writepages` / `s_writepages_rwsem`.
- Still reported on linux-5.15 / 6.1 / 6.6 at the time of the dashboard
  snapshot. Syzbot’s “fix commit” is **`7461c60b9c6a`** (patch 1),
  because that commit carries the tags; this commit closes the **same**
  `ext4_evict_inode` frame.

**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**

Record: Series is (1) skip expansion during mount, (2) this flag in
evict, then later deferred-iput patches. Patch 1 covers all `!SB_ACTIVE`
callers (including `ext4_process_orphan` → `ext4_truncate`). Patch 2
covers **all** eviction, including post-mount. They complement; this one
is not incomplete on its own for the syzbot stack.

**Step 4.5: CHECK STABLE MAILING LIST HISTORY**

Record: No stable-list thread found for this subject. Absence of Cc:
stable is expected for this pipeline.

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**

Record: **`ext4_evict_inode()`** (modified). Indirectly
**`__ext4_mark_inode_dirty()`**, **`ext4_try_to_expand_extra_isize()`**.

**Step 5.2: TRACE CALLERS**

Record:
- `ext4_evict_inode` is `ext4_sops.evict_inode` (`fs/ext4/super.c`).
  Called from VFS `evict()` on last `iput` when `i_nlink == 0`.
- Reachable from unlink/close, and from **`ext4_process_orphan()` →
  `iput()`** during `ext4_orphan_cleanup()` at mount
  (`fs/ext4/orphan.c`). That is the syzbot path.

**Step 5.3: TRACE CALLEES**

Record: After the new flag: `ext4_mark_inode_dirty` →
`__ext4_mark_inode_dirty` → `ext4_try_to_expand_extra_isize` (now a no-
op via `-EOVERFLOW`) → later `ext4_truncate`, `ext4_xattr_delete_inode`,
`ext4_free_inode`. No new callees.

**Step 5.4: FOLLOW THE CALL CHAIN**

Record: **Yes, userspace-reachable.** Unprivileged unlink hits eviction
(no deadlock there once `SB_ACTIVE` is set). The deadlock needs mount-
time orphan cleanup (`!SB_ACTIVE`), typically `mount(2)` (admin /
crafted image). Syzbot reproduced it. Assessment: DoS, filesystem
trigger.

**Step 5.5: SEARCH FOR SIMILAR PATTERNS**

Record: Only this site sets `EXT4_STATE_NO_EXPAND` outside the xattr
lock helpers. No sibling-driver clone. Patch 1 is the related early-
return in `ext4_try_to_expand_extra_isize`.

---

## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE

**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**

Record:
- Local tree: **`v7.3-rc4-27-gf0100363d8c37`**, `make kernelversion` =
  **7.3.0-rc4** (mainline, not a `*.y` stable branch).
- `ext4_evict_inode` + `ext4_mark_inode_dirty` + expand-on-dirty all
  exist.
- This commit **is already an ancestor** of HEAD (`2c0e4fb511f97`). That
  is expected (source tree), not a reason to treat it as “already
  selected for stable”.
- Bug class dates to extra-isize expansion (2007) plus
  `s_writepages_rwsem` (2016 / v4.7).

**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**

Record: **Clean apply.** Insert one call between long-stable
`inode->i_size = 0` and `ext4_mark_inode_dirty()`. No refactor of that
sequence. `EXT4_STATE_NO_EXPAND` exists here.

**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**

Record: Patch 1 (`7461c60b9c6a8`) and later deferred-iput work are also
in this mainline checkout. They do not make this line wrong or redundant
for stable: patch 1 is mount-only; this flag also covers post-mount
eviction and is the direct closer of the syzbot `ext4_evict_inode`
frame.

---

## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT

**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**

Record: **ext4 (`fs/ext4/`)** — **IMPORTANT** (default filesystem on a
large fraction of Linux systems; mount/orphan cleanup is a common path
after crash).

**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**

Record: Actively developed (recent writeback, xattr, orphan, deadlock
fixes). The eviction dirtying sequence itself has been stable for many
years; this is a small invariant on old code, not a feature on new code.

---

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1: DETERMINE WHO IS AFFECTED**

Record: **Filesystem-specific (ext4), but a very large user
population.** Triggered on mount of a filesystem with orphans that still
need extra-isize expansion and have xattrs that must move.

**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**

Record:
- **Deadlock:** mount-time orphan cleanup, inode with `i_extra_isize <
  s_want_extra_isize`, expansion moves xattrs, `!SB_ACTIVE` forces
  `write_inode_now` on EA `iput`. Syzbot has a C repro.
- **Post-mount:** every deletion of such an inode would previously
  attempt a pointless expand (not this deadlock).
- **Unprivileged mount:** generally no; crafted/unclean ext4 images and
  admin mount yes. Syzbot still reached it from syscall fuzzing.

**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**

Record: **Deadlock / lockdep circular dependency → hang or lockdep
splat. Severity: HIGH (DoS on mount/orphan cleanup).** Not a data-
corruption bug.

**Step 8.4: CALCULATE RISK-BENEFIT RATIO**

Record:
- **Benefit:** high for a 1-line closer of a documented, syzbot-
  reproduced deadlock path on ext4 eviction; also stops pointless expand
  (xattr shuffle / EA `iput`) on every delete.
- **Risk:** very low (1 line, existing flag, deletion-only).
- **Ratio:** strongly favorable.

---

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: COMPILE THE EVIDENCE**

**FOR backporting:**
- Syzbot C-repro deadlock; stack is exactly `ext4_evict_inode` → mark
  dirty → expand extra isize.
- 1-line, obviously correct; Jan Kara Reviewed-by; Ted Ts’o merged.
- Uses a flag and check that have existed since 2016–2017; no new API.
- Independent of patch 1; complements the `!SB_ACTIVE` skip.
- Defense-in-depth on a HIGH-severity hang in a core filesystem.
- Applies cleanly to this tree’s `ext4_evict_inode`.

**AGAINST:**
- Final message frames it as “unnecessary work” / “defense-in-depth”;
  author called v1 incomplete vs the real lock-order bug.
- Patch 2/2; the tagged “real” mount fix is patch 1.
- Jan Kara: this line alone does not fix `ext4_xattr_block_set` taking
  `s_writepages_rwsem` under a handle.
- Deadlock is mount-time / orphan-specific, not every unlink.

**UNRESOLVED:** lore.kernel.org returned 403 to WebFetch; discussion
recovered via b4 dig, openwall/lkml mirrors, patchew, and the syzbot
dashboard. No stable@ thread found.

**Step 9.2: APPLY THE STABLE RULES CHECKLIST**

1. Obviously correct and tested? **PASS** — 1-line invariant; Reviewed-
   by Jan Kara; in mainline; syzbot exercised the path.
2. Fixes a real bug that affects users? **PASS** — same path as the
   syzbot deadlock; also skips harmful extra work on delete.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
   deadlock / DoS (HIGH), not theoretical.
4. Small and contained? **PASS** — +1 line, one function.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — call site and
   `EXT4_STATE_NO_EXPAND` are present; insertion is mechanical.

**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**

Record: Not a device-ID/quirk/DT/docs/build exception. It is a normal
small correctness/deadlock-path fix.

**Step 9.4: MAKE YOUR DECISION**

This tree is **7.3-rc4 mainline**. The eviction dirtying path exists;
the extra-isize expand-on-dirty path exists; the syzbot stack is this
function. The committed wording is modest, but the change is the direct
closer of a real, reproduced deadlock edge, not a refactor or a new
feature. Risk is negligible. It should be backported.

---

### What the commit solves for stable users

On ext4, `ext4_mark_inode_dirty()` may try to grow `i_extra_isize`.
During **mount-time orphan cleanup**, that runs from
**`ext4_evict_inode`** while `!SB_ACTIVE`. Expanding can move xattrs and
`iput()` EA inodes, which then calls `write_inode_now()` and takes
`s_writepages_rwsem` under a jbd2 handle and `xattr_sem`. Syzbot
reproduced that cycle. Setting `EXT4_STATE_NO_EXPAND` before the dirty
call is correct (the inode is being deleted) and stops that expand/iput
edge for every eviction.

### Stable rules / risk

Meets all six criteria: one line, reviewed, real deadlock path, no new
API, applies cleanly. Sibling patch 1 (`!SB_ACTIVE`) is the broader
mount fix; this line does not need it, and it still helps post-mount by
skipping pointless expansion.

### Concerns

Incomplete as the *only* lock-order fix (Jan Kara). That is a reason to
also want patch 1 / deferred iput, not a reason to drop this 1-liner. No
backport rework needed on this tree.

---

Verification:
- [Phase 1] Subject/tags: ext4 set NO_EXPAND; Reviewed-by Jan Kara; Link
  patch 2/2; Ted Ts’o SOB; no Fixes/Reported-by on this revision
- [Phase 1] Body: skip expand on evict; defense-in-depth for
  s_writepages_rwsem deadlock
- [Phase 2] Diff: +1 line in `ext4_evict_inode` before
  `ext4_mark_inode_dirty`
- [Phase 2] Expand skip: `ext4_try_to_expand_extra_isize` returns
  `-EOVERFLOW` if `EXT4_STATE_NO_EXPAND` (inode.c:6597)
- [Phase 2] Flag restore: `ext4_write_unlock_xattr` clears only if
  `*save == 0` (xattr.h:166-170)
- [Phase 3] `git describe HEAD`: v7.3-rc4-27-gf0100363d8c37; `make
  kernelversion`: 7.3.0-rc4
- [Phase 3] `git merge-base --is-ancestor 2c0e4fb511f97 HEAD`: yes
  (mainline already has it)
- [Phase 3] Blame: `i_size=0` 2006; `mark_inode_dirty` in evict
  `bc965ab3f2b4b7` 2008; expand-on-dirty `6dd4ee7cab7e3` 2007; NO_EXPAND
  check `cf0a5e818fe216` 2017
- [Phase 3] Sibling 7461c60b9c6a8 Fixes: c8585c6fcaf2 (v4.7-rc1);
  `merge-base --is-ancestor c8585c6fcaf2 HEAD`: yes
- [Phase 4] `b4 dig -c 2c0e4fb511f97`: msgid 20260623061903.2148767-2
- [Phase 4] `b4 dig -a`: v5–v8 larger series then final 2-patch series
- [Phase 4] `b4 dig -w`: tytso, adilger, jack@suse.cz, linux-ext4 on
  To/Cc
- [Phase 4] Jan Kara 2026-06-11 (openwall/lkml): agrees with the flag;
  says it only covers the syzbot reproducer, not the full lock-order bug
  — no NAK
- [Phase 4] Cover letter: “belt-and-suspenders semantic improvement”
- [Phase 4] Syzbot bug extid=5d19358d7eb30ffb0cc5: stack through
  `ext4_evict_inode`; prio high; C repro; linux-5.15/6.1/6.6 still
  listed
- [Phase 4] lore.kernel.org WebFetch: 403; used b4 + mirrors. Stable
  list search: no hits
- [Phase 5] Caller: `ext4_sops.evict_inode`; orphan:
  `ext4_process_orphan` → `iput` (orphan.c:359)
- [Phase 6] Local `ext4_evict_inode` already contains the line at
  inode.c:268; apply would be clean on the pre-patch form of the same
  function
- [Phase 7] ext4, IMPORTANT, actively developed
- [Phase 8] Failure: circular lockdep / deadlock on mount orphan
  cleanup; severity HIGH; risk very low
- UNVERIFIED: live lore.kernel.org HTML of the thread (403);
  reconstructed from b4, openwall, patchew, syzbot

**YES**

 fs/ext4/inode.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index bbc437be5e63b..9a5c08650bd1e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -261,6 +261,7 @@ void ext4_evict_inode(struct inode *inode)
 	if (ext4_inode_is_fast_symlink(inode))
 		memset(EXT4_I(inode)->i_data, 0, sizeof(EXT4_I(inode)->i_data));
 	inode->i_size = 0;
+	ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
 	err = ext4_mark_inode_dirty(handle, inode);
 	if (err) {
 		ext4_warning(inode->i_sb,
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
                   ` (3 preceding siblings ...)
  2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
  2026-10-19 15:06   ` sashiko-bot
  2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit Sasha Levin
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
  To: patches, stable
  Cc: Baokun Li, Theodore Ts'o, Sashiko, Jan Kara, Zhang Yi,
	Sasha Levin, linux-ext4, linux-kernel

From: Baokun Li <libaokun@linux.alibaba.com>

[ Upstream commit d42dc7726a003262b73ffef2b744ff57a5488799 ]

The block and inode bitmap checksums are computed over a whole number of
bytes: ext4_inode_bitmap_csum_*() use EXT4_INODES_PER_GROUP(sb) >> 3 and
ext4_block_bitmap_csum_*() use EXT4_CLUSTERS_PER_GROUP(sb) / 8 as the
length passed to ext4_chksum().

If s_inodes_per_group or s_clusters_per_group is not a multiple of 8, the
trailing fractional bits are excluded from the checksum.  Those bits are
then unprotected, and any incremental csum update path that assumes a
byte-aligned bitmap can compute a checksum inconsistent with the full
recalculation, corrupting the on-disk bitmap checksum.

Reject such filesystems at mount time by adding the missing " & 7"
alignment checks alongside the existing range validation.

Suggested-by: Theodore Ts'o <tytso@mit.edu>
Link: https://patch.msgid.link/h3n7jlfhyna64dn5o76qxcspnhxdddcs6crpxftmy7gnl7b3sx@jenszfpcsnit
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260508121539.4174601-1-libaokun%40linux.alibaba.com?part=10
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20260608111150.827117-2-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

This is a small ext4 mount-time geometry check. Local tree is
**7.3.0-rc4** (`v7.3-rc4-27-gf0100363d8c37`). The candidate is
`d42dc7726a003`. The checksum path still uses byte-truncated lengths, so
the bug this closes is real in this tree.

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1: PARSE THE SUBJECT LINE**

Record: **[ext4] [reject] reject mount if clusters/inodes per group are
not 8-aligned**

Subsystem `ext4`. Verb `reject` is a defensive mount-time check, not a
feature or refactor.

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**

Record:
- **Suggested-by:** Theodore Ts'o `<tytso@mit.edu>` (ext4 maintainer)
- **Link:** `https://patch.msgid.link/h3n7jlfhyna64dn5o76qxcspnhxdddcs6c
  rpxftmy7gnl7b3sx@jenszfpcsnit` (Ted’s suggestion)
- **Reported-by:** Sashiko `<sashiko-bot@kernel.org>` (static-analysis
  bot, not syzbot)
- **Closes:** sashiko.dev URL pointing at RFC series part 10
- **Signed-off-by:** Baokun Li `<libaokun@linux.alibaba.com>` (author)
- **Reviewed-by:** Jan Kara `<jack@suse.cz>` (ext4 co-maintainer)
- **Reviewed-by:** Zhang Yi `<yi.zhang@huawei.com>`
- **Link:** `https://patch.msgid.link/20260608111150.827117-2-
  libaokun@linux.alibaba.com` (v2 1/3)
- **Signed-off-by:** Theodore Ts'o `<tytso@mit.edu>` (applied)
- **No Fixes:** tag (expected)
- **No Cc: stable** (expected)
- Ignore pipeline markers: none of `[Upstream commit]` / Sasha Levin SOB
  on this commit

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**

Record:
- **Bug:** inode/block bitmap checksums hash a whole number of bytes
  (`EXT4_INODES_PER_GROUP >> 3`, `EXT4_CLUSTERS_PER_GROUP / 8`). If
  those counts are not multiples of 8, the last 1–7 bits are omitted
  from the CRC.
- **Symptom:** those bits are unprotected; an incremental CRC path that
  assumes byte alignment can disagree with a full recalculation and
  write a bad on-disk bitmap checksum.
- **Version info:** none in the message.
- **Root cause (author):** missing `& 7` checks next to the existing
  range checks in `ext4_handle_clustersize()` /
  `ext4_block_group_meta_init()`.

**Step 1.4: DETECT HIDDEN BUG FIXES**

Record: **Not hidden.** Explicit mount rejection for invalid superblock
geometry. Cover letter (`[PATCH v2 0/3]`) states the series prevents
crafted images from causing bitmap checksum corruption, integer
overflow, or OOB inode-table access. This patch is the
checksum/alignment piece.

---

## PHASE 2: DIFF ANALYSIS

**Step 2.1: INVENTORY THE CHANGES**

Record:
- **File:** `fs/ext4/super.c` only (`+6 / -4`)
- **Functions:** `ext4_handle_clustersize()`,
  `ext4_block_group_meta_init()`
- **Scope:** single-file surgical fix, two existing `if` conditions

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**

Record:
- **Hunk 1 (`ext4_handle_clustersize`):** previously rejected only
  `s_clusters_per_group > blocksize * 8`. After: also reject
  `s_clusters_per_group & 7`. Error text becomes `"invalid #clusters per
  group"`.
- **Hunk 2 (`ext4_block_group_meta_init`):** previously rejected inodes-
  per-group outside `[inodes_per_block, blocksize*8]`. After: also
  reject `s_inodes_per_group & 7`. Trailing `\n` in the format string
  dropped.
- **Path:** mount / `__ext4_fill_super()` only. Legitimate 8-aligned
  filesystems are unchanged.

**Step 2.3: IDENTIFY THE BUG MECHANISM**

Record: **[Logic / correctness + metadata integrity]**

Verified in `fs/ext4/bitmap.c`:

```31:31:fs/ext4/bitmap.c
        sz = EXT4_INODES_PER_GROUP(sb) >> 3;
```

```68:68:fs/ext4/bitmap.c
        int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8;
```

Set and verify use the same truncated length, so kernel-internal CRC is
consistent. Trailing bits are still live inode/cluster bits
(`ext4_set_bit` in alloc/free) but are **not** covered by
`metadata_csum`. `ialloc.c` zeros with `(EXT4_INODES_PER_GROUP(sb) + 7)
/ 8` (round up) while CRC uses `>> 3` (round down).

The “incremental csum update” failure mode is what Sashiko flagged in
**unmerged** RFC helper `ext4_inode_bitmap_csum_set_fast()`.
`crc32c_flip_range` is **not** in this tree. The gap that **is** in this
tree is unprotected trailing bitmap bits plus disagreement with any tool
that hashes a different length.

**Step 2.4: ASSESS THE FIX QUALITY**

Record:
- **Quality:** obviously correct. `& 7` matches the CRC byte length.
  Same style as the existing upper-bound checks.
- **Regression risk:** only rejects non-8-aligned geometries. Ted
  documented that old Android `make_ext4fs` could emit those; he also
  said that was fixed more than a decade ago and those devices should be
  gone. Follow-up `a34de48f329b2` only adds another conjunct on the same
  `if`; it does not revert this check.

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1: BLAME THE CHANGED LINES**

Record:
- Cluster range check introduced in `40da553f5da02` (“ext4: verify
  s_clusters_per_group even without bigalloc”, 2024-03-07, Jan Kara).
- Inode range check lived in this helper since `107d2be90116a` (2023
  factor-out); the `blocksize * 8` bound is older (`c8267c51425ab` moved
  a local).
- Bitmap CRC with `/ 8` / `>> 3` dates to `41a246d1ff75a` /
  `fa77dcfafeaa6` (2012, metadata_csum).
- Alignment checks themselves are `d42dc7726a003` (this commit).

**Step 3.2: FOLLOW THE FIXES: TAG**

Record: **No Fixes: tag.** Buggy assumption is as old as metadata_csum
(2012), not a recent regression.

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**

Record:
- Same series, independent patches:
  - `d42dc7726a003` — this commit (v2 1/3)
  - `afa3caf2fbc41` — max cluster size (v2 2/3)
  - `a34de48f329b2` — inodes_per_group % inodes_per_block (v2 3/3)
- Cover letter: patches 2 and 3 are “independent of Patch 1”.
- This patch does not need 2/3.

**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**

Record: Baokun Li is a regular ext4 contributor (many DIO/DAX and
validation patches). Not the maintainer; Ted applied it. Jan Kara and
Zhang Yi reviewed.

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**

Record: **Standalone.** Touches existing `if`s in helpers that exist
here (`ext4_handle_clustersize` at `super.c:4461`,
`ext4_block_group_meta_init` at `super.c:5294`). No new helpers, no
incremental CRC.

`git merge-base --is-ancestor d42dc7726a003 HEAD` → **yes** (exit 0).
Already in this checkout via `ext4_for_linus-7.3-rc1`.

---

## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH

**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**

Record:
- **b4 dig -c d42dc7726a003:** `https://patch.msgid.link/20260608111150.
  827117-2-libaokun@linux.alibaba.com`
- **Revisions:**
  - v1 RFC: part of 17-patch incremental CRC series (`lib/crc: add
    crc32c_flip_range()`), 2026-05-08
  - v2: `[PATCH v2 0/3] ext4: tighten mount-time superblock geometry
    validation`, 2026-06-08 (this is what landed)
- v2 vs v1 for **this** patch: only dropped a spurious `\n` in the error
  format.
- **Reviews:** Zhang Yi “Looks good”; Jan Kara “Looks good”; Ted
  “Applied, thanks!” with the three SHAs.
- **No NAKs.** No reviewer asked for `Cc: stable`.
- lore.kernel.org HTTP **403**; thread recovered via `b4 dig -m`.

**Step 4.2: CHECK WHO REVIEWED THE PATCH**

Record (**b4 dig -w**): linux-ext4, Ted Ts'o, Andreas Dilger, Jan Kara,
Zhang Yi, Ojaswin Mujoo, Ritesh, Sashiko. Subsystem maintainers were on
To/Cc. Jan Kara and Zhang Yi reviewed this patch; Ted applied it.

**Step 4.3: SEARCH FOR THE BUG REPORT**

Record: Sashiko High finding on RFC 10/17
`ext4_inode_bitmap_csum_set_fast()`: incremental CRC would corrupt the
checksum if `INODES_PER_GROUP` is not a multiple of 8.

Ted’s reply (verified from mbox
`h3n7jlfhyna64dn5o76qxcspnhxdddcs6crpxftmy7gnl7b3sx@jenszfpcsnit`):

- Kernel historically **did not** enforce 8-alignment because old
  Android `make_ext4fs` (MIT, pre-e2fsprogs) sometimes created non-
  multiples of 8.
- That hit e2fsck ([sourceforge e2fsprogs bug
  292](https://sourceforge.net/p/e2fsprogs/bugs/292/)).
- “Fixed long ago (over a decade ago)… any such mobile handsets are in
  the landfill, so we probably should fix this by adding a check in
  ext4_fill_super().”

So this is maintainer-directed policy: stop mounting geometries e2fsck
already treats as invalid.

**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**

Record: v2 is three independent mount checks. Incremental CRC RFC was
**not** merged (`crc32c_flip_range` absent). This patch does not pull in
that series.

**Step 4.5: CHECK STABLE MAILING LIST HISTORY**

Record: **UNVERIFIED** — lore.kernel.org/stable returned 403. No stable
discussion in the ext4 mbox.

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1: IDENTIFY KEY FUNCTIONS**

Record: `ext4_handle_clustersize`, `ext4_block_group_meta_init`.
Supporting: `ext4_inode_bitmap_csum_{set,verify}`,
`ext4_block_bitmap_csum_{set,verify}`.

**Step 5.2: TRACE CALLERS**

Record: both are called only from `__ext4_fill_super()` (`super.c:5443`
and `5451`). Mount path, not hot I/O. Reaching the bug is “mount this
filesystem” (loop, USB, etc.).

**Step 5.3: TRACE CALLEES**

Record: read superblock fields, `ext4_msg`, `return -EINVAL`. No alloc,
no new locks.

**Step 5.4: FOLLOW THE CALL CHAIN**

Record: `mount` / `fsopen` → `ext4_fill_super` → these checks.
Unprivileged users can hit it with a crafted image on a loop device if
they can mount (or via automount). **Userspace-reachable.**

**Step 5.5: SEARCH FOR SIMILAR PATTERNS**

Record: same file already rejects other invalid geometry (blocks vs
clusters, inodes_per_block). Series patch 3 adds `% inodes_per_block` on
the same inode `if`. `ext4_count_free()` debug paths also use `/ 8`, so
free-count vs last bits can disagree on unaligned groups.

---

## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE

**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**

Record: **Yes.** This tree is **7.3.0-rc4**. `bitmap.c` still uses `>>
3` and `/ 8`. The alignment checks are already present at
`super.c:4494-4498` and `5327-5333` because `d42dc7726a003` is an
ancestor of HEAD. The bug the commit addresses (CRC length vs bit count)
is inherent in that checksum code, which has been here since
metadata_csum.

**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**

Record: **Clean apply on this tree** — already applied; helpers and
surrounding checks match the diff. (Older stables that still have these
checks inline in `ext4_fill_super` would need context adjustment; that
is **not** this checkout.)

**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**

Record: this exact fix is in the tree. No alternate fix. `a34de48f329b2`
extends the inode `if` but does not replace the `& 7` check.

---

## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT

**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**

Record: **ext4 (`fs/ext4/`) — IMPORTANT.** Default Linux filesystem;
corruption/integrity issues matter to a large user base.

**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**

Record: active (recent 7.3 merges, DIO/DAX, writeback, fastcommit).
Superblock validation is mature; this fills a long-standing hole.

---

## PHASE 8: IMPACT AND RISK ASSESSMENT

**Step 8.1: DETERMINE WHO IS AFFECTED**

Record: **filesystem-specific**, ext4 with `metadata_csum` (and bitmap
ops generally). Trigger is a superblock with `s_inodes_per_group` or
`s_clusters_per_group` not divisible by 8. Normal `mke2fs` images are
8-aligned (group size `blocksize * 8`). Population: crafted/fuzzed
images, plus theoretically ancient Android `make_ext4fs` images Ted
believes are gone.

**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**

Record: mount of such an image. Not every boot of a normal distro disk.
Unprivileged trigger if the user can mount a file. Not a race.

**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**

Record:
- **Without the check:** trailing bitmap bits omitted from
  `metadata_csum` → integrity hole; debug free-counts ignore those bits;
  incremental CRC (not in this tree) could write a wrong checksum.
- **With the check:** mount fails with `-EINVAL` and a clear error.
- **Severity: MEDIUM–HIGH** for crafted images (metadata integrity /
  checksum vs tools). **Not** a panic on a normal disk. Fits the stable
  “oh, that’s not good” / data-integrity class more than oops/deadlock.

**Step 8.4: CALCULATE RISK-BENEFIT RATIO**

Record:
- **Benefit:** stops mounting invalid geometry; closes unprotected
  bitmap bits; matches e2fsck/Ted’s request. High for anyone mounting
  untrusted ext4 images; low for typical servers with `mke2fs` disks.
- **Risk:** very low on this tree — 6 lines, mount-time only, no
  locking/API change. Residual risk is refusing a 10+ year-old Android
  image; maintainer explicitly accepted that.
- **Ratio:** favorable.

---

## PHASE 9: FINAL SYNTHESIS

**Step 9.1: COMPILE THE EVIDENCE**

**FOR backporting**
- Real metadata-integrity bug: CRC covers `n/8` bytes, bitmaps have `n`
  bits.
- Crafted-image mount path is userspace-reachable.
- 6-line, obviously correct addition to existing validation.
- Suggested and applied by Ted Ts'o; Reviewed-by Jan Kara and Zhang Yi;
  no NAKs.
- Independent of the rest of the v2 series and of the unmerged CRC RFC.
- Code and helpers exist in this 7.3-rc4 tree; patch applies as written.
- Cover letter: “preventing crafted filesystem images from causing
  bitmap checksum corruption”.

**AGAINST**
- Incremental CRC that would *write* a wrong checksum is **not** in this
  kernel.
- No production oops/syzbot repro on a normal filesystem.
- Possible mount refusal of ancient `make_ext4fs` images (Ted:
  landfill).
- Sashiko is static analysis, not a user crash.

**UNRESOLVED**
- Stable list archives (lore 403).
- Current e2fsprogs source not in this repo (Ted’s historical e2fsck
  conflict is documented).

**Step 9.2: APPLY THE STABLE RULES CHECKLIST**

1. Obviously correct and tested? **PASS** — `& 7` next to existing
   bounds; reviewed by two ext4 developers; applied by maintainer.
2. Fixes a real bug that affects users? **PASS** — unprotected bitmap
   bits and crafted-image checksum/integrity mismatch; maintainer
   treated it as a real fill_super hole.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
   metadata checksum integrity / crafted-image corruption; not a panic,
   but on-disk checksum and `metadata_csum` bypass for trailing bits.
4. Small and contained? **PASS** — 6 insertions / 4 deletions, one file.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — already applies; context
   matches.

**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**

Record: none (not a device ID, quirk, DT, build, or docs patch).
Qualified on the normal bug-fix path.

**Step 9.4: MAKE YOUR DECISION**

This belongs on this tree: the checksum code still truncates to whole
bytes, mount already validates these fields, and adding `& 7` is the
missing invariant the CRC and bitmaps assume. It is small, maintainer-
directed, and does not depend on the incremental-CRC series that never
landed.

### What problem it solves and why it matters here

`metadata_csum` hashes inode/block bitmaps in byte units. A superblock
with inodes or clusters per group not divisible by 8 leaves up to 7 bits
out of the CRC while alloc/free still uses those bits. That is an
integrity hole and a footgun for any checksum updater that assumes byte
alignment. Rejecting that geometry at mount is the same class of check
this file already does for “too big” groups.

### Risk vs benefit

Benefit is closing that hole and refusing crafted images. Risk is a
failed mount of a pathological superblock. Ted already signed off that
remaining Android `make_ext4fs` cases are historical.

---

Verification:
- [Phase 1] Parsed tags: Suggested-by Ted Ts'o; Reported-by Sashiko;
  Reviewed-by Jan Kara, Zhang Yi; msgid 827117-2; no Fixes/Cc-stable
- [Phase 1] Cover letter in mbox: crafted images → bitmap checksum
  corruption / overflow / OOB inode table
- [Phase 2] Diff: +6/-4 in `fs/ext4/super.c`; `s_clusters_per_group & 7`
  and `s_inodes_per_group & 7`
- [Phase 2] `bitmap.c`: `>> 3` and `/ 8` confirmed; set and verify share
  length
- [Phase 2] `ialloc.c:173`: memset uses `(n+7)/8` vs CRC `>> 3`
- [Phase 2] `crc32c_flip_range`: no matches — incremental CRC not in
  this tree
- [Phase 3] `git describe HEAD` / `make kernelversion`: **v7.3-rc4 /
  7.3.0-rc4**
- [Phase 3] `git merge-base --is-ancestor d42dc7726a003 HEAD`: yes
- [Phase 3] blame: cluster bound `40da553f5da02` (2024); inode bound via
  `107d2be90116a`; CRC since `41a246d1ff75a` (2012)
- [Phase 3] series: `afa3caf2fbc41` and `a34de48f329b2` independent;
  cover letter says so
- [Phase 4] `b4 dig -c`: patch.msgid.link/20260608111150.827117-2-…; v1
  RFC 17-patch CRC, v2 3-patch validation
- [Phase 4] `b4 dig -a/-w/-m`: Zhang Yi + Jan Kara R-b; Ted applied;
  recipients linux-ext4 + maintainers
- [Phase 4] Ted mbox: Android make_ext4fs history; add fill_super check
- [Phase 4] lore HTTP 403; used b4 instead
- [Phase 5] callers: only `__ext4_fill_super` at lines 5443 and 5451
- [Phase 6] local `super.c` already has both `& 7` checks; bitmap CRC
  still truncated
- [Phase 7] ext4, important, actively merged in 7.3
- [Phase 8] failure mode: unprotected trailing bitmap bits / crafted-
  image integrity; mount-time -EINVAL after fix
- [Phase 8] stable-kernel-rules.rst: oops/hang/corruption/security/“oh,
  that’s not good”; 100-line cap
- UNVERIFIED: stable@ lore search (403); live e2fsprogs source not in
  tree

The patch is a 6-line, maintainer-reviewed mount check that enforces an
invariant the bitmap checksum code has assumed since 2012. It is in
scope for this 7.3-rc4 tree and meets stable criteria.

**YES**

 fs/ext4/super.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 9b45d27515f9f..cdb7e253015e5 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4431,8 +4431,9 @@ static int ext4_handle_clustersize(struct super_block *sb)
 		sbi->s_cluster_bits = 0;
 	}
 	sbi->s_clusters_per_group = le32_to_cpu(es->s_clusters_per_group);
-	if (sbi->s_clusters_per_group > sb->s_blocksize * 8) {
-		ext4_msg(sb, KERN_ERR, "#clusters per group too big: %lu",
+	if (sbi->s_clusters_per_group > sb->s_blocksize * 8 ||
+	    sbi->s_clusters_per_group & 7) {
+		ext4_msg(sb, KERN_ERR, "invalid #clusters per group: %lu",
 			 sbi->s_clusters_per_group);
 		return -EINVAL;
 	}
@@ -5230,8 +5231,9 @@ static int ext4_block_group_meta_init(struct super_block *sb, int silent)
 		return -EINVAL;
 	}
 	if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
-	    sbi->s_inodes_per_group > sb->s_blocksize * 8) {
-		ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu\n",
+	    sbi->s_inodes_per_group > sb->s_blocksize * 8 ||
+	    sbi->s_inodes_per_group & 7) {
+		ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu",
 			 sbi->s_inodes_per_group);
 		return -EINVAL;
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit
       [not found] <20261019135441.1420968-1-sashal@kernel.org>
                   ` (4 preceding siblings ...)
  2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned Sasha Levin
@ 2026-10-19 13:53 ` Sasha Levin
  2026-10-19 15:27   ` sashiko-bot
  5 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-10-19 13:53 UTC (permalink / raw)
  To: patches, stable
  Cc: Baokun Li, Sashiko, Andreas Dilger, Theodore Ts'o,
	Sasha Levin, linux-ext4, linux-kernel

From: Baokun Li <libaokun@linux.alibaba.com>

[ Upstream commit afa3caf2fbc417f755f36e271c4b3c2d45ccda9d ]

The mke2fs man page documents:

  Valid cluster-size values are from 2048 to 256M bytes per cluster.

but EXT4_MAX_CLUSTER_LOG_SIZE was set to 30 (1GB), allowing crafted
filesystem images to specify cluster sizes up to 1GB.

On 32-bit systems with bigalloc enabled, the consistency check in
ext4_handle_clustersize():

  s_blocks_per_group == s_clusters_per_group * (clustersize / blocksize)

can overflow when the cluster ratio is large enough. Since
s_blocks_per_group is not range-checked in the bigalloc path, the
wrapped product can pass the consistency check, leading to inconsistent
group geometry and potential out-of-bounds block allocation.

Reduce EXT4_MAX_CLUSTER_LOG_SIZE to 28 to match the documented 256MB
limit. With this cap, the maximum product is:

  (blocksize * 8) * (256M / blocksize) = 2^31

which fits safely in a 32-bit unsigned long for all block sizes.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260608061112.392391-1-libaokun%40linux.alibaba.com
Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Link: https://patch.msgid.link/20260608111150.827117-3-libaokun@linux.alibaba.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Local tree is **v7.3-rc4** (kernel 7.3.0-rc4, detached HEAD). The change
is a one-line cap on ext4 bigalloc cluster size to stop a 32-bit
overflow on crafted images.

===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================

**Step 1.1: PARSE THE SUBJECT LINE**

Record: **[ext4]** **[reduce]** reduce `EXT4_MAX_CLUSTER_LOG_SIZE` from
30 (1GB) to 28 (256MB) to match the documented mke2fs limit and stop a
32-bit overflow.

**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**

Record:
- **Reported-by:** Sashiko `<sashiko-bot@kernel.org>` (automated kernel
  review, not syzbot)
- **Closes:** https://sashiko.dev/#/patchset/20260608061112.392391-1-
  libaokun%40linux.alibaba.com (v1 series)
- **Reviewed-by:** Andreas Dilger `<adilger@dilger.ca>` (ext4 co-
  maintainer)
- **Link:** https://patch.msgid.link/20260608111150.827117-3-
  libaokun@linux.alibaba.com
- **Signed-off-by:** Baokun Li `<libaokun@linux.alibaba.com>` (author)
- **Signed-off-by:** Theodore Ts'o `<tytso@mit.edu>` (ext4 maintainer;
  applied the series)
- **Fixes:** none (expected for this review pipeline)
- **Cc: stable:** none (expected)
- Ignore pipeline markers: none present in the supplied message beyond
  the usual evaluation context

**Step 1.3: ANALYZE THE COMMIT BODY TEXT**

Record:
- **Bug:** `EXT4_MAX_CLUSTER_LOG_SIZE` was 30, so crafted bigalloc
  images can claim cluster sizes up to 1GB. mke2fs only documents
  2048–256MB.
- **Symptom/failure mode:** On 32-bit, `s_clusters_per_group *
  (clustersize / blocksize)` in `ext4_handle_clustersize()` wraps.
  `s_blocks_per_group` is not range-checked on the bigalloc path, so the
  wrapped product can pass the consistency check. That yields
  inconsistent group geometry and possible out-of-bounds block
  allocation.
- **Version info:** none beyond “32-bit systems with bigalloc”.
- **Root cause (author):** cluster-size cap is too high; product can
  exceed 32-bit `unsigned long`.

**Step 1.4: DETECT HIDDEN BUG FIXES**

Record: Not a disguised cleanup. The message names overflow, crafted
images, and OOB allocation. It is an explicit mount-time sanity fix.

===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================

**Step 2.1: INVENTORY THE CHANGES**

Record:
- **File:** `fs/ext4/ext4.h` — 1 line changed (`30` → `28`)
- **Functions:** none; only `#define EXT4_MAX_CLUSTER_LOG_SIZE`
- **Scope:** single-file, one-constant surgical fix

**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**

Record:
- **Before:** `__ext4_fill_super()` rejects `s_log_cluster_size` only if
  it is greater than `30 - 10 = 20`, so `clustersize = BLOCK_SIZE << log
  = 1024 << 20 = 1GB` is accepted.
- **After:** max log is `28 - 10 = 18`, so max cluster size is `1024 <<
  18 = 256MB`.
- **Path:** mount-time superblock validation in `__ext4_fill_super()`,
  before `ext4_handle_clustersize()`.

Verified use site:

```5196:5202:fs/ext4/super.c
        if (le32_to_cpu(es->s_log_cluster_size) >
            (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
                ext4_msg(sb, KERN_ERR,
                         "Invalid log cluster size: %u",
                         le32_to_cpu(es->s_log_cluster_size));
                goto out;
        }
```

**Step 2.3: IDENTIFY THE BUG MECHANISM**

Record:
- **Category:** integer overflow in mount-time geometry check, leading
  to inconsistent geometry / possible OOB block allocation (memory-
  safety / filesystem-image robustness).
- **Mechanism:** `s_blocks_per_group` and `s_clusters_per_group` are
  `unsigned long` (`fs/ext4/ext4.h`). The check is:

```4500:4506:fs/ext4/super.c
        if (sbi->s_blocks_per_group !=
            (sbi->s_clusters_per_group * (clustersize /
sb->s_blocksize))) {
                ext4_msg(sb, KERN_ERR,
                         "blocks per group (%lu) and clusters per group
(%lu) inconsistent",
                         sbi->s_blocks_per_group,
sbi->s_clusters_per_group);
                return -EINVAL;
        }
```

`s_clusters_per_group` is capped at `blocksize * 8`. Max product is
`(blocksize * 8) * (clustersize / blocksize) = 8 * clustersize`.
- With 1GB clusters: `8 * 2^30 = 2^33` → wraps on 32-bit `unsigned
  long`.
- With 256MB clusters: `8 * 2^28 = 2^31` → fits in 32-bit `unsigned
  long`.

The `s_blocks_per_group > sb->s_blocksize * 8` range check is only on
the **non-bigalloc** branch (verified in `ext4_handle_clustersize()`).

**Step 2.4: ASSESS THE FIX QUALITY**

Record:
- **Quality:** obviously correct. Tightens an existing mount-time bound
  to the documented mkfs limit; the overflow math is checkable by
  inspection.
- **Regression risk:** very low. mke2fs documents max 256MB; Andreas
  Dilger noted real-world >1GB clusters are implausible. A 512MB (log
  29) filesystem would also be rejected; Jan Kara said 28 or 29 were
  both acceptable. **29 is not overflow-safe:** `8 * 512MB = 2^32` wraps
  to 0 on 32-bit `unsigned long`. 28 is the right cap. Ted applied 28.

===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================

**Step 3.1: BLAME THE CHANGED LINES**

Record:
- Current line (already 28 in this checkout): `afa3caf2fbc41` Baokun Li,
  2026-06-08 — the candidate itself.
- Previous value 30 introduced by **`9e47a4c9fc580`** (“ext4: sanity
  check the block and cluster size at mount time”, Ted Ts'o,
  2016-11-18), first in **v4.10-rc1**. Duplicate in-tree copy:
  `8cdf3372fe836`.
- That original commit was **Cc: stable** and cited security refs
  (SecurityFocus 539661, RH BZ 1332506). The 1GB cap has been in place
  since then.

**Step 3.2: FOLLOW THE FIXES: TAG**

Record: No `Fixes:` tag. The overflow is in the interaction of the 2016
cap (`9e47a4c9fc580`, in this tree) and the bigalloc consistency
multiply (bigalloc from `281b59959707d`, **v3.2-rc1**). Both ancestors
of HEAD.

**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**

Record:
- This is **v2 2/3** of “ext4: tighten mount-time superblock geometry
  validation”.
- Sibling **1/3:** `d42dc7726a003` — 8-alignment of clusters/inodes per
  group (bitmap csum).
- Sibling **3/3:** `a34de48f329b2` — inodes-per-group multiple of
  inodes-per-block.
- Cover letter (Ted applied 2026-07-23): patches 2 and 3 were added in
  v2 for additional Sashiko issues and are **independent of patch 1**.
- This commit is standalone: only the `#define` in `ext4.h`. No
  prerequisite from 1/3 or 3/3.

**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**

Record: Baokun Li is a regular, high-volume ext4 contributor (many
recent ext4 commits in this tree). Series was reviewed by
Dilger/Kara/Zhang Yi and applied by Ted Ts'o.

**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**

Record: None required. `EXT4_MAX_CLUSTER_LOG_SIZE` and the
`s_log_cluster_size` check exist here. The define is the only consumer
besides `ext4.h` itself (`git grep` shows only `fs/ext4/ext4.h` and
`fs/ext4/super.c`). Applies standalone.

===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================

**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**

Record:
- **b4 dig -c afa3caf2fbc41:** matched `[PATCH v2 2/3]` at https://patch
  .msgid.link/20260608111150.827117-3-libaokun@linux.alibaba.com
- **b4 dig -a:** series is **v2** “ext4: tighten mount-time superblock
  geometry validation” (2026-06-08). v1 was only patch 1; patches 2–3
  are new in v2.
- **Jan Kara** (2026-06-09): no NAK; defer 28 vs 29 to Ted; both fine if
  consistent.
- **Andreas Dilger** (2026-06-08): Reviewed-by; “pretty safe”; doubts
  anyone uses >1GiB clusters.
- **Ted Ts'o** (2026-07-23): “Applied, thanks!” with this SHA.
- No NAKs. No reviewer `Cc: stable` in the thread (absence expected).

**Step 4.2: CHECK WHO REVIEWED THE PATCH**

Record (**b4 dig -w**): linux-ext4, tytso, adilger, jack@suse.cz,
yi.zhang@huawei.com, ojaswin@linux.ibm.com, ritesh.list@gmail.com,
Sashiko. Maintainers and regular reviewers were on the To/Cc list.
Dilger R-b; Ted applied.

**Step 4.3: SEARCH FOR THE BUG REPORT**

Record: Sashiko is an LF/Google automated review bot, not a user crash
or syzbot repro. The Closes URL is the v1 patchset page (SPA; fetch
returned the Sashiko landing page, not the finding text). Cover letter:
patches 2 and 3 fix additional Sashiko-reported issues. Severity from
the patch itself: crafted-image overflow → inconsistent geometry / OOB
allocation.

**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**

Record: Three independent mount-time checks. This one does not need 1/3
or 3/3 to be correct. Siblings are also real bugfixes but out of scope
for this verdict.

**Step 4.5: CHECK STABLE MAILING LIST HISTORY**

Record: lore.kernel.org/stable returned 403. Openwall/web search found
no stable-list rejection of this patch. UNVERIFIED whether anyone
already requested it on stable@.

===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================

**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**

Record: No function body changed. Consumer: `__ext4_fill_super()`
cluster-log check; downstream user of the accepted size:
`ext4_handle_clustersize()`.

**Step 5.2: TRACE CALLERS**

Record:
- `ext4_handle_clustersize()` is static; only caller is
  `__ext4_fill_super()` at mount (`fs/ext4/super.c:5451`).
- `ext4_fill_super()` is the VFS mount entry (`:5835`).
- Context: filesystem mount, not IRQ/hot path.

**Step 5.3: TRACE CALLEES**

Record: The define is only compared in the mount validator. No new
calls.

**Step 5.4: FOLLOW THE CALL CHAIN**

Record: Userspace mount of an ext4 image (`mount`, loop, USB, VM disk) →
`ext4_fill_super` → `__ext4_fill_super` → log-cluster check →
`ext4_handle_clustersize()`. Reachable from any ext4 mount of a bigalloc
image. Triggering the overflow needs a crafted superblock (untrusted
image), typically CAP_SYS_ADMIN to mount, still the usual malicious-
filesystem class.

**Step 5.5: SEARCH FOR SIMILAR PATTERNS**

Record: Same series adds two other geometry checks. Same class of
crafted-image bugs. No other `EXT4_MAX_CLUSTER_LOG_SIZE` sites.

===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================

**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**

Record:
- Tree: **v7.3-rc4-27-gf0100363d8c37**, `VERSION=7 PATCHLEVEL=3
  SUBLEVEL=0 EXTRAVERSION=-rc4`.
- `git merge-base --is-ancestor afa3caf2fbc41 HEAD` → commit **is** in
  HEAD (landed via ext4-for-linus 7.3-rc1). Current `#define` is already
  28.
- That does **not** mean “already selected for stable”; it is the
  mainline landing. The **bug mechanism** (32-bit multiply of
  `s_clusters_per_group` by cluster ratio, uncapped `s_blocks_per_group`
  on bigalloc) is still in `ext4_handle_clustersize()` here; only the
  cap is 28.
- Bug class has existed since the 2016 cap (`9e47a4c9fc580` is an
  ancestor). Code is not missing.

**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**

Record: Expected apply: **clean**. One-line `#define` change in
`fs/ext4/ext4.h`. Macro and check have been stable since 2016 / the 2022
`ext4_handle_clustersize()` factor-out (`4a8557b094671`).

**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**

Record: This is the fix. No earlier alternate cap. No follow-up revert
or tightening of this define after `afa3caf2fbc41` in `fs/ext4/ext4.h`.

===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================

**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**

Record: **ext4** (`fs/ext4/`). **IMPORTANT** — default Linux filesystem;
crafted-image bugs affect anyone who mounts untrusted ext4 (install
media, USB, VMs, backups).

**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**

Record: Actively developed (ext4_for_linus pulls this cycle). The
overflow is in long-standing mount validation, not new BS>PS work.

===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================

**Step 8.1: DETERMINE WHO IS AFFECTED**

Record: **Filesystem-specific (ext4)**, extra conditions: **bigalloc +
32-bit `unsigned long` + cluster size > 256MB**. 64-bit does not wrap at
1GB, but the looser cap still allows undocumented cluster sizes. 32-bit
still matters (embedded, some Android/i686).

**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**

Record: Mount of a crafted bigalloc image with large
`s_log_cluster_size`. Not every boot. Not an unprivileged syscall by
itself (mount is privileged), but standard untrusted-image attack. Not a
timing race.

**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**

Record: Integer overflow bypass of geometry check → inconsistent groups
→ **potential out-of-bounds block allocation**. Severity **HIGH**
(memory corruption / OOB on crafted mount). Not a guaranteed panic on
every mount, but it is a real robustness/security class that stable
routinely takes.

**Step 8.4: CALCULATE RISK-BENEFIT RATIO**

Record:
- **Benefit:** high for 32-bit ext4 mounts of untrusted images; aligns
  kernel with documented mkfs limit.
- **Risk:** very low (one constant; Dilger R-b; Ted applied). Only
  theoretical regression is rejecting 512MB/1GB cluster filesystems that
  mke2fs would not create.
- **Ratio:** strongly favors backport.

===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================

**Step 9.1: COMPILE THE EVIDENCE**

FOR:
- Real 32-bit overflow in mount-time geometry check; wrapped product can
  pass; OOB allocation is the stated consequence.
- One-line, obviously correct cap matching mke2fs (256MB).
- 28 is the max value that keeps `8 * clustersize` ≤ 2^31 on 32-bit.
- Reviewed by Andreas Dilger; applied by Ted Ts'o; Jan Kara did not
  object.
- Independent of the rest of the series.
- Affected code present since v4.10; applies cleanly.
- Same class as the original 2016 cluster-size sanity check (that one
  was Cc: stable).

AGAINST:
- Trigger needs crafted bigalloc + typically 32-bit.
- No `Fixes:` / `Cc: stable` (not a negative per rules).
- Sashiko is a bot, not a production crash with a reproducer.
- Jan Kara floated 29; that value still overflows (verified); committed
  value is 28.

UNRESOLVED:
- Stable@ discussion (lore/stable 403).
- Full Sashiko finding text (SPA page).

**Step 9.2: APPLY THE STABLE RULES CHECKLIST**

1. Obviously correct and tested? **PASS** — one-constant change;
   maintainer-applied; Dilger R-b.
2. Fixes a real bug that affects users? **PASS** — overflow on crafted
   bigalloc mount.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
   HIGH: overflow → bad geometry / possible OOB allocation.
4. Small and contained? **PASS** — 1 line, 1 file.
5. No new features or APIs? **PASS** — tightens an existing limit.
6. Can apply to the local tree? **PASS** — define and check exist; patch
   is a single substitution.

**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**

Record: Not an ID/quirk/DT/build/docs exception. It is a normal small
correctness/security-style mount check.

**Step 9.4: MAKE YOUR DECISION**

This tree has the ext4 mount path, the overflow-prone multiply, and the
too-large historical cap. The fix is a one-line tightening to the
documented 256MB limit so the 32-bit product cannot wrap. Independent,
reviewed, and low regression risk. It should be backported here.

------------------------------------------------
What the commit solves and why it matters
------------------------------------------------
Crafted ext4 bigalloc images can set cluster size up to 1GB. On 32-bit,
the groups-per-cluster consistency multiply wraps, so a bogus
`s_blocks_per_group` can look consistent. That can produce wrong group
geometry and out-of-bounds block allocation when the image is mounted.
Capping at 256MB matches mke2fs and keeps the product at 2^31.

------------------------------------------------
Stable rules / risk vs benefit
------------------------------------------------
Meets all six criteria: real overflow, small, no API, applies cleanly.
Benefit is blocking a crafted-image OOB path; risk is rejecting
undocumented huge clusters that tools do not create.

------------------------------------------------
Concerns
------------------------------------------------
No extra series deps. No backport rework expected. 32-bit-centric, but
still a valid stable-class filesystem-image bug.

Verification:
- [Phase 1] Parsed tags: Reported-by Sashiko; Reviewed-by Andreas
  Dilger; SOB Baokun Li + Ted Ts'o; Link msgid 20260608111150.827117-3;
  no Fixes/Cc:stable
- [Phase 1] Cover letter (openwall/spinics): v2 2/3 independent of 1/3;
  overflow on 32-bit bigalloc
- [Phase 2] Diff: 1 line in fs/ext4/ext4.h, 30→28
- [Phase 2] Read ext4_handle_clustersize(): s_blocks_per_group range
  check only on non-bigalloc; multiply at lines 4500–4501
- [Phase 2] Types: s_blocks_per_group / s_clusters_per_group are
  unsigned long (ext4.h:1595–1596)
- [Phase 2] Math: max product 8*clustersize; 1GB → 2^33 wrap; 256MB →
  2^31; 512MB → 2^32 wrap (29 unsafe)
- [Phase 2] Consumer: __ext4_fill_super log-cluster check at
  super.c:5196–5202
- [Phase 3] git blame: current 28 from afa3caf2fbc41; 30 from
  9e47a4c9fc580 (2016-11-18, v4.10-rc1, Cc:stable)
- [Phase 3] git merge-base --is-ancestor 9e47a4c9fc580 HEAD: yes
- [Phase 3] git merge-base --is-ancestor afa3caf2fbc41 HEAD: yes
  (mainline landing, not used as circular “already selected”)
- [Phase 3] Series siblings d42dc7726a003 and a34de48f329b2 are
  independent; this patch only touches the define
- [Phase 3] git grep EXT4_MAX_CLUSTER_LOG_SIZE: only ext4.h and super.c
- [Phase 4] b4 dig -c: lore msgid 20260608111150.827117-3
- [Phase 4] b4 dig -a: v2 series 2026-06-08; v1 was patch 1 only
- [Phase 4] b4 dig -w: tytso, dilger, jack, linux-ext4 on original To/Cc
- [Phase 4] Jan Kara: 28 vs 29 up to Ted, no NAK
- [Phase 4] Andreas Dilger: Reviewed-by; safe, nobody using >1GiB
  clusters
- [Phase 4] Ted: Applied 2026-07-23 as afa3caf2fbc41
- [Phase 4] lore.kernel.org/stable: 403, UNVERIFIED
- [Phase 4] sashiko.dev hash URL: landing page only, UNVERIFIED full
  finding text
- [Phase 5] Only caller of ext4_handle_clustersize: __ext4_fill_super
  (mount)
- [Phase 6] git describe HEAD: v7.3-rc4-27-gf0100363d8c37; make
  kernelversion 7.3.0-rc4
- [Phase 6] Buggy cap/check present in this lineage since v4.10; apply
  is a one-line define swap
- [Phase 8] Failure mode: 32-bit overflow → inconsistent geometry /
  possible OOB alloc, severity HIGH
- UNVERIFIED: stable@ thread; full Sashiko report body

**YES**

 fs/ext4/ext4.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index da6428312c36b..a9178d63a7d1b 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -334,7 +334,7 @@ struct ext4_io_submit {
 #define	EXT4_MAX_BLOCK_SIZE		65536
 #define EXT4_MIN_BLOCK_LOG_SIZE		10
 #define EXT4_MAX_BLOCK_LOG_SIZE		16
-#define EXT4_MAX_CLUSTER_LOG_SIZE	30
+#define EXT4_MAX_CLUSTER_LOG_SIZE	28
 #ifdef __KERNEL__
 # define EXT4_BLOCK_SIZE(s)		((s)->s_blocksize)
 #else
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing
  2026-10-19 13:44 ` [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing Sasha Levin
@ 2026-10-19 14:04   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 14:04 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

> From: Zhang Yi <yi.zhang@huawei.com>
> 
> [ Upstream commit e1cf7b5f5c8ad1e00d00c50c61c3e8fdc79cd422 ]
> 
> ext4_load_tail_bh() returns a locked folio that callers immediately
> mutate through folio_zero_range() and mark_buffer_dirty().  Use
> FGP_WRITEBEGIN so that, on backing devices that require stable writes,
> __filemap_get_folio() waits for writeback to finish before returning
> the folio; on regular devices the wait is a no-op.
> 
> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Link: https://patch.msgid.link/20260714080044.4038124-2-yi.zhang@huaweicloud.com
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Sasha Levin <sashal@kernel.org>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-5-sashal@kernel.org?part=1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh()
  2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh() Sasha Levin
@ 2026-10-19 14:32   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 14:32 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] ext4: unchecked ext4_block_truncate_page() return in truncate callers
--

commit 26fe59dd3c7737fcb95b3fe2c9732b862d57565e
Author: Zhang Yi <yi.zhang@huawei.com>

ext4: check return value of ext4_get_block() in ext4_load_tail_bh()

This patch checks and propagates the return value of ext4_get_block() in
__ext4_block_zero_page_range() so that I/O or allocation failures are not
silently ignored as holes during zero-range, truncate, or punch-hole
operations.

Link: https://patch.msgid.link/20260714080044.4038124-4-yi.zhang@huaweicloud.com

> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index e99306a8f47ce..234dfe20ef4f3 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -4092,7 +4092,9 @@ static int __ext4_block_zero_page_range(handle_t *handle,
>  	}
>  	if (!buffer_mapped(bh)) {
>  		BUFFER_TRACE(bh, "unmapped");
> -		ext4_get_block(inode, iblock, bh, 0);
> +		err = ext4_get_block(inode, iblock, bh, 0);
> +		if (err < 0)
> +			goto unlock;
>  		/* unmapped? It's a hole - nothing to do */
>  		if (!buffer_mapped(bh)) {
>  			BUFFER_TRACE(bh, "still unmapped");

[Severity: Medium]
While this propagates the negative error from ext4_get_block() out of
__ext4_block_zero_page_range() via ext4_block_zero_page_range(),
ext4_block_truncate_page(), and ext4_zero_partial_blocks(), several
truncate and fallocate callers ignore the returned error.

In fs/ext4/inode.c, a shrinking truncate via
ext4_setattr()->ext4_truncate()->ext4_block_truncate_page() ignores the
return value and proceeds with block truncation:

	if (inode->i_size & (inode->i_sb->s_blocksize - 1))
		ext4_block_truncate_page(handle, mapping, inode->i_size);

Similarly, an extending truncate in ext4_setattr() ignores the error from
ext4_block_truncate_page() and proceeds to update i_disksize and i_size:

	if (!shrink) {
		inode_set_mtime_to_ts(inode,
				      inode_set_ctime_current(inode));
		if (oldsize & (inode->i_sb->s_blocksize - 1))
			ext4_block_truncate_page(handle,
					inode->i_mapping, oldsize);
	}

And in fs/ext4/extents.c, an extending fallocate or zero-range
preallocation in ext4_alloc_file_blocks() ignores the error returned by
ext4_zero_partial_blocks() when zeroing the old EOF tail block:

	if (epos > old_size) {
		pagecache_isize_extended(inode, old_size, epos);
		ext4_zero_partial_blocks(handle, inode,
				     old_size, epos - old_size);
	}

When the tail buffer_head is unmapped and ext4_get_block() fails, can
these paths still silently discard the error, update the inode size, and
return success with stale data left in the partial tail block?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-141-sashal@kernel.org?part=1

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info
  2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info Sasha Levin
@ 2026-10-19 14:53   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 14:53 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

> From: Junzhe Yu <junzheyu1@gmail.com>
> 
> [ Upstream commit 8f3901fbb40745046e513226ad84e8b84492632d ]
> 
> Resend: previous attempt was rejected by vger for containing HTML.
> 
> ==================================================================
> 
> ext4_mark_group_bitmap_corrupted() already treats a NULL return from
> ext4_get_group_info() as "nothing to do", but ext4_get_group_info()
> indexes s_group_info without checking whether the array exists.
> 
> During mount, fast-commit replay runs inside jbd2_journal_load() from
> ext4_load_and_init_journal(), which is before ext4_mb_init() allocates
> s_group_info. Replaying an FC UNLINK for an inode whose bitmap bit is
> [ ... ]
> 
> Signed-off-by: Yu Junzhe <junzheyu1@gmail.com>
> Link: https://patch.msgid.link/65c955b0-716b-4599-b925-59c2782e38b4@gmail.com
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Sasha Levin <sashal@kernel.org>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-308-sashal@kernel.org?part=1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode
  2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode Sasha Levin
@ 2026-10-19 14:55   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 14:55 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

> From: Yun Zhou <yun.zhou@windriver.com>
> 
> [ Upstream commit 2c0e4fb511f97467dafc91b6afb3414100289081 ]
> 
> An inode being evicted will never need its extra isize expanded.  Set
> EXT4_STATE_NO_EXPAND before ext4_mark_inode_dirty() in ext4_evict_inode()
> to make this explicit and prevent any unnecessary work in
> ext4_try_to_expand_extra_isize().
> 
> This also provides defense-in-depth for the s_writepages_rwsem deadlock
> during mount-time orphan cleanup, ensuring the expand path is blocked
> for inodes under eviction regardless of how they are reached.
> 
> Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Link: https://patch.msgid.link/20260623061903.2148767-2-yun.zhou@windriver.com
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Sasha Levin <sashal@kernel.org>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-321-sashal@kernel.org?part=1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned
  2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned Sasha Levin
@ 2026-10-19 15:06   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 15:06 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

> From: Baokun Li <libaokun@linux.alibaba.com>
> 
> [ Upstream commit d42dc7726a003262b73ffef2b744ff57a5488799 ]
> 
> The block and inode bitmap checksums are computed over a whole number of
> bytes: ext4_inode_bitmap_csum_*() use EXT4_INODES_PER_GROUP(sb) >> 3 and
> ext4_block_bitmap_csum_*() use EXT4_CLUSTERS_PER_GROUP(sb) / 8 as the
> length passed to ext4_chksum().
> 
> If s_inodes_per_group or s_clusters_per_group is not a multiple of 8, the
> trailing fractional bits are excluded from the checksum.  Those bits are
> then unprotected, and any incremental csum update path that assumes a
> byte-aligned bitmap can compute a checksum inconsistent with the full
> recalculation, corrupting the on-disk bitmap checksum.
> 
> Reject such filesystems at mount time by adding the missing " & 7"
> alignment checks alongside the existing range validation.
> 
> Suggested-by: Theodore Ts'o <tytso@mit.edu>
> Link: https://patch.msgid.link/h3n7jlfhyna64dn5o76qxcspnhxdddcs6crpxftmy7gnl7b3sx@jenszfpcsnit
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://sashiko.dev/#/patchset/20260508121539.4174601-1-libaokun%40linux.alibaba.com?part=10
> Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
> Link: https://patch.msgid.link/20260608111150.827117-2-libaokun@linux.alibaba.com
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Sasha Levin <sashal@kernel.org>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-395-sashal@kernel.org?part=1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit
  2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit Sasha Levin
@ 2026-10-19 15:27   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-10-19 15:27 UTC (permalink / raw)
  To: Sasha Levin; +Cc: linux-ext4, tytso

> From: Baokun Li <libaokun@linux.alibaba.com>
> 
> [ Upstream commit afa3caf2fbc417f755f36e271c4b3c2d45ccda9d ]
> 
> The mke2fs man page documents:
> 
>   Valid cluster-size values are from 2048 to 256M bytes per cluster.
> 
> but EXT4_MAX_CLUSTER_LOG_SIZE was set to 30 (1GB), allowing crafted
> filesystem images to specify cluster sizes up to 1GB.
> 
> On 32-bit systems with bigalloc enabled, the consistency check in
> ext4_handle_clustersize():
> 
>   s_blocks_per_group == s_clusters_per_group * (clustersize / blocksize)
> [ ... ]
> Signed-off-by: Baokun Li <libaokun@linux.alibaba.com>
> Reviewed-by: Andreas Dilger <adilger@dilger.ca>
> Link: https://patch.msgid.link/20260608111150.827117-3-libaokun@linux.alibaba.com
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> Signed-off-by: Sasha Levin <sashal@kernel.org>

Sashiko has reviewed this patch and found no issues.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-511-sashal@kernel.org?part=1


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-10-19 15:27 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:44 ` [PATCH AUTOSEL 6.18-6.6] ext4: use FGP_WRITEBEGIN for tail block zeroing Sasha Levin
2026-10-19 14:04   ` sashiko-bot
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-5.10] ext4: check return value of ext4_get_block() in ext4_load_tail_bh() Sasha Levin
2026-10-19 14:32   ` sashiko-bot
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.10] ext4: guard against NULL s_group_info in ext4_get_group_info Sasha Levin
2026-10-19 14:53   ` sashiko-bot
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.10] ext4: set EXT4_STATE_NO_EXPAND in ext4_evict_inode Sasha Levin
2026-10-19 14:55   ` sashiko-bot
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ext4: reject mount if clusters/inodes per group are not 8-aligned Sasha Levin
2026-10-19 15:06   ` sashiko-bot
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.10] ext4: reduce max cluster size to match documented 256MB limit Sasha Levin
2026-10-19 15:27   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox