[PATCH] mm/zswap: flush dcache in the compressed decompression path

From: Song Hu

Date: Fri Jul 10 2026 - 04:36:27 EST


Both branches of zswap_decompress() write the destination folio through a
kernel mapping: the incompressible branch via kmap_local_folio() and the
compressed branch via the crypto scatterwalk. Yet only the incompressible
branch calls flush_dcache_folio(); the compressed branch was missed. On
aliasing D-cache architectures this can leave stale cache lines visible to
userland after a zswap load.

zram flushes in the same situation (zram_bio_read()). Hoist a single
flush_dcache_folio() out of the incompressible branch so both paths are
covered.

Fixes: e2c3b6b21c77 ("mm: zswap: use SG list decompression APIs from zsmalloc")
Signed-off-by: Song Hu <husong@xxxxxxxxxx>
---
mm/zswap.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mm/zswap.c b/mm/zswap.c
index b5a17ea20237..bb0c16d102d5 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -943,7 +943,6 @@ static bool zswap_decompress(struct zswap_entry *entry, struct folio *folio)
memcpy_from_sglist(dst, input, 0, PAGE_SIZE);
dlen = PAGE_SIZE;
kunmap_local(dst);
- flush_dcache_folio(folio);
} else {
sg_init_table(&output, 1);
sg_set_folio(&output, folio, PAGE_SIZE, 0);
@@ -954,6 +953,9 @@ static bool zswap_decompress(struct zswap_entry *entry, struct folio *folio)
dlen = acomp_ctx->req->dlen;
}

+ /* Both branches write the folio through a kernel alias. */
+ flush_dcache_folio(folio);
+
zs_obj_read_sg_end(pool->zs_pool, entry->handle);
mutex_unlock(&acomp_ctx->mutex);

--
2.43.0