zram: rework recompression loop
authorSergey Senozhatsky <senozhatsky@chromium.org>
Mon, 3 Mar 2025 02:03:19 +0000 (11:03 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 17 Mar 2025 05:06:35 +0000 (22:06 -0700)
This reworks recompression loop handling:

- set a rule that stream-put NULLs the stream pointer If the loop
  returns with a non-NULL stream then it's a successful recompression,
  otherwise the stream should always be NULL.

- do not count the number of recompressions Mark object as
  incompressible as soon as the algorithm with the highest priority failed
  to compress that object.

- count compression errors as resource usage Even if compression has
  failed, we still need to bump num_recomp_pages counter.

Link: https://lkml.kernel.org/r/20250303022425.285971-11-senozhatsky@chromium.org
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Hillf Danton <hdanton@sina.com>
Cc: Kairui Song <ryncsn@gmail.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
drivers/block/zram/zram_drv.c

index 6dee885bef9b7786529037c947e5957f24b3127d..bb88b63d193b6bd28a32f9fecb5cd87a8b7b14f6 100644 (file)
@@ -1888,9 +1888,8 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
        unsigned int comp_len_new;
        unsigned int class_index_old;
        unsigned int class_index_new;
-       u32 num_recomps = 0;
        void *src, *dst;
-       int ret;
+       int ret = 0;
 
        handle_old = zram_get_handle(zram, index);
        if (!handle_old)
@@ -1933,7 +1932,6 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
                if (!zram->comps[prio])
                        continue;
 
-               num_recomps++;
                zstrm = zcomp_stream_get(zram->comps[prio]);
                src = kmap_local_page(page);
                ret = zcomp_compress(zram->comps[prio], zstrm,
@@ -1942,7 +1940,8 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
 
                if (ret) {
                        zcomp_stream_put(zstrm);
-                       return ret;
+                       zstrm = NULL;
+                       break;
                }
 
                class_index_new = zs_lookup_class_index(zram->mem_pool,
@@ -1952,6 +1951,7 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
                if (class_index_new >= class_index_old ||
                    (threshold && comp_len_new >= threshold)) {
                        zcomp_stream_put(zstrm);
+                       zstrm = NULL;
                        continue;
                }
 
@@ -1959,14 +1959,6 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
                break;
        }
 
-       /*
-        * We did not try to recompress, e.g. when we have only one
-        * secondary algorithm and the page is already recompressed
-        * using that algorithm
-        */
-       if (!zstrm)
-               return 0;
-
        /*
         * Decrement the limit (if set) on pages we can recompress, even
         * when current recompression was unsuccessful or did not compress
@@ -1976,38 +1968,32 @@ static int recompress_slot(struct zram *zram, u32 index, struct page *page,
        if (*num_recomp_pages)
                *num_recomp_pages -= 1;
 
-       if (class_index_new >= class_index_old) {
+       /* Compression error */
+       if (ret)
+               return ret;
+
+       if (!zstrm) {
                /*
                 * Secondary algorithms failed to re-compress the page
-                * in a way that would save memory, mark the object as
-                * incompressible so that we will not try to compress
-                * it again.
+                * in a way that would save memory.
                 *
-                * We need to make sure that all secondary algorithms have
-                * failed, so we test if the number of recompressions matches
-                * the number of active secondary algorithms.
+                * Mark the object incompressible if the max-priority
+                * algorithm couldn't re-compress it.
                 */
-               if (num_recomps == zram->num_active_comps - 1)
-                       zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+               if (prio < zram->num_active_comps)
+                       return 0;
+               zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
                return 0;
        }
 
-       /* Successful recompression but above threshold */
-       if (threshold && comp_len_new >= threshold)
-               return 0;
-
        /*
-        * No direct reclaim (slow path) for handle allocation and no
-        * re-compression attempt (unlike in zram_write_bvec()) since
-        * we already have stored that object in zsmalloc. If we cannot
-        * alloc memory for recompressed object then we bail out and
-        * simply keep the old (existing) object in zsmalloc.
+        * We are holding per-CPU stream mutex and entry lock so better
+        * avoid direct reclaim.  Allocation error is not fatal since
+        * we still have the old object in the mem_pool.
         */
        handle_new = zs_malloc(zram->mem_pool, comp_len_new,
-                              __GFP_KSWAPD_RECLAIM |
-                              __GFP_NOWARN |
-                              __GFP_HIGHMEM |
-                              __GFP_MOVABLE);
+                              GFP_NOIO | __GFP_NOWARN |
+                              __GFP_HIGHMEM | __GFP_MOVABLE);
        if (IS_ERR_VALUE(handle_new)) {
                zcomp_stream_put(zstrm);
                return PTR_ERR((void *)handle_new);