zram: add algo parameter support to zram_recompress()
authorSergey Senozhatsky <senozhatsky@chromium.org>
Wed, 9 Nov 2022 11:50:44 +0000 (20:50 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Wed, 30 Nov 2022 23:58:52 +0000 (15:58 -0800)
Recompression iterates through all the registered secondary compression
algorithms in order of their priorities so that we have higher chances of
finding the algorithm that compresses a particular page.  This, however,
may not always be best approach and sometimes we may want to limit
recompression to only one particular algorithm.  For instance, when a
higher priority algorithm uses too much power and device has a relatively
low battery level we may want to limit recompression to use only a lower
priority algorithm, which uses less power.

Introduce algo= parameter support to recompression sysfs knob so that
user-sapce can request recompression with particular algorithm only:

  echo "type=idle algo=zstd" > /sys/block/zramX/recompress

Link: https://lkml.kernel.org/r/20221109115047.2921851-11-senozhatsky@chromium.org
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Acked-by: Minchan Kim <minchan@kernel.org>
Cc: Alexey Romanov <avromanov@sberdevices.ru>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nitin Gupta <ngupta@vflare.org>
Cc: Suleiman Souhlal <suleiman@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h

index 72beb33366fb2dcfd0ccf5c570a81e8c8dc5b18f..798c421fdd364226167278bdde8b0422463ca3f5 100644 (file)
@@ -1674,6 +1674,7 @@ static int zram_recompress(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;
 
@@ -1708,6 +1709,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
                if (prio <= zram_get_priority(zram, index))
                        continue;
 
+               num_recomps++;
                zstrm = zcomp_stream_get(zram->comps[prio]);
                src = kmap_atomic(page);
                ret = zcomp_compress(zstrm, src, &comp_len_new);
@@ -1740,13 +1742,19 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
        if (!zstrm)
                return 0;
 
-       /*
-        * All 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.
-        */
        if (class_index_new >= class_index_old) {
-               zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+               /*
+                * 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.
+                *
+                * 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.
+                */
+               if (num_recomps == zram->num_active_comps - 1)
+                       zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
                return 0;
        }
 
@@ -1795,10 +1803,11 @@ static ssize_t recompress_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t len)
 {
+       u32 prio = ZRAM_SECONDARY_COMP, prio_max = ZRAM_MAX_COMPS;
        struct zram *zram = dev_to_zram(dev);
-       u32 mode = 0, threshold = 0, prio = ZRAM_SECONDARY_COMP;
        unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
-       char *args, *param, *val;
+       char *args, *param, *val, *algo = NULL;
+       u32 mode = 0, threshold = 0;
        unsigned long index;
        struct page *page;
        ssize_t ret;
@@ -1830,6 +1839,11 @@ static ssize_t recompress_store(struct device *dev,
                                return ret;
                        continue;
                }
+
+               if (!strcmp(param, "algo")) {
+                       algo = val;
+                       continue;
+               }
        }
 
        if (threshold >= PAGE_SIZE)
@@ -1841,6 +1855,26 @@ static ssize_t recompress_store(struct device *dev,
                goto release_init_lock;
        }
 
+       if (algo) {
+               bool found = false;
+
+               for (; prio < ZRAM_MAX_COMPS; prio++) {
+                       if (!zram->comp_algs[prio])
+                               continue;
+
+                       if (!strcmp(zram->comp_algs[prio], algo)) {
+                               prio_max = min(prio + 1, ZRAM_MAX_COMPS);
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       ret = -EINVAL;
+                       goto release_init_lock;
+               }
+       }
+
        page = alloc_page(GFP_KERNEL);
        if (!page) {
                ret = -ENOMEM;
@@ -1871,7 +1905,7 @@ static ssize_t recompress_store(struct device *dev,
                        goto next;
 
                err = zram_recompress(zram, index, page, threshold,
-                                     prio, ZRAM_MAX_COMPS);
+                                     prio, prio_max);
 next:
                zram_slot_unlock(zram, index);
                if (err) {
@@ -2107,6 +2141,7 @@ static void zram_destroy_comps(struct zram *zram)
                if (!comp)
                        continue;
                zcomp_destroy(comp);
+               zram->num_active_comps--;
        }
 }
 
@@ -2174,6 +2209,7 @@ static ssize_t disksize_store(struct device *dev,
                }
 
                zram->comps[prio] = comp;
+               zram->num_active_comps++;
        }
        zram->disksize = disksize;
        set_capacity_and_notify(zram->disk, zram->disksize >> SECTOR_SHIFT);
index b80faae7683543a2e9cf981980cc7405b4ab9bc4..473325415a74c8247a4e19c7ce29de9d46d100a2 100644 (file)
@@ -125,6 +125,7 @@ struct zram {
         */
        u64 disksize;   /* bytes */
        const char *comp_algs[ZRAM_MAX_COMPS];
+       s8 num_active_comps;
        /*
         * zram is claimed so open request will be failed
         */