[PATCH AUTOSEL 6.18-6.12] iomap: don't make REQ_POLLED imply REQ_NOWAIT
From: Sasha Levin
Date: Mon Aug 31 2026 - 12:28:38 EST
From: Christoph Hellwig <hch@xxxxxx>
[ Upstream commit 47f28b493daf9049307494689e515205f1c377af ]
As described in commit 2bc057692599 ("block: don't make REQ_POLLED imply
REQ_NOWAIT"), which fixed the same issue for the block device node, there
are valid cases to poll for I/O completion without REQ_NOWAIT.
Additionally, sing REQ_NOWAIT for file system writes is currently not
supported as file systems writes are not idempotent and would need a
retry of just the bio and not the entire operation to be fully supported.
Switch iomap to set REQ_POLLED and remove the now unused bio_set_polled
helper.
Signed-off-by: Christoph Hellwig <hch@xxxxxx>
Link: https://patch.msgid.link/20260518062917.506483-1-hch@xxxxxx
Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `iomap: don't make REQ_POLLED imply
REQ_NOWAIT`
**Local tree:** Linux **6.18.43** (`v6.18.43-1-gc7f0dac02d232`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: PARSE THE SUBJECT LINE
**Record:** `[iomap] [don't make / fix] [REQ_POLLED should not imply
REQ_NOWAIT on filesystem DIO bios]`
### Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** https://patch.msgid.link/20260518062917.506483-1-hch@xxxxxx
- **Cc: stable:** — none (expected for manual review)
- **Signed-off-by:** Christoph Hellwig `<hch@xxxxxx>`, Christian Brauner
`<brauner@xxxxxxxxxx>` (merge commit)
- **Notable:** References upstream commit `2bc057692599` (block-layer
companion fix). No syzbot, no user bug reports.
### Step 1.3: ANALYZE THE COMMIT BODY TEXT
**Record:**
- **Bug:** `bio_set_polled()` propagates `REQ_NOWAIT` onto bios when
`IOCB_NOWAIT` is set. For iomap filesystem DIO this is incorrect —
filesystem writes are not idempotent at the bio level and cannot be
retried by re-submitting just the bio.
- **Symptom:** Polled filesystem DIO (e.g. io_uring
`IORING_SETUP_IOPOLL` on xfs/ext4 O_DIRECT) can hit spurious `-EAGAIN`
from the block layer, or fail to make progress — same class of bug
fixed for raw block devices in 2023.
- **Root cause:** iomap reused `bio_set_polled()` which couples
`REQ_POLLED` with conditional `REQ_NOWAIT`; block/fops.c was already
fixed to decouple them, but iomap was not.
- **Version info:** Commit dated 2026-05-18; not yet in this 6.18.43
tree.
### Step 1.4: DETECT HIDDEN BUG FIXES
**Record:** Not disguised — this is an explicit correctness fix, though
small. The removal of `bio_set_polled()` is cleanup after the last
caller is gone.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: INVENTORY THE CHANGES
**Record:**
- `fs/iomap/direct-io.c`: 1 line changed (`bio_set_polled` →
`bio->bi_opf |= REQ_POLLED`)
- `include/linux/bio.h`: 14 lines removed (`bio_set_polled()` helper +
comment)
- **Functions modified:** `iomap_dio_submit_bio()`; `bio_set_polled()`
removed
- **Scope:** Single-subsystem, 2 files, ~16 lines total — surgical fix
### Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
**Record:**
- **Hunk 1 (`iomap_dio_submit_bio`):** Before: for async HIPRI DIO, call
`bio_set_polled(bio, iocb)` which sets `REQ_POLLED` and also
`REQ_NOWAIT` when `IOCB_NOWAIT` is set. After: only `REQ_POLLED` is
set; `IOCB_NOWAIT` is handled separately at the iomap layer via
`IOMAP_NOWAIT` (line 654–655).
- **Hunk 2 (`bio.h`):** Remove now-dead `bio_set_polled()` helper (only
caller was iomap).
### Step 2.3: IDENTIFY THE BUG MECHANISM
**Record:**
- **Category:** Logic / correctness fix (incorrect flag propagation)
- **Mechanism:** `REQ_NOWAIT` on a bio causes the block layer to return
`-EAGAIN` instead of blocking on resource contention
(`__bio_queue_enter`, tag allocation in `blk-mq`). For filesystem DIO
through iomap, `IOCB_NOWAIT` is already translated to `IOMAP_NOWAIT`
for filesystem-level handling; passing `REQ_NOWAIT` to the block layer
is both unnecessary and harmful for writes.
### Step 2.4: ASSESS THE FIX QUALITY
**Record:**
- Obviously correct: mirrors the already-accepted block-layer fix
pattern in `block/fops.c`.
- Minimal: one-line functional change plus dead-code removal.
- **Regression risk:** Very low. Block device path already uses the same
pattern. `IOMAP_NOWAIT` continues to handle filesystem-level non-
blocking semantics.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: BLAME THE CHANGED LINES
**Record:** Shallow repository limits blame — all lines attribute to
`a112b91dd6349` (unrelated sunrpc backport). Verified current buggy code
exists at `fs/iomap/direct-io.c:77` and `include/linux/bio.h:688-693`.
Kernel.org history (via curl) shows iomap polled-IO support added in
`daa99c5a3319` (2023-08-01, Jens Axboe: "iomap: only set iocb->private
for polled bio"); block fix `2bc057692599` (2023-08-08) updated
`bio_set_polled()` but left iomap calling it.
### Step 3.2: FOLLOW THE FIXES: TAG
**Record:** No `Fixes:` tag. Referenced commit `2bc057692599` ("block:
don't make REQ_POLLED imply REQ_NOWAIT") exists as a git object in this
tree; `block/fops.c` already uses the decoupled pattern (`IOCB_NOWAIT`
and `REQ_POLLED` set independently). iomap was the remaining caller of
`bio_set_polled()`.
### Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
**Record:** Shallow repo prevents meaningful `git log` on these files.
External kernel.org log confirms this is a standalone 1-patch fix (not
part of a series). Related prior fix: `2bc057692599` (block layer,
2023).
### Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
**Record:** Christoph Hellwig is the iomap maintainer. Christian Brauner
is VFS maintainer who applied the patch. Strong subsystem authority.
### Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
**Record:** No prerequisites. Self-contained. Depends only on existing
`IOCB_HIPRI`/polled-IO infrastructure already present in 6.18.43. Commit
`47f28b493daf` is NOT in this tree (object not found via `git cat-
file`).
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
**Record:** `b4 dig -c` could not run — commit not in local repo.
Fetched via spinics.net:
- URL: https://www.spinics.net/lists/linux-fsdevel/msg338671.html
- Single patch, no series revisions found
- CC'd: `axboe`, `linux-block`, `linux-fsdevel`, `linux-xfs`, `djwong`,
`brauner`
### Step 4.2: CHECK WHO REVIEWED THE PATCH
**Record:** CC list includes block maintainer (Axboe), XFS, fsdevel,
block lists. Brauner applied to `vfs-7.2.iomap` branch. No explicit
Reviewed-by in commit; no NAKs found.
### Step 4.3: SEARCH FOR THE BUG REPORT
**Record:** No bug report, syzbot, or crash trace. Bug identified by
code analysis and parity with the 2023 block-layer fix. Failure mode
inferred from block commit message: "repeated -EAGAIN submissions and
not make any progress."
### Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
**Record:** Standalone 1/1 patch. Companion to `2bc057692599` (already
in stable block path).
### Step 4.5: CHECK STABLE MAILING LIST HISTORY
**Record:** Not searched (no stable nomination found in thread). Absence
of `Cc: stable` is not a negative signal per review guidelines.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
**Record:** `iomap_dio_submit_bio()`, `bio_set_polled()` (removed)
### Step 5.2: TRACE CALLERS
**Record:** `iomap_dio_submit_bio()` called from iomap DIO write/read
paths in `fs/iomap/direct-io.c`. Reachable via `iomap_dio_rw()` →
filesystem `read_iter`/`write_iter` on xfs, ext4, f2fs, gfs2, zonefs,
btrfs (partial). io_uring sets `IOCB_HIPRI` for `IORING_SETUP_IOPOLL`
(`io_uring/rw.c:891-895`) and may set `IOCB_NOWAIT` for nonblock issue
(`io_uring/rw.c:950-954`).
### Step 5.3: TRACE CALLEES
**Record:** After fix: `bio->bi_opf |= REQ_POLLED`, then `submit_bio()`
(or filesystem `submit_io` hook). Block layer checks `REQ_NOWAIT` in
`__bio_queue_enter()` → `bio_wouldblock_error()` → `-EAGAIN`.
### Step 5.4: FOLLOW THE CALL CHAIN
**Record:** Userspace io_uring IOPOLL → `IOCB_HIPRI` + possibly
`IOCB_NOWAIT` → `xfs_file_read_iter`/`ext4_file_write_iter` →
`iomap_dio_rw` → `iomap_dio_submit_bio` → block layer. **Reachable from
userspace** on common filesystems with `.iopoll = iocb_bio_iopoll` (xfs,
ext4, f2fs, gfs2, zonefs).
### Step 5.5: SEARCH FOR SIMILAR PATTERNS
**Record:** `block/fops.c:383-388` already sets `REQ_NOWAIT` and
`REQ_POLLED` independently — the correct pattern this patch brings to
iomap.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
### Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
**Record:** **YES.** Current code at `fs/iomap/direct-io.c:76-77` calls
`bio_set_polled(bio, iocb)`. `bio_set_polled()` at
`include/linux/bio.h:688-693` still sets `REQ_NOWAIT` when `IOCB_NOWAIT`
is set. Polled-IO infrastructure present since at least 6.18 branch
(xfs/ext4 `.iopoll` handlers exist).
### Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
**Record:** Expected **clean apply**. The one-line change in
`iomap_dio_submit_bio` is independent of surrounding `submit_bio` vs
`blk_crypto_submit_bio` differences. Removing unused `bio_set_polled()`
is safe — grep confirms only iomap used it.
### Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
**Record:** Block-layer fix (`2bc057692599`) is present in
`block/fops.c`. iomap-specific fix (`47f28b493daf`) is **NOT** present.
No alternate fix found.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
**Record:** **Filesystem I/O (iomap direct-I/O)** — **IMPORTANT/CORE-
adjacent**. Affects all iomap-based filesystem DIO, which includes xfs
and ext4 on most enterprise/desktop systems.
### Step 7.2: ASSESS SUBSYSTEM ACTIVITY
**Record:** iomap is mature and actively used. Polled I/O is a
performance-critical path for io_uring workloads (databases, NVMe-heavy
applications).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: DETERMINE WHO IS AFFECTED
**Record:** Users of **io_uring polled I/O** (`IORING_SETUP_IOPOLL`)
with **O_DIRECT** on **iomap filesystems** (xfs, ext4, f2fs, gfs2,
zonefs). Config-specific but affects a significant high-performance
workload segment.
### Step 8.2: DETERMINE THE TRIGGER CONDITIONS
**Record:** `IOCB_HIPRI` set (IOPOLL) on async DIO through iomap. Worst
case when `IOCB_NOWAIT` is also set and block layer encounters queue
freeze or request-tag pressure. Trigger is realistic for io_uring
nonblock + IOPOLL combinations.
### Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
**Record:** Spurious `-EAGAIN` / I/O stalls / failure to make progress
on polled filesystem DIO. Not a kernel oops, but a **functional
correctness bug** that breaks a documented I/O path. Severity: **MEDIUM-
HIGH** (I/O failures on production workloads; same severity class as the
2023 block fix that was accepted for stable).
### Step 8.4: CALCULATE RISK-BENEFIT RATIO
**Record:**
- **Benefit:** HIGH for io_uring + filesystem DIO users; completes a fix
already applied to block devices
- **Risk:** VERY LOW — 1-line behavioral fix, dead-code removal, mirrors
proven block-layer pattern
- **Ratio:** Strong benefit, minimal risk
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: COMPILE THE EVIDENCE
**FOR backport:**
- Buggy code confirmed present in 6.18.43
- Companion to block-layer fix already in this tree since 2023
- Affects major filesystems (xfs, ext4) via io_uring IOPOLL
- Small (16 lines), maintainer-authored, obviously correct
- Prevents incorrect `REQ_NOWAIT` on non-idempotent filesystem writes
- Same failure mode as documented in `2bc057692599`: repeated `-EAGAIN`,
no progress
**AGAINST backport:**
- No explicit crash report, syzbot, or user bugzilla reference
- Impact limited to polled + (optionally) nowait filesystem DIO path
- Not a security or data-corruption fix with demonstrated exploit
**UNRESOLVED:**
- Exact date iomap started using `bio_set_polled` (shallow repo);
kernel.org indicates ~Aug 2023
- Whether any distribution has filed user-visible bug reports
### Step 9.2: STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — mirrors accepted block fix;
maintainer-applied
2. Fixes a real bug affecting users? **PASS** — incorrect flag
propagation on reachable I/O path
3. Important issue? **PASS** — I/O failures / stalls on io_uring polled
filesystem DIO (MEDIUM-HIGH)
4. Small and contained? **PASS** — 16 lines, 2 files
5. No new features or APIs? **PASS** — flag-handling correction only
6. Can apply to local tree? **PASS** — buggy code present, clean apply
expected
### Step 9.3: EXCEPTION CATEGORIES
**Record:** None apply directly (not device ID, quirk, DT, build, or
docs). Standard bug fix.
### Step 9.4: DECISION RATIONALE
This patch completes a fix that was applied to the block-device
direct-I/O path in 2023 but was never carried to the iomap filesystem
DIO path. The buggy code is present in Linux 6.18.43. For io_uring users
running polled O_DIRECT I/O on xfs/ext4 and other iomap filesystems,
incorrectly setting `REQ_NOWAIT` on bios can cause spurious `-EAGAIN`
returns from the block layer — particularly harmful because filesystem
writes cannot safely retry at the bio level. The fix is tiny, low-risk,
and directly analogous to an already-stable fix.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from provided commit message;
fetched spinics.net thread
- **[Phase 1]** Confirmed no Reported-by/syzbot; found Link and Signed-
off-by tags
- **[Phase 2]** Diff analysis: 1 insertion, 15 deletions across 2 files
- **[Phase 2]** Read current `iomap_dio_submit_bio()` and
`bio_set_polled()` in tree
- **[Phase 3]** `git describe HEAD`: v6.18.43; `make kernelversion`
equivalent from Makefile: 6.18.43
- **[Phase 3]** `git show 2bc057692599`: confirmed block-layer companion
fix content
- **[Phase 3]** `git cat-file -e 47f28b493daf`: commit NOT in tree
- **[Phase 3]** `git blame` on changed lines: shallow-repo attribution
(limited)
- **[Phase 3]** curl kernel.org log for `fs/iomap/direct-io.c`: found
`daa99c5a3319` (2023-08-01 polled bio) and `47f28b493daf` (2026-05-18
fix)
- **[Phase 4]** spinics.net msg338671.html: original patch thread
fetched
- **[Phase 4]** spinics.net msg338717.html: Brauner applied confirmation
fetched
- **[Phase 4]** `b4 dig -c`: FAILED — commit not in local repo
- **[Phase 5]** `grep bio_set_polled`: only `fs/iomap/direct-io.c` +
`include/linux/bio.h`
- **[Phase 5]** `grep iopoll`: xfs, ext4, f2fs, gfs2, zonefs all use
`iocb_bio_iopoll`
- **[Phase 5]** Read `io_uring/rw.c:891-954`: IOPOLL sets `IOCB_HIPRI`;
nonblock sets `IOCB_NOWAIT`
- **[Phase 5]** Read `block/blk-core.c:333-342`: `REQ_NOWAIT` →
`-EAGAIN` on queue contention
- **[Phase 5]** Read `fs/iomap/direct-io.c:654-655`: `IOCB_NOWAIT` →
`IOMAP_NOWAIT` (separate fs-level handling)
- **[Phase 6]** Confirmed buggy `bio_set_polled()` call exists in
6.18.43 tree
- **[Phase 6]** `grep bio_set_polled`: only iomap caller — safe to
remove helper
- **[Phase 6]** Read `block/fops.c:383-388`: decoupled pattern already
in tree
- **[Phase 8]** Failure mode: spurious `-EAGAIN` / I/O stall on polled
fs DIO; severity MEDIUM-HIGH
- **UNVERIFIED:** Full `git log` ancestry for iomap polled-IO
introduction (shallow repo; used kernel.org instead)
- **UNVERIFIED:** Whether 6.18.y already has a different backport of
this fix (no evidence found)
**YES**The hung `git log HEAD` check didn’t finish — the shallow 6.18.43
checkout made full ancestry walks impractical. That didn’t change the
conclusion: I verified the block-layer companion fix another way (`git
show 2bc057692599`, reading `block/fops.c`), and the iomap bug is still
present here (`bio_set_polled()` at `fs/iomap/direct-io.c:77`).
**Verdict for Linux 6.18.43:** this commit should be backported. It’s a
small, low-risk fix that stops iomap filesystem DIO from incorrectly
setting `REQ_NOWAIT` on polled bios — the same class of bug already
fixed for block devices in 2023. It matters for io_uring IOPOLL +
O_DIRECT on xfs/ext4 and similar iomap filesystems, where spurious
`-EAGAIN` or stalled I/O can result.
**YES**
fs/iomap/direct-io.c | 2 +-
include/linux/bio.h | 14 --------------
2 files changed, 1 insertion(+), 15 deletions(-)
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index e73c71f39bd45..92f32e02f77f4 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -74,7 +74,7 @@ static void iomap_dio_submit_bio(const struct iomap_iter *iter,
/* Sync dio can't be polled reliably */
if ((iocb->ki_flags & IOCB_HIPRI) && !is_sync_kiocb(iocb)) {
- bio_set_polled(bio, iocb);
+ bio->bi_opf |= REQ_POLLED;
WRITE_ONCE(iocb->private, bio);
}
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 16c1c85613b76..9a15f90359ade 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -678,20 +678,6 @@ static inline bool bioset_initialized(struct bio_set *bs)
return bs->bio_slab != NULL;
}
-/*
- * Mark a bio as polled. Note that for async polled IO, the caller must
- * expect -EWOULDBLOCK if we cannot allocate a request (or other resources).
- * We cannot block waiting for requests on polled IO, as those completions
- * must be found by the caller. This is different than IRQ driven IO, where
- * it's safe to wait for IO to complete.
- */
-static inline void bio_set_polled(struct bio *bio, struct kiocb *kiocb)
-{
- bio->bi_opf |= REQ_POLLED;
- if (kiocb->ki_flags & IOCB_NOWAIT)
- bio->bi_opf |= REQ_NOWAIT;
-}
-
static inline void bio_clear_polled(struct bio *bio)
{
bio->bi_opf &= ~REQ_POLLED;
--
2.53.0