]> Gentwo Git Trees - linux/.git/commitdiff
erofs: tidy up z_erofs_lz4_handle_overlap()
authorGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 25 Nov 2025 17:01:02 +0000 (01:01 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 28 Nov 2025 13:59:51 +0000 (21:59 +0800)
 - 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>
fs/erofs/decompressor.c

index 354762c9723f94b1a532d93ec83cd8e37ba7772b..2f4cef67cf6403fce99d18c9dd29c82e32b490a5 100644 (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);
-       }
-
-       if (rq->inpages <= 1) {
-               *maptype = 0;
-               return inpage;
+                               break;
+               if (i >= rq->inpages) {
+                       kunmap_local(inpage);
+                       *maptype = 3;
+                       return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
+               }
        }
-       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 @@ static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
                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;