| From: Sergey Senozhatsky <senozhatsky@chromium.org> |
| Subject: zram: add recompression algorithm sysfs knob |
| Date: Wed, 9 Nov 2022 20:50:36 +0900 |
| |
| Introduce recomp_algorithm sysfs knob that controls secondary algorithm |
| selection used for recompression. |
| |
| We will support up to 3 secondary compression algorithms which are sorted |
| in order of their priority. To select an algorithm user has to provide |
| its name and priority: |
| |
| echo "algo=zstd priority=1" > /sys/block/zramX/recomp_algorithm |
| echo "algo=deflate priority=2" > /sys/block/zramX/recomp_algorithm |
| |
| During recompression zram iterates through the list of registered |
| secondary algorithms in order of their priorities. |
| |
| We also have a short version for cases when there is only |
| one secondary compression algorithm: |
| |
| echo "algo=zstd" > /sys/block/zramX/recomp_algorithm |
| |
| This will register zstd as the secondary algorithm with priority 1. |
| |
| Link: https://lkml.kernel.org/r/20221109115047.2921851-3-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 | 124 +++++++++++++++++++++++++++----- |
| 1 file changed, 105 insertions(+), 19 deletions(-) |
| |
| --- a/drivers/block/zram/zram_drv.c~zram-add-recompression-algorithm-sysfs-knob |
| +++ a/drivers/block/zram/zram_drv.c |
| @@ -997,31 +997,28 @@ static ssize_t max_comp_streams_store(st |
| return len; |
| } |
| |
| -static ssize_t comp_algorithm_show(struct device *dev, |
| - struct device_attribute *attr, char *buf) |
| +static void comp_algorithm_set(struct zram *zram, u32 prio, const char *alg) |
| { |
| - size_t sz; |
| - struct zram *zram = dev_to_zram(dev); |
| + /* Do not free statically defined compression algorithms */ |
| + if (zram->comp_algs[prio] != default_compressor) |
| + kfree(zram->comp_algs[prio]); |
| + |
| + zram->comp_algs[prio] = alg; |
| +} |
| + |
| +static ssize_t __comp_algorithm_show(struct zram *zram, u32 prio, char *buf) |
| +{ |
| + ssize_t sz; |
| |
| down_read(&zram->init_lock); |
| - sz = zcomp_available_show(zram->comp_algs[ZRAM_PRIMARY_COMP], buf); |
| + sz = zcomp_available_show(zram->comp_algs[prio], buf); |
| up_read(&zram->init_lock); |
| |
| return sz; |
| } |
| |
| -static void comp_algorithm_set(struct zram *zram, u32 prio, const char *alg) |
| -{ |
| - /* Do not kfree() algs that we didn't allocate, IOW the default ones */ |
| - if (zram->comp_algs[prio] != default_compressor) |
| - kfree(zram->comp_algs[prio]); |
| - zram->comp_algs[prio] = alg; |
| -} |
| - |
| -static ssize_t comp_algorithm_store(struct device *dev, |
| - struct device_attribute *attr, const char *buf, size_t len) |
| +static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf) |
| { |
| - struct zram *zram = dev_to_zram(dev); |
| char *compressor; |
| size_t sz; |
| |
| @@ -1050,11 +1047,94 @@ static ssize_t comp_algorithm_store(stru |
| return -EBUSY; |
| } |
| |
| - comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, compressor); |
| + comp_algorithm_set(zram, prio, compressor); |
| up_write(&zram->init_lock); |
| - return len; |
| + return 0; |
| +} |
| + |
| +static ssize_t comp_algorithm_show(struct device *dev, |
| + struct device_attribute *attr, |
| + char *buf) |
| +{ |
| + struct zram *zram = dev_to_zram(dev); |
| + |
| + return __comp_algorithm_show(zram, ZRAM_PRIMARY_COMP, buf); |
| +} |
| + |
| +static ssize_t comp_algorithm_store(struct device *dev, |
| + struct device_attribute *attr, |
| + const char *buf, |
| + size_t len) |
| +{ |
| + struct zram *zram = dev_to_zram(dev); |
| + int ret; |
| + |
| + ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, buf); |
| + return ret ? ret : len; |
| } |
| |
| +#ifdef CONFIG_ZRAM_MULTI_COMP |
| +static ssize_t recomp_algorithm_show(struct device *dev, |
| + struct device_attribute *attr, |
| + char *buf) |
| +{ |
| + struct zram *zram = dev_to_zram(dev); |
| + ssize_t sz = 0; |
| + u32 prio; |
| + |
| + for (prio = ZRAM_SECONDARY_COMP; prio < ZRAM_MAX_COMPS; prio++) { |
| + if (!zram->comp_algs[prio]) |
| + continue; |
| + |
| + sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2, "#%d: ", prio); |
| + sz += __comp_algorithm_show(zram, prio, buf + sz); |
| + } |
| + |
| + return sz; |
| +} |
| + |
| +static ssize_t recomp_algorithm_store(struct device *dev, |
| + struct device_attribute *attr, |
| + const char *buf, |
| + size_t len) |
| +{ |
| + struct zram *zram = dev_to_zram(dev); |
| + int prio = ZRAM_SECONDARY_COMP; |
| + char *args, *param, *val; |
| + char *alg = NULL; |
| + int ret; |
| + |
| + args = skip_spaces(buf); |
| + while (*args) { |
| + args = next_arg(args, ¶m, &val); |
| + |
| + if (!*val) |
| + return -EINVAL; |
| + |
| + if (!strcmp(param, "algo")) { |
| + alg = val; |
| + continue; |
| + } |
| + |
| + if (!strcmp(param, "priority")) { |
| + ret = kstrtoint(val, 10, &prio); |
| + if (ret) |
| + return ret; |
| + continue; |
| + } |
| + } |
| + |
| + if (!alg) |
| + return -EINVAL; |
| + |
| + if (prio < ZRAM_SECONDARY_COMP || prio >= ZRAM_MAX_COMPS) |
| + return -EINVAL; |
| + |
| + ret = __comp_algorithm_store(zram, prio, alg); |
| + return ret ? ret : len; |
| +} |
| +#endif |
| + |
| static ssize_t compact_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t len) |
| { |
| @@ -1895,6 +1975,9 @@ static DEVICE_ATTR_WO(writeback); |
| static DEVICE_ATTR_RW(writeback_limit); |
| static DEVICE_ATTR_RW(writeback_limit_enable); |
| #endif |
| +#ifdef CONFIG_ZRAM_MULTI_COMP |
| +static DEVICE_ATTR_RW(recomp_algorithm); |
| +#endif |
| |
| static struct attribute *zram_disk_attrs[] = { |
| &dev_attr_disksize.attr, |
| @@ -1918,6 +2001,9 @@ static struct attribute *zram_disk_attrs |
| &dev_attr_bd_stat.attr, |
| #endif |
| &dev_attr_debug_stat.attr, |
| +#ifdef CONFIG_ZRAM_MULTI_COMP |
| + &dev_attr_recomp_algorithm.attr, |
| +#endif |
| NULL, |
| }; |
| |
| @@ -1997,7 +2083,7 @@ static int zram_add(void) |
| if (ret) |
| goto out_cleanup_disk; |
| |
| - zram->comp_algs[ZRAM_PRIMARY_COMP] = default_compressor; |
| + comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor); |
| |
| zram_debugfs_register(zram); |
| pr_info("Added device: %s\n", zram->disk->disk_name); |
| _ |