From: Greg Kroah-Hartman Date: Sun, 25 Feb 2024 10:39:13 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v4.19.308~75 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6d84fad5c58dc88f88b93a4faba6c4e8c7713003;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: erofs-fix-lz4-inplace-decompression.patch --- diff --git a/queue-5.15/erofs-fix-lz4-inplace-decompression.patch b/queue-5.15/erofs-fix-lz4-inplace-decompression.patch new file mode 100644 index 00000000000..f2af10ebffd --- /dev/null +++ b/queue-5.15/erofs-fix-lz4-inplace-decompression.patch @@ -0,0 +1,137 @@ +From 3c12466b6b7bf1e56f9b32c366a3d83d87afb4de Mon Sep 17 00:00:00 2001 +From: Gao Xiang +Date: Wed, 6 Dec 2023 12:55:34 +0800 +Subject: erofs: fix lz4 inplace decompression + +From: Gao Xiang + +commit 3c12466b6b7bf1e56f9b32c366a3d83d87afb4de upstream. + +Currently EROFS can map another compressed buffer for inplace +decompression, that was used to handle the cases that some pages of +compressed data are actually not in-place I/O. + +However, like most simple LZ77 algorithms, LZ4 expects the compressed +data is arranged at the end of the decompressed buffer and it +explicitly uses memmove() to handle overlapping: + __________________________________________________________ + |_ direction of decompression --> ____ |_ compressed data _| + +Although EROFS arranges compressed data like this, it typically maps two +individual virtual buffers so the relative order is uncertain. +Previously, it was hardly observed since LZ4 only uses memmove() for +short overlapped literals and x86/arm64 memmove implementations seem to +completely cover it up and they don't have this issue. Juhyung reported +that EROFS data corruption can be found on a new Intel x86 processor. +After some analysis, it seems that recent x86 processors with the new +FSRM feature expose this issue with "rep movsb". + +Let's strictly use the decompressed buffer for lz4 inplace +decompression for now. Later, as an useful improvement, we could try +to tie up these two buffers together in the correct order. + +Reported-and-tested-by: Juhyung Park +Closes: https://lore.kernel.org/r/CAD14+f2AVKf8Fa2OO1aAUdDNTDsVzzR6ctU_oJSmTyd6zSYR2Q@mail.gmail.com +Fixes: 0ffd71bcc3a0 ("staging: erofs: introduce LZ4 decompression inplace") +Fixes: 598162d05080 ("erofs: support decompress big pcluster for lz4 backend") +Cc: stable # 5.4+ +Tested-by: Yifan Zhao +Signed-off-by: Gao Xiang +Link: https://lore.kernel.org/r/20231206045534.3920847-1-hsiangkao@linux.alibaba.com +Signed-off-by: Greg Kroah-Hartman +--- + fs/erofs/decompressor.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +--- a/fs/erofs/decompressor.c ++++ b/fs/erofs/decompressor.c +@@ -124,11 +124,11 @@ static int z_erofs_lz4_prepare_destpages + } + + static void *z_erofs_handle_inplace_io(struct z_erofs_decompress_req *rq, +- void *inpage, unsigned int *inputmargin, int *maptype, +- bool support_0padding) ++ void *inpage, void *out, unsigned int *inputmargin, int *maptype, ++ bool support_0padding) + { + unsigned int nrpages_in, nrpages_out; +- unsigned int ofull, oend, inputsize, total, i, j; ++ unsigned int ofull, oend, inputsize, total, i; + struct page **in; + void *src, *tmp; + +@@ -143,12 +143,13 @@ static void *z_erofs_handle_inplace_io(s + ofull - oend < LZ4_DECOMPRESS_INPLACE_MARGIN(inputsize)) + goto docopy; + +- for (i = 0; i < nrpages_in; ++i) { +- DBG_BUGON(rq->in[i] == NULL); +- for (j = 0; j < nrpages_out - nrpages_in + i; ++j) +- if (rq->out[j] == rq->in[i]) +- goto docopy; +- } ++ for (i = 0; i < nrpages_in; ++i) ++ if (rq->out[nrpages_out - nrpages_in + i] != ++ rq->in[i]) ++ goto docopy; ++ kunmap_atomic(inpage); ++ *maptype = 3; ++ return out + ((nrpages_out - nrpages_in) << PAGE_SHIFT); + } + + if (nrpages_in <= 1) { +@@ -156,7 +157,6 @@ static void *z_erofs_handle_inplace_io(s + return inpage; + } + kunmap_atomic(inpage); +- might_sleep(); + src = erofs_vm_map_ram(rq->in, nrpages_in); + if (!src) + return ERR_PTR(-ENOMEM); +@@ -193,10 +193,10 @@ docopy: + return src; + } + +-static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out) ++static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *dst) + { + unsigned int inputmargin; +- u8 *headpage, *src; ++ u8 *out, *headpage, *src; + bool support_0padding; + int ret, maptype; + +@@ -220,11 +220,12 @@ static int z_erofs_lz4_decompress(struct + } + + rq->inputsize -= inputmargin; +- src = z_erofs_handle_inplace_io(rq, headpage, &inputmargin, &maptype, +- support_0padding); ++ src = z_erofs_handle_inplace_io(rq, headpage, dst, &inputmargin, ++ &maptype, support_0padding); + if (IS_ERR(src)) + return PTR_ERR(src); + ++ out = dst + rq->pageofs_out; + /* legacy format could compress extra data in a pcluster. */ + if (rq->partial_decoding || !support_0padding) + ret = LZ4_decompress_safe_partial(src + inputmargin, out, +@@ -253,7 +254,7 @@ static int z_erofs_lz4_decompress(struct + vm_unmap_ram(src, PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT); + } else if (maptype == 2) { + erofs_put_pcpubuf(src); +- } else { ++ } else if (maptype != 3) { + DBG_BUGON(1); + return -EFAULT; + } +@@ -354,8 +355,7 @@ static int z_erofs_decompress_generic(st + dst_maptype = 2; + + dstmap_out: +- ret = alg->decompress(rq, dst + rq->pageofs_out); +- ++ ret = alg->decompress(rq, dst); + if (!dst_maptype) + kunmap_atomic(dst); + else if (dst_maptype == 2) diff --git a/queue-5.15/series b/queue-5.15/series index 02dc62afee4..776e9f423dd 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -74,3 +74,4 @@ virtio-blk-ensure-no-requests-in-virtqueues-before-d.patch pmdomain-mediatek-fix-race-conditions-with-genpd.patch ksmbd-free-aux-buffer-if-ksmbd_iov_pin_rsp_read-fail.patch pmdomain-renesas-r8a77980-sysc-cr7-must-be-always-on.patch +erofs-fix-lz4-inplace-decompression.patch