erofs: tidy up z_erofs_lz4_handle_overlap()

[ Upstream commit 9ae77198d4 ]

 - Add some useful comments to explain inplace I/Os and decompression;

 - Rearrange the code to get rid of one unnecessary goto.

Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Stable-dep-of: 21e161de2d ("erofs: fix unsigned underflow in z_erofs_lz4_handle_overlap()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Gao Xiang
2026-05-14 15:30:25 +02:00
committed by Greg Kroah-Hartman
parent d309d3308d
commit 24da4cc6bf
+46 -39
View File
@@ -105,44 +105,58 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
return kaddr ? 1 : 0;
}
static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
static void *z_erofs_lz4_handle_overlap(const struct z_erofs_decompress_req *rq,
void *inpage, void *out, unsigned int *inputmargin,
int *maptype, bool may_inplace)
{
unsigned int oend, omargin, total, i;
unsigned int oend, omargin, cnt, i;
struct page **in;
void *src, *tmp;
if (rq->inplace_io) {
oend = rq->pageofs_out + rq->outputsize;
omargin = PAGE_ALIGN(oend) - oend;
if (rq->partial_decoding || !may_inplace ||
omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize))
goto docopy;
void *src;
/*
* If in-place I/O isn't used, for example, the bounce compressed cache
* can hold data for incomplete read requests. Just map the compressed
* buffer as well and decompress directly.
*/
if (!rq->inplace_io) {
if (rq->inpages <= 1) {
*maptype = 0;
return inpage;
}
kunmap_local(inpage);
src = erofs_vm_map_ram(rq->in, rq->inpages);
if (!src)
return ERR_PTR(-ENOMEM);
*maptype = 1;
return src;
}
/*
* Then, deal with in-place I/Os. The reasons why in-place I/O is useful
* are: (1) It minimizes memory footprint during the I/O submission,
* which is useful for slow storage (including network devices and
* low-end HDDs/eMMCs) but with a lot inflight I/Os; (2) If in-place
* decompression can also be applied, it will reuse the unique buffer so
* that no extra CPU D-cache is polluted with temporary compressed data
* for extreme performance.
*/
oend = rq->pageofs_out + rq->outputsize;
omargin = PAGE_ALIGN(oend) - oend;
if (!rq->partial_decoding && may_inplace &&
omargin >= LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize)) {
for (i = 0; i < rq->inpages; ++i)
if (rq->out[rq->outpages - rq->inpages + i] !=
rq->in[i])
goto docopy;
kunmap_local(inpage);
*maptype = 3;
return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
break;
if (i >= rq->inpages) {
kunmap_local(inpage);
*maptype = 3;
return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
}
}
if (rq->inpages <= 1) {
*maptype = 0;
return inpage;
}
kunmap_local(inpage);
src = erofs_vm_map_ram(rq->in, rq->inpages);
if (!src)
return ERR_PTR(-ENOMEM);
*maptype = 1;
return src;
docopy:
/* Or copy compressed data which can be overlapped to per-CPU buffer */
in = rq->in;
/*
* If in-place decompression can't be applied, copy compressed data that
* may potentially overlap during decompression to a per-CPU buffer.
*/
src = z_erofs_get_gbuf(rq->inpages);
if (!src) {
DBG_BUGON(1);
@@ -150,20 +164,13 @@ docopy:
return ERR_PTR(-EFAULT);
}
tmp = src;
total = rq->inputsize;
while (total) {
unsigned int page_copycnt =
min_t(unsigned int, total, PAGE_SIZE - *inputmargin);
for (i = 0, in = rq->in; i < rq->inputsize; i += cnt, ++in) {
cnt = min_t(u32, rq->inputsize - i, PAGE_SIZE - *inputmargin);
if (!inpage)
inpage = kmap_local_page(*in);
memcpy(tmp, inpage + *inputmargin, page_copycnt);
memcpy(src + i, inpage + *inputmargin, cnt);
kunmap_local(inpage);
inpage = NULL;
tmp += page_copycnt;
total -= page_copycnt;
++in;
*inputmargin = 0;
}
*maptype = 2;