[PATCH 2/3] mm/swap: account synchronous swap reads as memory stall

From: Kairui Song via B4 Relay

Date: Thu Oct 29 2026 - 14:35:38 EST


From: Josef Bacik <josef@xxxxxxxxxxxxxx>

Swap-ins from SWP_SYNCHRONOUS_IO devices such as zram are no longer
counted in PSI memory pressure or in the swapin and thrashing delays of
delay accounting. Refaults of the workingset from zram, the main input
to userspace OOM handlers like lmkd and systemd-oomd on zram systems,
become invisible in /proc/pressure/memory.

swap_read_folio() opens the accounting window with
psi_memstall_enter() and delayacct_swapin_start() and, per its comment,
means to count the submission time. For synchronous devices the
submission is the entire read: swap_bdev_submit_read() does
submit_bio_wait() and completes the folio. Since reads are batched in
a swap_iocb, swap_read_folio() only queues the folio with
swap_add_folio(), and the bio is submitted later by swap_read_submit()
in the caller, e.g. swapin_sync(), after the window has been closed.
By then the folio is uptodate and unlocked, so the fault does not wait
on the folio lock either and the read time is not counted anywhere.

Found by code inspection; not reproduced.

Fix by submitting synchronous reads from within swap_read_folio(), as
was done before the batching, rather than from the caller. This gives
up batching of readahead for synchronous devices, which do their I/O
inline anyway, in exchange for keeping the accounting simple and in one
place.

Fixes: dda8fb68b590 ("mm/swap: also use struct swap_iocb for block I/O")
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
Signed-off-by: Kairui Song <kasong@xxxxxxxxxxx>
---
mm/page_io.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/mm/page_io.c b/mm/page_io.c
index 65681eed9c80..83ed0246ebfc 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -500,6 +500,13 @@ void swap_read_folio(struct swap_io_ctx *ctx, struct folio *folio)
zswap_folio_swapin(folio);
swap_add_folio(ctx, folio, READ);

+ /*
+ * Synchronous devices do the whole read at submission time, submit
+ * it here so that it is accounted as memory stall and delay.
+ */
+ if (synchronous)
+ swap_read_submit(ctx);
+
finish:
if (workingset) {
delayacct_thrashing_end(&in_thrashing);

--
2.56.0