From: Greg Kroah-Hartman Date: Mon, 5 Jan 2026 14:01:26 +0000 (+0100) Subject: 6.18-stable patches X-Git-Tag: v6.12.64~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8598dddc78d0f58f7fa1d7a58cd421e4c6b55a32;p=thirdparty%2Fkernel%2Fstable-queue.git 6.18-stable patches added patches: erofs-fix-unexpected-eio-under-memory-pressure.patch --- diff --git a/queue-6.18/erofs-fix-unexpected-eio-under-memory-pressure.patch b/queue-6.18/erofs-fix-unexpected-eio-under-memory-pressure.patch new file mode 100644 index 0000000000..4707063fbc --- /dev/null +++ b/queue-6.18/erofs-fix-unexpected-eio-under-memory-pressure.patch @@ -0,0 +1,132 @@ +From 4012d78562193ef5eb613bad4b0c0fa187637cfe Mon Sep 17 00:00:00 2001 +From: Junbeom Yeom +Date: Fri, 19 Dec 2025 21:40:31 +0900 +Subject: erofs: fix unexpected EIO under memory pressure + +From: Junbeom Yeom + +commit 4012d78562193ef5eb613bad4b0c0fa187637cfe upstream. + +erofs readahead could fail with ENOMEM under the memory pressure because +it tries to alloc_page with GFP_NOWAIT | GFP_NORETRY, while GFP_KERNEL +for a regular read. And if readahead fails (with non-uptodate folios), +the original request will then fall back to synchronous read, and +`.read_folio()` should return appropriate errnos. + +However, in scenarios where readahead and read operations compete, +read operation could return an unintended EIO because of an incorrect +error propagation. + +To resolve this, this patch modifies the behavior so that, when the +PCL is for read(which means pcl.besteffort is true), it attempts actual +decompression instead of propagating the privios error except initial EIO. + +- Page size: 4K +- The original size of FileA: 16K +- Compress-ratio per PCL: 50% (Uncompressed 8K -> Compressed 4K) +[page0, page1] [page2, page3] +[PCL0]---------[PCL1] + +- functions declaration: + . pread(fd, buf, count, offset) + . readahead(fd, offset, count) +- Thread A tries to read the last 4K +- Thread B tries to do readahead 8K from 4K +- RA, besteffort == false +- R, besteffort == true + + + +pread(FileA, buf, 4K, 12K) + do readahead(page3) // failed with ENOMEM + wait_lock(page3) + if (!uptodate(page3)) + goto do_read + readahead(FileA, 4K, 8K) + // Here create PCL-chain like below: + // [null, page1] [page2, null] + // [PCL0:RA]-----[PCL1:RA] +... + do read(page3) // found [PCL1:RA] and add page3 into it, + // and then, change PCL1 from RA to R +... + // Now, PCL-chain is as below: + // [null, page1] [page2, page3] + // [PCL0:RA]-----[PCL1:R] + + // try to decompress PCL-chain... + z_erofs_decompress_queue + err = 0; + + // failed with ENOMEM, so page 1 + // only for RA will not be uptodated. + // it's okay. + err = decompress([PCL0:RA], err) + + // However, ENOMEM propagated to next + // PCL, even though PCL is not only + // for RA but also for R. As a result, + // it just failed with ENOMEM without + // trying any decompression, so page2 + // and page3 will not be uptodated. + ** BUG HERE ** --> err = decompress([PCL1:R], err) + + return err as ENOMEM +... + wait_lock(page3) + if (!uptodate(page3)) + return EIO <-- Return an unexpected EIO! +... + +Fixes: 2349d2fa02db ("erofs: sunset unneeded NOFAILs") +Cc: stable@vger.kernel.org +Reviewed-by: Jaewook Kim +Reviewed-by: Sungjong Seo +Signed-off-by: Junbeom Yeom +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +Reviewed-by: Gao Xiang +Signed-off-by: Gao Xiang +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/zdata.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1262,17 +1262,17 @@ static int z_erofs_parse_in_bvecs(struct + return err; + } + +-static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err) ++static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, bool eio) + { + struct erofs_sb_info *const sbi = EROFS_SB(be->sb); + struct z_erofs_pcluster *pcl = be->pcl; + unsigned int pclusterpages = z_erofs_pclusterpages(pcl); + const struct z_erofs_decompressor *decomp = + z_erofs_decomp[pcl->algorithmformat]; +- int i, j, jtop, err2; ++ bool try_free = true; ++ int i, j, jtop, err2, err = eio ? -EIO : 0; + struct page *page; + bool overlapped; +- bool try_free = true; + + mutex_lock(&pcl->lock); + be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT; +@@ -1400,12 +1400,12 @@ static int z_erofs_decompress_queue(cons + .pcl = io->head, + }; + struct z_erofs_pcluster *next; +- int err = io->eio ? -EIO : 0; ++ int err = 0; + + for (; be.pcl != Z_EROFS_PCLUSTER_TAIL; be.pcl = next) { + DBG_BUGON(!be.pcl); + next = READ_ONCE(be.pcl->next); +- err = z_erofs_decompress_pcluster(&be, err) ?: err; ++ err = z_erofs_decompress_pcluster(&be, io->eio) ?: err; + } + return err; + } diff --git a/queue-6.18/series b/queue-6.18/series index 18b2b3db62..172bfd4bca 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -302,3 +302,4 @@ drm-xe-svm-fix-a-debug-printout.patch drm-pagemap-drm-xe-ensure-that-the-devmem-allocation-is-idle-before-use.patch drm-nouveau-dispnv50-don-t-call-drm_atomic_get_crtc_state-in-prepare_fb.patch drm-imagination-disallow-exporting-of-pm-fw-protected-objects.patch +erofs-fix-unexpected-eio-under-memory-pressure.patch