2024-05-03 09:18:48

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 00/14] zram: convert to custom comp API and allow algorithms configuration

This patch set moves zram from crypto API to a custom compression
API which allows us to tune and configure compression algorithms,
something that crypto API, unfortunately, doesn't support. Basically,
this seroes brings back the bits of comp "backend" code that we had
many years ago. This means that if we want zram to support new
compression algorithms we need to implement corresponding backends.

Currently, zram supports a pretty decent number of comp backends:
lzo, lzorle, lz4, lz4hc, deflate, zstd

At this point we handle 2 parameters: a compression level and
a pre-trained compression dictionary. Which seems like a good enough
start. The list will be extended in the future.

Examples:

- changes default compression level
echo "algo=zstd level=11" > /sys/block/zram0/comp_algorithm

- passes path to a pre-trained dictionary
echo "algo=zstd dict=/etc/dictionary" > /sys/block/zram0/comp_algorithm

TEST
====

using default zstd
/sys/block/zram0/mm_stat
1750315008 504602831 514256896 0 514256896 1 0 34204 34204

using zstd level=7 dict=/etc/dictionary
/sys/block/zram0/mm_stat
1750310912 432540606 441712640 0 441712640 1 0 34187 34187

Sergey Senozhatsky (14):
zram: move from crypto API to custom comp backends API
zram: add lzo and lzorle compression backends support
zram: add lz4 compression backend support
zram: add lz4hc compression backend support
zram: add zstd compression backend support
zram: pass estimated src size hint to zstd
zram: add zlib compression backend support
zram: check that backends array has at least one backend
zram: introduce zcomp_config structure
zram: extend comp_algorithm attr write handling
zram: support compression level comp config
zram: add support for dict comp config
zram: add dictionary support to zstd backend
Documentation/zram: add documentation for algorithm parameters

Documentation/admin-guide/blockdev/zram.rst | 38 ++++-
drivers/block/zram/Kconfig | 69 ++++++--
drivers/block/zram/Makefile | 7 +
drivers/block/zram/backend_deflate.c | 133 +++++++++++++++
drivers/block/zram/backend_deflate.h | 10 ++
drivers/block/zram/backend_lz4.c | 47 ++++++
drivers/block/zram/backend_lz4.h | 10 ++
drivers/block/zram/backend_lz4hc.c | 74 +++++++++
drivers/block/zram/backend_lz4hc.h | 10 ++
drivers/block/zram/backend_lzo.c | 44 +++++
drivers/block/zram/backend_lzo.h | 10 ++
drivers/block/zram/backend_lzorle.c | 44 +++++
drivers/block/zram/backend_lzorle.h | 10 ++
drivers/block/zram/backend_zstd.c | 174 ++++++++++++++++++++
drivers/block/zram/backend_zstd.h | 10 ++
drivers/block/zram/zcomp.c | 145 ++++++++--------
drivers/block/zram/zcomp.h | 38 ++++-
drivers/block/zram/zram_drv.c | 110 ++++++++++++-
drivers/block/zram/zram_drv.h | 1 +
19 files changed, 870 insertions(+), 114 deletions(-)
create mode 100644 drivers/block/zram/backend_deflate.c
create mode 100644 drivers/block/zram/backend_deflate.h
create mode 100644 drivers/block/zram/backend_lz4.c
create mode 100644 drivers/block/zram/backend_lz4.h
create mode 100644 drivers/block/zram/backend_lz4hc.c
create mode 100644 drivers/block/zram/backend_lz4hc.h
create mode 100644 drivers/block/zram/backend_lzo.c
create mode 100644 drivers/block/zram/backend_lzo.h
create mode 100644 drivers/block/zram/backend_lzorle.c
create mode 100644 drivers/block/zram/backend_lzorle.h
create mode 100644 drivers/block/zram/backend_zstd.c
create mode 100644 drivers/block/zram/backend_zstd.h

--
2.45.0.rc1.225.g2a3ae87e7f-goog



2024-05-03 09:19:13

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 02/14] zram: add lzo and lzorle compression backends support

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 24 ++++++++++++++++
drivers/block/zram/Makefile | 3 ++
drivers/block/zram/backend_lzo.c | 44 +++++++++++++++++++++++++++++
drivers/block/zram/backend_lzo.h | 10 +++++++
drivers/block/zram/backend_lzorle.c | 44 +++++++++++++++++++++++++++++
drivers/block/zram/backend_lzorle.h | 10 +++++++
drivers/block/zram/zcomp.c | 7 +++++
7 files changed, 142 insertions(+)
create mode 100644 drivers/block/zram/backend_lzo.c
create mode 100644 drivers/block/zram/backend_lzo.h
create mode 100644 drivers/block/zram/backend_lzorle.c
create mode 100644 drivers/block/zram/backend_lzorle.h

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 8ecb74f83a5e..a1fe8b989ee2 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -14,8 +14,32 @@ config ZRAM

See Documentation/admin-guide/blockdev/zram.rst for more information.

+config ZRAM_BACKEND_LZO
+ bool "lzo and lzo-rle compression support"
+ depends on ZRAM
+ default n
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
+
+choice
+ prompt "Default zram compressor"
+ default ZRAM_DEF_COMP_LZORLE
+ depends on ZRAM
+
+config ZRAM_DEF_COMP_LZORLE
+ bool "lzo-rle"
+ depends on ZRAM_BACKEND_LZO
+
+config ZRAM_DEF_COMP_LZO
+ bool "lzo"
+ depends on ZRAM_BACKEND_LZO
+
+endchoice
+
config ZRAM_DEF_COMP
string
+ default "lzo-rle" if ZRAM_DEF_COMP_LZORLE
+ default "lzo" if ZRAM_DEF_COMP_LZO
default "unset-value"

config ZRAM_WRITEBACK
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index de9e457907b1..2dcbc9b75d91 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
+
zram-y := zcomp.o zram_drv.o

obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/block/zram/backend_lzo.c b/drivers/block/zram/backend_lzo.c
new file mode 100644
index 000000000000..d9a003fbb360
--- /dev/null
+++ b/drivers/block/zram/backend_lzo.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+
+#include "backend_lzo.h"
+
+static void *lzo_create(void)
+{
+ return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void lzo_destroy(void *ctx)
+{
+ kfree(ctx);
+}
+
+static int lzo_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ int ret;
+
+ ret = lzo1x_1_compress(src, PAGE_SIZE, dst, dst_len, ctx);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+static int lzo_decompress(void *ctx, const unsigned char *src, size_t src_len,
+ unsigned char *dst)
+{
+ size_t dst_len = PAGE_SIZE;
+ int ret;
+
+ ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+struct zcomp_backend backend_lzo = {
+ .compress = lzo_compress,
+ .decompress = lzo_decompress,
+ .create_ctx = lzo_create,
+ .destroy_ctx = lzo_destroy,
+ .name = "lzo",
+};
diff --git a/drivers/block/zram/backend_lzo.h b/drivers/block/zram/backend_lzo.h
new file mode 100644
index 000000000000..377ccb7389e2
--- /dev/null
+++ b/drivers/block/zram/backend_lzo.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_LZO_H__
+#define __BACKEND_LZO_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_lzo;
+
+#endif /* __BACKEND_LZO_H__ */
diff --git a/drivers/block/zram/backend_lzorle.c b/drivers/block/zram/backend_lzorle.c
new file mode 100644
index 000000000000..9bf1843021b0
--- /dev/null
+++ b/drivers/block/zram/backend_lzorle.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+
+#include "backend_lzorle.h"
+
+static void *lzorle_create(void)
+{
+ return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void lzorle_destroy(void *ctx)
+{
+ kfree(ctx);
+}
+
+static int lzorle_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ int ret;
+
+ ret = lzorle1x_1_compress(src, PAGE_SIZE, dst, dst_len, ctx);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+static int lzorle_decompress(void *ctx, const unsigned char *src,
+ size_t src_len, unsigned char *dst)
+{
+ size_t dst_len = PAGE_SIZE;
+ int ret;
+
+ ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len);
+ return ret == LZO_E_OK ? 0 : ret;
+}
+
+struct zcomp_backend backend_lzorle = {
+ .compress = lzorle_compress,
+ .decompress = lzorle_decompress,
+ .create_ctx = lzorle_create,
+ .destroy_ctx = lzorle_destroy,
+ .name = "lzo-rle",
+};
diff --git a/drivers/block/zram/backend_lzorle.h b/drivers/block/zram/backend_lzorle.h
new file mode 100644
index 000000000000..5c1db65a38a4
--- /dev/null
+++ b/drivers/block/zram/backend_lzorle.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_LZORLE_H__
+#define __BACKEND_LZORLE_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_lzorle;
+
+#endif /* __BACKEND_LZORLE_H__ */
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 0d0d2e6dbaa9..58fb3ac91f4b 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -15,7 +15,14 @@

#include "zcomp.h"

+#include "backend_lzo.h"
+#include "backend_lzorle.h"
+
static struct zcomp_backend *backends[] = {
+#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
+ &backend_lzorle,
+ &backend_lzo,
+#endif
NULL
};

--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:19:19

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 01/14] zram: move from crypto API to custom comp backends API

Crypto API is beautiful and powerful, however, being a
generic API, it lacks support for fine-grained per-algorithm
configuration. A number of compression algorithms provide
various knobs to tune characteristics for particular data
patterns. The simplest case is "compression level". A more
complicated and interesting case is user-space trained
dictionaries (e.g. lz4 and zstd).

Moving to custom backends implementation gives us ability to
have our own minimalistic and extendable API, and algorithms
tunings becomes possible.

The list of compression backends is empty at this point,
we will add backends in the followup patches.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 39 +----------
drivers/block/zram/zcomp.c | 127 +++++++++++++---------------------
drivers/block/zram/zcomp.h | 26 +++++--
drivers/block/zram/zram_drv.c | 9 ++-
4 files changed, 73 insertions(+), 128 deletions(-)

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 7b29cce60ab2..8ecb74f83a5e 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -2,7 +2,6 @@
config ZRAM
tristate "Compressed RAM block device support"
depends on BLOCK && SYSFS && MMU
- depends on CRYPTO_LZO || CRYPTO_ZSTD || CRYPTO_LZ4 || CRYPTO_LZ4HC || CRYPTO_842
select ZSMALLOC
help
Creates virtual block devices called /dev/zramX (X = 0, 1, ...).
@@ -15,45 +14,9 @@ config ZRAM

See Documentation/admin-guide/blockdev/zram.rst for more information.

-choice
- prompt "Default zram compressor"
- default ZRAM_DEF_COMP_LZORLE
- depends on ZRAM
-
-config ZRAM_DEF_COMP_LZORLE
- bool "lzo-rle"
- depends on CRYPTO_LZO
-
-config ZRAM_DEF_COMP_ZSTD
- bool "zstd"
- depends on CRYPTO_ZSTD
-
-config ZRAM_DEF_COMP_LZ4
- bool "lz4"
- depends on CRYPTO_LZ4
-
-config ZRAM_DEF_COMP_LZO
- bool "lzo"
- depends on CRYPTO_LZO
-
-config ZRAM_DEF_COMP_LZ4HC
- bool "lz4hc"
- depends on CRYPTO_LZ4HC
-
-config ZRAM_DEF_COMP_842
- bool "842"
- depends on CRYPTO_842
-
-endchoice
-
config ZRAM_DEF_COMP
string
- default "lzo-rle" if ZRAM_DEF_COMP_LZORLE
- default "zstd" if ZRAM_DEF_COMP_ZSTD
- default "lz4" if ZRAM_DEF_COMP_LZ4
- default "lzo" if ZRAM_DEF_COMP_LZO
- default "lz4hc" if ZRAM_DEF_COMP_LZ4HC
- default "842" if ZRAM_DEF_COMP_842
+ default "unset-value"

config ZRAM_WRITEBACK
bool "Write back incompressible or idle page to backing device"
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 8237b08c49d8..0d0d2e6dbaa9 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -15,31 +15,16 @@

#include "zcomp.h"

-static const char * const backends[] = {
-#if IS_ENABLED(CONFIG_CRYPTO_LZO)
- "lzo",
- "lzo-rle",
-#endif
-#if IS_ENABLED(CONFIG_CRYPTO_LZ4)
- "lz4",
-#endif
-#if IS_ENABLED(CONFIG_CRYPTO_LZ4HC)
- "lz4hc",
-#endif
-#if IS_ENABLED(CONFIG_CRYPTO_842)
- "842",
-#endif
-#if IS_ENABLED(CONFIG_CRYPTO_ZSTD)
- "zstd",
-#endif
+static struct zcomp_backend *backends[] = {
+ NULL
};

-static void zcomp_strm_free(struct zcomp_strm *zstrm)
+static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
{
- if (!IS_ERR_OR_NULL(zstrm->tfm))
- crypto_free_comp(zstrm->tfm);
+ if (zstrm->ctx)
+ comp->backend->destroy_ctx(zstrm->ctx);
vfree(zstrm->buffer);
- zstrm->tfm = NULL;
+ zstrm->ctx = NULL;
zstrm->buffer = NULL;
}

@@ -47,60 +32,55 @@ static void zcomp_strm_free(struct zcomp_strm *zstrm)
* Initialize zcomp_strm structure with ->tfm initialized by backend, and
* ->buffer. Return a negative value on error.
*/
-static int zcomp_strm_init(struct zcomp_strm *zstrm, struct zcomp *comp)
+static int zcomp_strm_init(struct zcomp *comp, struct zcomp_strm *zstrm)
{
- zstrm->tfm = crypto_alloc_comp(comp->name, 0, 0);
+ zstrm->ctx = comp->backend->create_ctx();
+
/*
* allocate 2 pages. 1 for compressed data, plus 1 extra for the
* case when compressed size is larger than the original one
*/
zstrm->buffer = vzalloc(2 * PAGE_SIZE);
- if (IS_ERR_OR_NULL(zstrm->tfm) || !zstrm->buffer) {
- zcomp_strm_free(zstrm);
+ if (!zstrm->ctx || !zstrm->buffer) {
+ zcomp_strm_free(comp, zstrm);
return -ENOMEM;
}
return 0;
}

+static struct zcomp_backend *lookup_backend(const char *comp)
+{
+ int i = 0;
+
+ while (backends[i]) {
+ if (sysfs_streq(comp, backends[i]->name))
+ break;
+ i++;
+ }
+ return backends[i];
+}
+
bool zcomp_available_algorithm(const char *comp)
{
- /*
- * Crypto does not ignore a trailing new line symbol,
- * so make sure you don't supply a string containing
- * one.
- * This also means that we permit zcomp initialisation
- * with any compressing algorithm known to crypto api.
- */
- return crypto_has_comp(comp, 0, 0) == 1;
+ return lookup_backend(comp) != NULL;
}

/* show available compressors */
ssize_t zcomp_available_show(const char *comp, char *buf)
{
- bool known_algorithm = false;
ssize_t sz = 0;
int i;

- for (i = 0; i < ARRAY_SIZE(backends); i++) {
- if (!strcmp(comp, backends[i])) {
- known_algorithm = true;
+ for (i = 0; i < ARRAY_SIZE(backends) - 1; i++) {
+ if (!strcmp(comp, backends[i]->name)) {
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
- "[%s] ", backends[i]);
+ "[%s] ", backends[i]->name);
} else {
sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
- "%s ", backends[i]);
+ "%s ", backends[i]->name);
}
}

- /*
- * Out-of-tree module known to crypto api or a missing
- * entry in `backends'.
- */
- if (!known_algorithm && crypto_has_comp(comp, 0, 0) == 1)
- sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
- "[%s] ", comp);
-
- sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
return sz;
}

@@ -115,8 +95,8 @@ void zcomp_stream_put(struct zcomp *comp)
local_unlock(&comp->stream->lock);
}

-int zcomp_compress(struct zcomp_strm *zstrm,
- const void *src, unsigned int *dst_len)
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const void *src, unsigned int *dst_len)
{
/*
* Our dst memory (zstrm->buffer) is always `2 * PAGE_SIZE' sized
@@ -132,21 +112,19 @@ int zcomp_compress(struct zcomp_strm *zstrm,
* the dst buffer, zram_drv will take care of the fact that
* compressed buffer is too big.
*/
- *dst_len = PAGE_SIZE * 2;
+ size_t dlen = PAGE_SIZE * 2;
+ int ret;

- return crypto_comp_compress(zstrm->tfm,
- src, PAGE_SIZE,
- zstrm->buffer, dst_len);
+ ret = comp->backend->compress(zstrm->ctx, src, zstrm->buffer, &dlen);
+ if (!ret)
+ *dst_len = dlen;
+ return ret;
}

-int zcomp_decompress(struct zcomp_strm *zstrm,
- const void *src, unsigned int src_len, void *dst)
+int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const void *src, unsigned int src_len, void *dst)
{
- unsigned int dst_len = PAGE_SIZE;
-
- return crypto_comp_decompress(zstrm->tfm,
- src, src_len,
- dst, &dst_len);
+ return comp->backend->decompress(zstrm->ctx, src, src_len, dst);
}

int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node)
@@ -158,7 +136,7 @@ int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node)
zstrm = per_cpu_ptr(comp->stream, cpu);
local_lock_init(&zstrm->lock);

- ret = zcomp_strm_init(zstrm, comp);
+ ret = zcomp_strm_init(comp, zstrm);
if (ret)
pr_err("Can't allocate a compression stream\n");
return ret;
@@ -170,7 +148,7 @@ int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node)
struct zcomp_strm *zstrm;

zstrm = per_cpu_ptr(comp->stream, cpu);
- zcomp_strm_free(zstrm);
+ zcomp_strm_free(comp, zstrm);
return 0;
}

@@ -199,32 +177,21 @@ void zcomp_destroy(struct zcomp *comp)
kfree(comp);
}

-/*
- * search available compressors for requested algorithm.
- * allocate new zcomp and initialize it. return compressing
- * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
- * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
- * case of allocation error, or any other error potentially
- * returned by zcomp_init().
- */
struct zcomp *zcomp_create(const char *alg)
{
struct zcomp *comp;
int error;

- /*
- * Crypto API will execute /sbin/modprobe if the compression module
- * is not loaded yet. We must do it here, otherwise we are about to
- * call /sbin/modprobe under CPU hot-plug lock.
- */
- if (!zcomp_available_algorithm(alg))
- return ERR_PTR(-EINVAL);
-
comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
if (!comp)
return ERR_PTR(-ENOMEM);

- comp->name = alg;
+ comp->backend = lookup_backend(alg);
+ if (!comp->backend) {
+ kfree(comp);
+ return ERR_PTR(-EINVAL);
+ }
+
error = zcomp_init(comp);
if (error) {
kfree(comp);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index e9fe63da0e9b..757b85017e23 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -12,13 +12,26 @@ struct zcomp_strm {
local_lock_t lock;
/* compression/decompression buffer */
void *buffer;
- struct crypto_comp *tfm;
+ void *ctx;
+};
+
+struct zcomp_backend {
+ int (*compress)(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len);
+
+ int (*decompress)(void *ctx, const unsigned char *src, size_t src_len,
+ unsigned char *dst);
+
+ void *(*create_ctx)(void);
+ void (*destroy_ctx)(void *ctx);
+
+ const char *name;
};

/* dynamic per-device compression frontend */
struct zcomp {
struct zcomp_strm __percpu *stream;
- const char *name;
+ struct zcomp_backend *backend;
struct hlist_node node;
};

@@ -33,10 +46,9 @@ void zcomp_destroy(struct zcomp *comp);
struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);
void zcomp_stream_put(struct zcomp *comp);

-int zcomp_compress(struct zcomp_strm *zstrm,
- const void *src, unsigned int *dst_len);
-
-int zcomp_decompress(struct zcomp_strm *zstrm,
- const void *src, unsigned int src_len, void *dst);
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const void *src, unsigned int *dst_len);
+int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
+ const void *src, unsigned int src_len, void *dst);

#endif /* _ZCOMP_H_ */
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 4cf38f7d3e0a..298ef0e97e03 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1342,7 +1342,8 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page,
ret = 0;
} else {
dst = kmap_local_page(page);
- ret = zcomp_decompress(zstrm, src, size, dst);
+ ret = zcomp_decompress(zram->comps[prio], zstrm,
+ src, size, dst);
kunmap_local(dst);
zcomp_stream_put(zram->comps[prio]);
}
@@ -1429,7 +1430,8 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index)
compress_again:
zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
src = kmap_local_page(page);
- ret = zcomp_compress(zstrm, src, &comp_len);
+ ret = zcomp_compress(zram->comps[ZRAM_PRIMARY_COMP], zstrm,
+ src, &comp_len);
kunmap_local(src);

if (unlikely(ret)) {
@@ -1616,7 +1618,8 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
num_recomps++;
zstrm = zcomp_stream_get(zram->comps[prio]);
src = kmap_local_page(page);
- ret = zcomp_compress(zstrm, src, &comp_len_new);
+ ret = zcomp_compress(zram->comps[prio], zstrm,
+ src, &comp_len_new);
kunmap_local(src);

if (ret) {
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:20:07

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 05/14] zram: add zstd compression backend support

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 12 ++++
drivers/block/zram/Makefile | 1 +
drivers/block/zram/backend_zstd.c | 97 +++++++++++++++++++++++++++++++
drivers/block/zram/backend_zstd.h | 10 ++++
drivers/block/zram/zcomp.c | 4 ++
5 files changed, 124 insertions(+)
create mode 100644 drivers/block/zram/backend_zstd.c
create mode 100644 drivers/block/zram/backend_zstd.h

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 8a775fd66eb9..d0f791a8c7bd 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -35,6 +35,13 @@ config ZRAM_BACKEND_LZ4HC
select LZ4HC_COMPRESS
select LZ4_DECOMPRESS

+config ZRAM_BACKEND_ZSTD
+ bool "zstd compression support"
+ depends on ZRAM
+ default n
+ select ZSTD_COMPRESS
+ select ZSTD_DECOMPRESS
+
choice
prompt "Default zram compressor"
default ZRAM_DEF_COMP_LZORLE
@@ -56,6 +63,10 @@ config ZRAM_DEF_COMP_LZ4HC
bool "lz4hc"
depends on ZRAM_BACKEND_LZ4HC

+config ZRAM_DEF_COMP_ZSTD
+ bool "zstd"
+ depends on ZRAM_BACKEND_ZSTD
+
endchoice

config ZRAM_DEF_COMP
@@ -64,6 +75,7 @@ config ZRAM_DEF_COMP
default "lzo" if ZRAM_DEF_COMP_LZO
default "lz4" if ZRAM_DEF_COMP_LZ4
default "lz4hc" if ZRAM_DEF_COMP_LZ4HC
+ default "zstd" if ZRAM_DEF_COMP_ZSTD
default "unset-value"

config ZRAM_WRITEBACK
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index 815b45471c7d..053fe35e346b 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
obj-$(CONFIG_ZRAM_BACKEND_LZ4HC) += backend_lz4hc.o
+obj-$(CONFIG_ZRAM_BACKEND_ZSTD) += backend_zstd.o

zram-y := zcomp.o zram_drv.o

diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
new file mode 100644
index 000000000000..4da49626f110
--- /dev/null
+++ b/drivers/block/zram/backend_zstd.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/zstd.h>
+
+#include "backend_zstd.h"
+
+struct zstd_ctx {
+ zstd_cctx *cctx;
+ zstd_dctx *dctx;
+ void *cctx_mem;
+ void *dctx_mem;
+ s32 level;
+};
+
+static void zstd_destroy(void *ctx)
+{
+ struct zstd_ctx *zctx = ctx;
+
+ vfree(zctx->cctx_mem);
+ vfree(zctx->dctx_mem);
+ kfree(zctx);
+}
+
+static void *zstd_create(void)
+{
+ zstd_parameters params;
+ struct zstd_ctx *ctx;
+ size_t sz;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->level = ZSTD_defaultCLevel();
+ params = zstd_get_params(ctx->level, 0);
+ sz = zstd_cctx_workspace_bound(&params.cParams);
+ ctx->cctx_mem = vzalloc(sz);
+ if (!ctx->cctx_mem)
+ goto error;
+
+ ctx->cctx = zstd_init_cctx(ctx->cctx_mem, sz);
+ if (!ctx->cctx)
+ goto error;
+
+ sz = zstd_dctx_workspace_bound();
+ ctx->dctx_mem = vzalloc(sz);
+ if (!ctx->dctx_mem)
+ goto error;
+
+ ctx->dctx = zstd_init_dctx(ctx->dctx_mem, sz);
+ if (!ctx->dctx)
+ goto error;
+
+ return ctx;
+
+error:
+ zstd_destroy(ctx);
+ return NULL;
+}
+
+static int zstd_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ struct zstd_ctx *zctx = ctx;
+ const zstd_parameters params = zstd_get_params(zctx->level, 0);
+ size_t ret;
+
+ ret = zstd_compress_cctx(zctx->cctx, dst, *dst_len,
+ src, PAGE_SIZE, &params);
+ if (zstd_is_error(ret))
+ return -EINVAL;
+ *dst_len = ret;
+ return 0;
+}
+
+static int zstd_decompress(void *ctx, const unsigned char *src, size_t src_len,
+ unsigned char *dst)
+{
+ struct zstd_ctx *zctx = ctx;
+ size_t ret;
+
+ ret = zstd_decompress_dctx(zctx->dctx, dst, PAGE_SIZE, src, src_len);
+ if (zstd_is_error(ret))
+ return -EINVAL;
+ return 0;
+}
+
+struct zcomp_backend backend_zstd = {
+ .compress = zstd_compress,
+ .decompress = zstd_decompress,
+ .create_ctx = zstd_create,
+ .destroy_ctx = zstd_destroy,
+ .name = "zstd",
+};
diff --git a/drivers/block/zram/backend_zstd.h b/drivers/block/zram/backend_zstd.h
new file mode 100644
index 000000000000..75d2d2c02768
--- /dev/null
+++ b/drivers/block/zram/backend_zstd.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_ZSTD_H__
+#define __BACKEND_ZSTD_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_zstd;
+
+#endif /* __BACKEND_ZSTD_H__ */
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index f04f5844a23c..c16eb038f608 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -19,6 +19,7 @@
#include "backend_lzorle.h"
#include "backend_lz4.h"
#include "backend_lz4hc.h"
+#include "backend_zstd.h"

static struct zcomp_backend *backends[] = {
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
@@ -30,6 +31,9 @@ static struct zcomp_backend *backends[] = {
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4HC)
&backend_lz4hc,
+#endif
+#if IS_ENABLED(CONFIG_ZRAM_BACKEND_ZSTD)
+ &backend_zstd,
#endif
NULL
};
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:20:25

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 06/14] zram: pass estimated src size hint to zstd

zram works with PAGE_SIZE buffers, so we always know exact
size of the source buffer and hence can pass estimated_src_size
to zstd_get_params().

This hint on x86_64, for example, reduces the size of the work
memory buffer from 1303520 bytes down to 90080 bytes. Given that
compression streams are per-CPU that's quite some memory saving.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/backend_zstd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index 4da49626f110..4a7734aa1a8a 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -35,7 +35,7 @@ static void *zstd_create(void)
return NULL;

ctx->level = ZSTD_defaultCLevel();
- params = zstd_get_params(ctx->level, 0);
+ params = zstd_get_params(ctx->level, PAGE_SIZE);
sz = zstd_cctx_workspace_bound(&params.cParams);
ctx->cctx_mem = vzalloc(sz);
if (!ctx->cctx_mem)
@@ -65,7 +65,7 @@ static int zstd_compress(void *ctx, const unsigned char *src,
unsigned char *dst, size_t *dst_len)
{
struct zstd_ctx *zctx = ctx;
- const zstd_parameters params = zstd_get_params(zctx->level, 0);
+ const zstd_parameters params = zstd_get_params(zctx->level, PAGE_SIZE);
size_t ret;

ret = zstd_compress_cctx(zctx->cctx, dst, *dst_len,
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:20:44

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 04/14] zram: add lz4hc compression backend support

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 12 +++++
drivers/block/zram/Makefile | 5 ++-
drivers/block/zram/backend_lz4hc.c | 72 ++++++++++++++++++++++++++++++
drivers/block/zram/backend_lz4hc.h | 10 +++++
drivers/block/zram/zcomp.c | 4 ++
5 files changed, 101 insertions(+), 2 deletions(-)
create mode 100644 drivers/block/zram/backend_lz4hc.c
create mode 100644 drivers/block/zram/backend_lz4hc.h

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index 02d20a30bf6c..8a775fd66eb9 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -28,6 +28,13 @@ config ZRAM_BACKEND_LZ4
select LZ4_COMPRESS
select LZ4_DECOMPRESS

+config ZRAM_BACKEND_LZ4HC
+ bool "lz4hc compression support"
+ depends on ZRAM
+ default n
+ select LZ4HC_COMPRESS
+ select LZ4_DECOMPRESS
+
choice
prompt "Default zram compressor"
default ZRAM_DEF_COMP_LZORLE
@@ -45,6 +52,10 @@ config ZRAM_DEF_COMP_LZ4
bool "lz4"
depends on ZRAM_BACKEND_LZ4

+config ZRAM_DEF_COMP_LZ4HC
+ bool "lz4hc"
+ depends on ZRAM_BACKEND_LZ4HC
+
endchoice

config ZRAM_DEF_COMP
@@ -52,6 +63,7 @@ config ZRAM_DEF_COMP
default "lzo-rle" if ZRAM_DEF_COMP_LZORLE
default "lzo" if ZRAM_DEF_COMP_LZO
default "lz4" if ZRAM_DEF_COMP_LZ4
+ default "lz4hc" if ZRAM_DEF_COMP_LZ4HC
default "unset-value"

config ZRAM_WRITEBACK
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index 1be5d2657960..815b45471c7d 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only

-obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
-obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
+obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
+obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
+obj-$(CONFIG_ZRAM_BACKEND_LZ4HC) += backend_lz4hc.o

zram-y := zcomp.o zram_drv.o

diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
new file mode 100644
index 000000000000..5c437623aa65
--- /dev/null
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -0,0 +1,72 @@
+#include <linux/kernel.h>
+#include <linux/lz4.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "backend_lz4hc.h"
+
+struct lz4hc_ctx {
+ void *mem;
+ s32 level;
+};
+
+static void lz4hc_destroy(void *ctx)
+{
+ struct lz4hc_ctx *zctx = ctx;
+
+ vfree(zctx->mem);
+ kfree(zctx);
+}
+
+static void *lz4hc_create(void)
+{
+ struct lz4hc_ctx *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->mem = vmalloc(LZ4HC_MEM_COMPRESS);
+ if (!ctx->mem) {
+ lz4hc_destroy(ctx);
+ return NULL;
+ }
+
+ /* @FIXME: using a hardcoded LZ4HC_DEFAULT_CLEVEL for now */
+ ctx->level = LZ4HC_DEFAULT_CLEVEL;
+ return ctx;
+}
+
+static int lz4hc_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ struct lz4hc_ctx *zctx = ctx;
+ int ret;
+
+ ret = LZ4_compress_HC(src, dst, PAGE_SIZE, *dst_len,
+ zctx->level, zctx->mem);
+ if (!ret)
+ return -EINVAL;
+ *dst_len = ret;
+ return 0;
+}
+
+static int lz4hc_decompress(void *ctx, const unsigned char *src,
+ size_t src_len, unsigned char *dst)
+{
+ int dst_len = PAGE_SIZE;
+ int ret;
+
+ ret = LZ4_decompress_safe(src, dst, src_len, dst_len);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+}
+
+struct zcomp_backend backend_lz4hc = {
+ .compress = lz4hc_compress,
+ .decompress = lz4hc_decompress,
+ .create_ctx = lz4hc_create,
+ .destroy_ctx = lz4hc_destroy,
+ .name = "lz4hc",
+};
diff --git a/drivers/block/zram/backend_lz4hc.h b/drivers/block/zram/backend_lz4hc.h
new file mode 100644
index 000000000000..29c428a850e2
--- /dev/null
+++ b/drivers/block/zram/backend_lz4hc.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_LZ4HC_H__
+#define __BACKEND_LZ4HC_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_lz4hc;
+
+#endif /* __BACKEND_LZ4HC_H__ */
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 902bdaf7e299..f04f5844a23c 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -18,6 +18,7 @@
#include "backend_lzo.h"
#include "backend_lzorle.h"
#include "backend_lz4.h"
+#include "backend_lz4hc.h"

static struct zcomp_backend *backends[] = {
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
@@ -26,6 +27,9 @@ static struct zcomp_backend *backends[] = {
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4)
&backend_lz4,
+#endif
+#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4HC)
+ &backend_lz4hc,
#endif
NULL
};
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:20:51

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 08/14] zram: check that backends array has at least one backend

Make sure that backends array has anything apart from the
sentinel NULL value.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/zcomp.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 9fc5477a6259..fdf06fc6b364 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -205,6 +205,14 @@ struct zcomp *zcomp_create(const char *alg)
struct zcomp *comp;
int error;

+ /*
+ * The backends array has a sentinel NULL value, so the minimum
+ * size is 1. In order to be valid the array, apart from the
+ * sentinel NULL element, should have at least one compression
+ * backend selected.
+ */
+ BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
+
comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
if (!comp)
return ERR_PTR(-ENOMEM);
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:21:17

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 09/14] zram: introduce zcomp_config structure

We will store a per-algorithm parameters there (compression level,
dictionary, dictionary size, etc.).

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/backend_deflate.c | 9 ++++++---
drivers/block/zram/backend_lz4.c | 2 +-
drivers/block/zram/backend_lz4hc.c | 10 ++++++----
drivers/block/zram/backend_lzo.c | 2 +-
drivers/block/zram/backend_lzorle.c | 2 +-
drivers/block/zram/backend_zstd.c | 8 ++++++--
drivers/block/zram/zcomp.c | 5 +++--
drivers/block/zram/zcomp.h | 14 ++++++++++++--
drivers/block/zram/zram_drv.c | 20 +++++++++++++++++++-
drivers/block/zram/zram_drv.h | 1 +
10 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/drivers/block/zram/backend_deflate.c b/drivers/block/zram/backend_deflate.c
index 949d402ea3dd..83c660adc722 100644
--- a/drivers/block/zram/backend_deflate.c
+++ b/drivers/block/zram/backend_deflate.c
@@ -32,7 +32,7 @@ static void deflate_destroy(void *ctx)
kfree(zctx);
}

-static void *deflate_create(void)
+static void *deflate_create(struct zcomp_config *config)
{
struct deflate_ctx *ctx;
size_t sz;
@@ -42,8 +42,11 @@ static void *deflate_create(void)
if (!ctx)
return NULL;

- /* @FIXME: using a hardcoded Z_DEFAULT_COMPRESSION for now */
- ctx->level = Z_DEFAULT_COMPRESSION;
+ if (config->level != ZCOMP_CONFIG_NO_LEVEL)
+ ctx->level = config->level;
+ else
+ ctx->level = Z_DEFAULT_COMPRESSION;
+
sz = zlib_deflate_workspacesize(-DEFLATE_DEF_WINBITS, MAX_MEM_LEVEL);
ctx->cctx.workspace = vzalloc(sz);
if (!ctx->cctx.workspace)
diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
index 697592dbabe2..98d9c9274149 100644
--- a/drivers/block/zram/backend_lz4.c
+++ b/drivers/block/zram/backend_lz4.c
@@ -4,7 +4,7 @@

#include "backend_lz4.h"

-static void *lz4_create(void)
+static void *lz4_create(struct zcomp_config *config)
{
return vmalloc(LZ4_MEM_COMPRESS);
}
diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
index 5c437623aa65..62721a7c82dc 100644
--- a/drivers/block/zram/backend_lz4hc.c
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -18,7 +18,7 @@ static void lz4hc_destroy(void *ctx)
kfree(zctx);
}

-static void *lz4hc_create(void)
+static void *lz4hc_create(struct zcomp_config *config)
{
struct lz4hc_ctx *ctx;

@@ -26,14 +26,16 @@ static void *lz4hc_create(void)
if (!ctx)
return NULL;

+ if (config->level != ZCOMP_CONFIG_NO_LEVEL)
+ ctx->level = config->level;
+ else
+ ctx->level = LZ4HC_DEFAULT_CLEVEL;
+
ctx->mem = vmalloc(LZ4HC_MEM_COMPRESS);
if (!ctx->mem) {
lz4hc_destroy(ctx);
return NULL;
}
-
- /* @FIXME: using a hardcoded LZ4HC_DEFAULT_CLEVEL for now */
- ctx->level = LZ4HC_DEFAULT_CLEVEL;
return ctx;
}

diff --git a/drivers/block/zram/backend_lzo.c b/drivers/block/zram/backend_lzo.c
index d9a003fbb360..c9ca18a2f993 100644
--- a/drivers/block/zram/backend_lzo.c
+++ b/drivers/block/zram/backend_lzo.c
@@ -6,7 +6,7 @@

#include "backend_lzo.h"

-static void *lzo_create(void)
+static void *lzo_create(struct zcomp_config *config)
{
return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
}
diff --git a/drivers/block/zram/backend_lzorle.c b/drivers/block/zram/backend_lzorle.c
index 9bf1843021b0..b0937103b5fb 100644
--- a/drivers/block/zram/backend_lzorle.c
+++ b/drivers/block/zram/backend_lzorle.c
@@ -6,7 +6,7 @@

#include "backend_lzorle.h"

-static void *lzorle_create(void)
+static void *lzorle_create(struct zcomp_config *config)
{
return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
}
diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index 4a7734aa1a8a..b2fb94902bef 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -24,7 +24,7 @@ static void zstd_destroy(void *ctx)
kfree(zctx);
}

-static void *zstd_create(void)
+static void *zstd_create(struct zcomp_config *config)
{
zstd_parameters params;
struct zstd_ctx *ctx;
@@ -34,7 +34,11 @@ static void *zstd_create(void)
if (!ctx)
return NULL;

- ctx->level = ZSTD_defaultCLevel();
+ if (config->level != ZCOMP_CONFIG_NO_LEVEL)
+ ctx->level = config->level;
+ else
+ ctx->level = ZSTD_defaultCLevel();
+
params = zstd_get_params(ctx->level, PAGE_SIZE);
sz = zstd_cctx_workspace_bound(&params.cParams);
ctx->cctx_mem = vzalloc(sz);
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index fdf06fc6b364..9e182eb52fe7 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -57,7 +57,7 @@ static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
*/
static int zcomp_strm_init(struct zcomp *comp, struct zcomp_strm *zstrm)
{
- zstrm->ctx = comp->backend->create_ctx();
+ zstrm->ctx = comp->backend->create_ctx(comp->config);

/*
* allocate 2 pages. 1 for compressed data, plus 1 extra for the
@@ -200,7 +200,7 @@ void zcomp_destroy(struct zcomp *comp)
kfree(comp);
}

-struct zcomp *zcomp_create(const char *alg)
+struct zcomp *zcomp_create(const char *alg, struct zcomp_config *config)
{
struct zcomp *comp;
int error;
@@ -217,6 +217,7 @@ struct zcomp *zcomp_create(const char *alg)
if (!comp)
return ERR_PTR(-ENOMEM);

+ comp->config = config;
comp->backend = lookup_backend(alg);
if (!comp->backend) {
kfree(comp);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 757b85017e23..345c78bc76db 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -5,6 +5,7 @@

#ifndef _ZCOMP_H_
#define _ZCOMP_H_
+
#include <linux/local_lock.h>

struct zcomp_strm {
@@ -15,6 +16,14 @@ struct zcomp_strm {
void *ctx;
};

+#define ZCOMP_CONFIG_NO_LEVEL INT_MIN
+
+struct zcomp_config {
+ s32 level;
+ size_t dict_sz;
+ void *dict;
+};
+
struct zcomp_backend {
int (*compress)(void *ctx, const unsigned char *src,
unsigned char *dst, size_t *dst_len);
@@ -22,7 +31,7 @@ struct zcomp_backend {
int (*decompress)(void *ctx, const unsigned char *src, size_t src_len,
unsigned char *dst);

- void *(*create_ctx)(void);
+ void *(*create_ctx)(struct zcomp_config *config);
void (*destroy_ctx)(void *ctx);

const char *name;
@@ -32,6 +41,7 @@ struct zcomp_backend {
struct zcomp {
struct zcomp_strm __percpu *stream;
struct zcomp_backend *backend;
+ struct zcomp_config *config;
struct hlist_node node;
};

@@ -40,7 +50,7 @@ int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node);
ssize_t zcomp_available_show(const char *comp, char *buf);
bool zcomp_available_algorithm(const char *comp);

-struct zcomp *zcomp_create(const char *alg);
+struct zcomp *zcomp_create(const char *alg, struct zcomp_config *config);
void zcomp_destroy(struct zcomp *comp);

struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 298ef0e97e03..6c36cd349431 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1994,6 +1994,20 @@ static void zram_slot_free_notify(struct block_device *bdev,
zram_slot_unlock(zram, index);
}

+static void zram_reset_comp_configs(struct zram *zram)
+{
+ u32 prio;
+
+ for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) {
+ struct zcomp_config *config = &zram->configs[prio];
+
+ vfree(config->dict);
+ config->level = ZCOMP_CONFIG_NO_LEVEL;
+ config->dict_sz = 0;
+ config->dict = NULL;
+ }
+}
+
static void zram_destroy_comps(struct zram *zram)
{
u32 prio;
@@ -2007,6 +2021,8 @@ static void zram_destroy_comps(struct zram *zram)
zcomp_destroy(comp);
zram->num_active_comps--;
}
+
+ zram_reset_comp_configs(zram);
}

static void zram_reset_device(struct zram *zram)
@@ -2064,7 +2080,8 @@ static ssize_t disksize_store(struct device *dev,
if (!zram->comp_algs[prio])
continue;

- comp = zcomp_create(zram->comp_algs[prio]);
+ comp = zcomp_create(zram->comp_algs[prio],
+ &zram->configs[prio]);
if (IS_ERR(comp)) {
pr_err("Cannot initialise %s compressing backend\n",
zram->comp_algs[prio]);
@@ -2271,6 +2288,7 @@ static int zram_add(void)
if (ret)
goto out_cleanup_disk;

+ zram_reset_comp_configs(zram);
comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor);

zram_debugfs_register(zram);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 37bf29f34d26..2c77f3bff166 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -107,6 +107,7 @@ struct zram {
struct zram_table_entry *table;
struct zs_pool *mem_pool;
struct zcomp *comps[ZRAM_MAX_COMPS];
+ struct zcomp_config configs[ZRAM_MAX_COMPS];
struct gendisk *disk;
/* Prevent concurrent execution of device init */
struct rw_semaphore init_lock;
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:21:27

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 10/14] zram: extend comp_algorithm attr write handling

Previously comp_algorithm device attr would accept only
algorithm name param, however in order to enabled comp
configuration we need to extend comp_algorithm_store()
with param=value support.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/zram_drv.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 6c36cd349431..bd8433363cbe 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1028,9 +1028,33 @@ static ssize_t comp_algorithm_store(struct device *dev,
size_t len)
{
struct zram *zram = dev_to_zram(dev);
+ char *args, *param, *val;
+ char *alg = NULL;
int ret;

- ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, buf);
+ args = skip_spaces(buf);
+ while (*args) {
+ args = next_arg(args, &param, &val);
+
+ /*
+ * We need to support 'param' without value, which is an
+ * old format for this attr (algorithm name only).
+ */
+ if (!val || !*val) {
+ alg = param;
+ continue;
+ }
+
+ if (!strcmp(param, "algo")) {
+ alg = val;
+ continue;
+ }
+ }
+
+ if (!alg)
+ return -EINVAL;
+
+ ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, alg);
return ret ? ret : len;
}

--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:21:38

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 07/14] zram: add zlib compression backend support

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 12 +++
drivers/block/zram/Makefile | 9 +-
drivers/block/zram/backend_deflate.c | 130 +++++++++++++++++++++++++++
drivers/block/zram/backend_deflate.h | 10 +++
drivers/block/zram/zcomp.c | 4 +
5 files changed, 161 insertions(+), 4 deletions(-)
create mode 100644 drivers/block/zram/backend_deflate.c
create mode 100644 drivers/block/zram/backend_deflate.h

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index d0f791a8c7bd..7155a23d66de 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -42,6 +42,13 @@ config ZRAM_BACKEND_ZSTD
select ZSTD_COMPRESS
select ZSTD_DECOMPRESS

+config ZRAM_BACKEND_DEFLATE
+ bool "deflate compression support"
+ depends on ZRAM
+ default n
+ select ZLIB_DEFLATE
+ select ZLIB_INFLATE
+
choice
prompt "Default zram compressor"
default ZRAM_DEF_COMP_LZORLE
@@ -67,6 +74,10 @@ config ZRAM_DEF_COMP_ZSTD
bool "zstd"
depends on ZRAM_BACKEND_ZSTD

+config ZRAM_DEF_COMP_DEFLATE
+ bool "deflate"
+ depends on ZRAM_BACKEND_DEFLATE
+
endchoice

config ZRAM_DEF_COMP
@@ -76,6 +87,7 @@ config ZRAM_DEF_COMP
default "lz4" if ZRAM_DEF_COMP_LZ4
default "lz4hc" if ZRAM_DEF_COMP_LZ4HC
default "zstd" if ZRAM_DEF_COMP_ZSTD
+ default "deflate" if ZRAM_DEF_COMP_DEFLATE
default "unset-value"

config ZRAM_WRITEBACK
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index 053fe35e346b..91c07595d8b4 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,9 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-only

-obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
-obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
-obj-$(CONFIG_ZRAM_BACKEND_LZ4HC) += backend_lz4hc.o
-obj-$(CONFIG_ZRAM_BACKEND_ZSTD) += backend_zstd.o
+obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
+obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o
+obj-$(CONFIG_ZRAM_BACKEND_LZ4HC) += backend_lz4hc.o
+obj-$(CONFIG_ZRAM_BACKEND_ZSTD) += backend_zstd.o
+obj-$(CONFIG_ZRAM_BACKEND_DEFLATE) += backend_deflate.o

zram-y := zcomp.o zram_drv.o

diff --git a/drivers/block/zram/backend_deflate.c b/drivers/block/zram/backend_deflate.c
new file mode 100644
index 000000000000..949d402ea3dd
--- /dev/null
+++ b/drivers/block/zram/backend_deflate.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/zlib.h>
+
+#include "backend_deflate.h"
+
+/* Use the same value as crypto API */
+#define DEFLATE_DEF_WINBITS 11
+#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL
+
+struct deflate_ctx {
+ struct z_stream_s cctx;
+ struct z_stream_s dctx;
+ s32 level;
+};
+
+static void deflate_destroy(void *ctx)
+{
+ struct deflate_ctx *zctx = ctx;
+
+ if (zctx->cctx.workspace) {
+ zlib_deflateEnd(&zctx->cctx);
+ vfree(zctx->cctx.workspace);
+ }
+ if (zctx->dctx.workspace) {
+ zlib_inflateEnd(&zctx->dctx);
+ vfree(zctx->dctx.workspace);
+ }
+ kfree(zctx);
+}
+
+static void *deflate_create(void)
+{
+ struct deflate_ctx *ctx;
+ size_t sz;
+ int ret;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ /* @FIXME: using a hardcoded Z_DEFAULT_COMPRESSION for now */
+ ctx->level = Z_DEFAULT_COMPRESSION;
+ sz = zlib_deflate_workspacesize(-DEFLATE_DEF_WINBITS, MAX_MEM_LEVEL);
+ ctx->cctx.workspace = vzalloc(sz);
+ if (!ctx->cctx.workspace)
+ goto error;
+
+ ret = zlib_deflateInit2(&ctx->cctx, ctx->level, Z_DEFLATED,
+ -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
+ Z_DEFAULT_STRATEGY);
+ if (ret != Z_OK)
+ goto error;
+
+ sz = zlib_inflate_workspacesize();
+ ctx->dctx.workspace = vzalloc(sz);
+ if (!ctx->dctx.workspace)
+ goto error;
+
+ ret = zlib_inflateInit2(&ctx->dctx, -DEFLATE_DEF_WINBITS);
+ if (ret != Z_OK)
+ goto error;
+
+ return ctx;
+
+error:
+ deflate_destroy(ctx);
+ return NULL;
+}
+
+static int deflate_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ struct deflate_ctx *zctx = ctx;
+ struct z_stream_s *deflate;
+ int ret;
+
+ deflate = &zctx->cctx;
+ ret = zlib_deflateReset(deflate);
+ if (ret != Z_OK)
+ return -EINVAL;
+
+ deflate->next_in = (u8 *)src;
+ deflate->avail_in = PAGE_SIZE;
+ deflate->next_out = (u8 *)dst;
+ deflate->avail_out = *dst_len;
+
+ ret = zlib_deflate(deflate, Z_FINISH);
+ if (ret != Z_STREAM_END)
+ return -EINVAL;
+
+ *dst_len = deflate->total_out;
+ return 0;
+}
+
+static int deflate_decompress(void *ctx, const unsigned char *src,
+ size_t src_len, unsigned char *dst)
+{
+ struct deflate_ctx *zctx = ctx;
+ struct z_stream_s *inflate;
+ int ret;
+
+ inflate = &zctx->dctx;
+
+ ret = zlib_inflateReset(inflate);
+ if (ret != Z_OK)
+ return -EINVAL;
+
+ inflate->next_in = (u8 *)src;
+ inflate->avail_in = src_len;
+ inflate->next_out = (u8 *)dst;
+ inflate->avail_out = PAGE_SIZE;
+
+ ret = zlib_inflate(inflate, Z_SYNC_FLUSH);
+ if (ret != Z_STREAM_END)
+ return -EINVAL;
+
+ return 0;
+}
+
+struct zcomp_backend backend_deflate = {
+ .compress = deflate_compress,
+ .decompress = deflate_decompress,
+ .create_ctx = deflate_create,
+ .destroy_ctx = deflate_destroy,
+ .name = "deflate",
+};
diff --git a/drivers/block/zram/backend_deflate.h b/drivers/block/zram/backend_deflate.h
new file mode 100644
index 000000000000..49cef8fc1e77
--- /dev/null
+++ b/drivers/block/zram/backend_deflate.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_DEFLATE_H__
+#define __BACKEND_DEFLATE_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_deflate;
+
+#endif /* __BACKEND_DEFLATE_H__ */
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index c16eb038f608..9fc5477a6259 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -20,6 +20,7 @@
#include "backend_lz4.h"
#include "backend_lz4hc.h"
#include "backend_zstd.h"
+#include "backend_deflate.h"

static struct zcomp_backend *backends[] = {
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
@@ -34,6 +35,9 @@ static struct zcomp_backend *backends[] = {
#endif
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_ZSTD)
&backend_zstd,
+#endif
+#if IS_ENABLED(CONFIG_ZRAM_BACKEND_DEFLATE)
+ &backend_deflate,
#endif
NULL
};
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:21:47

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 11/14] zram: support compression level comp config

Add support for compression level level=N comp configuration
to comp_algorithm and recomp_algorithm knobs.

Note that zram cannot verify ranges, it's a task of
corresponding backends to make sure that level makes
sense.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/zram_drv.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index bd8433363cbe..89a2eb37e26c 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1013,6 +1013,12 @@ static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf)
return 0;
}

+static int comp_config_store(struct zram *zram, u32 prio, s32 level)
+{
+ zram->configs[prio].level = level;
+ return 0;
+}
+
static ssize_t comp_algorithm_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1030,6 +1036,7 @@ static ssize_t comp_algorithm_store(struct device *dev,
struct zram *zram = dev_to_zram(dev);
char *args, *param, *val;
char *alg = NULL;
+ s32 level = ZCOMP_CONFIG_NO_LEVEL;
int ret;

args = skip_spaces(buf);
@@ -1049,12 +1056,21 @@ static ssize_t comp_algorithm_store(struct device *dev,
alg = val;
continue;
}
+
+ if (!strcmp(param, "level")) {
+ ret = kstrtoint(val, 10, &level);
+ if (ret)
+ return ret;
+ continue;
+ }
}

if (!alg)
return -EINVAL;

- ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, alg);
+ ret = comp_config_store(zram, ZRAM_PRIMARY_COMP, level);
+ if (!ret)
+ ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, alg);
return ret ? ret : len;
}

@@ -1087,6 +1103,7 @@ static ssize_t recomp_algorithm_store(struct device *dev,
int prio = ZRAM_SECONDARY_COMP;
char *args, *param, *val;
char *alg = NULL;
+ s32 level = ZCOMP_CONFIG_NO_LEVEL;
int ret;

args = skip_spaces(buf);
@@ -1107,6 +1124,13 @@ static ssize_t recomp_algorithm_store(struct device *dev,
return ret;
continue;
}
+
+ if (!strcmp(param, "level")) {
+ ret = kstrtoint(val, 10, &level);
+ if (ret)
+ return ret;
+ continue;
+ }
}

if (!alg)
@@ -1115,7 +1139,9 @@ static ssize_t recomp_algorithm_store(struct device *dev,
if (prio < ZRAM_SECONDARY_COMP || prio >= ZRAM_MAX_COMPS)
return -EINVAL;

- ret = __comp_algorithm_store(zram, prio, alg);
+ ret = comp_config_store(zram, prio, level);
+ if (!ret)
+ ret = __comp_algorithm_store(zram, prio, alg);
return ret ? ret : len;
}
#endif
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:24:17

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 12/14] zram: add support for dict comp config

Handle dict=path param so that we can read a pre-trained
compression algorithm dictionary which we then pass to the
backend configuration.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/zram_drv.c | 35 ++++++++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 89a2eb37e26c..c50283c7231e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -33,6 +33,7 @@
#include <linux/debugfs.h>
#include <linux/cpuhotplug.h>
#include <linux/part_stat.h>
+#include <linux/kernel_read_file.h>

#include "zram_drv.h"

@@ -1013,9 +1014,23 @@ static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf)
return 0;
}

-static int comp_config_store(struct zram *zram, u32 prio, s32 level)
+static int comp_config_store(struct zram *zram, u32 prio, s32 level,
+ const char *dict_path)
{
+ size_t sz = 0;
+
+ if (dict_path) {
+ sz = kernel_read_file_from_path(dict_path, 0,
+ &zram->configs[prio].dict,
+ INT_MAX,
+ NULL,
+ READING_POLICY);
+ if (sz < 0)
+ return -EINVAL;
+ }
+
zram->configs[prio].level = level;
+ zram->configs[prio].dict_sz = sz;
return 0;
}

@@ -1035,7 +1050,7 @@ static ssize_t comp_algorithm_store(struct device *dev,
{
struct zram *zram = dev_to_zram(dev);
char *args, *param, *val;
- char *alg = NULL;
+ char *alg = NULL, *dict_path = NULL;
s32 level = ZCOMP_CONFIG_NO_LEVEL;
int ret;

@@ -1063,12 +1078,17 @@ static ssize_t comp_algorithm_store(struct device *dev,
return ret;
continue;
}
+
+ if (!strcmp(param, "dict")) {
+ dict_path = val;
+ continue;
+ }
}

if (!alg)
return -EINVAL;

- ret = comp_config_store(zram, ZRAM_PRIMARY_COMP, level);
+ ret = comp_config_store(zram, ZRAM_PRIMARY_COMP, level, dict_path);
if (!ret)
ret = __comp_algorithm_store(zram, ZRAM_PRIMARY_COMP, alg);
return ret ? ret : len;
@@ -1102,7 +1122,7 @@ static ssize_t recomp_algorithm_store(struct device *dev,
struct zram *zram = dev_to_zram(dev);
int prio = ZRAM_SECONDARY_COMP;
char *args, *param, *val;
- char *alg = NULL;
+ char *alg = NULL, *dict_path = NULL;
s32 level = ZCOMP_CONFIG_NO_LEVEL;
int ret;

@@ -1131,6 +1151,11 @@ static ssize_t recomp_algorithm_store(struct device *dev,
return ret;
continue;
}
+
+ if (!strcmp(param, "dict")) {
+ dict_path = val;
+ continue;
+ }
}

if (!alg)
@@ -1139,7 +1164,7 @@ static ssize_t recomp_algorithm_store(struct device *dev,
if (prio < ZRAM_SECONDARY_COMP || prio >= ZRAM_MAX_COMPS)
return -EINVAL;

- ret = comp_config_store(zram, prio, level);
+ ret = comp_config_store(zram, prio, level, dict_path);
if (!ret)
ret = __comp_algorithm_store(zram, prio, alg);
return ret ? ret : len;
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:27:14

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 03/14] zram: add lz4 compression backend support

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/Kconfig | 12 ++++++++
drivers/block/zram/Makefile | 1 +
drivers/block/zram/backend_lz4.c | 47 ++++++++++++++++++++++++++++++++
drivers/block/zram/backend_lz4.h | 10 +++++++
drivers/block/zram/zcomp.c | 4 +++
5 files changed, 74 insertions(+)
create mode 100644 drivers/block/zram/backend_lz4.c
create mode 100644 drivers/block/zram/backend_lz4.h

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index a1fe8b989ee2..02d20a30bf6c 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -21,6 +21,13 @@ config ZRAM_BACKEND_LZO
select LZO_COMPRESS
select LZO_DECOMPRESS

+config ZRAM_BACKEND_LZ4
+ bool "lz4 compression support"
+ depends on ZRAM
+ default n
+ select LZ4_COMPRESS
+ select LZ4_DECOMPRESS
+
choice
prompt "Default zram compressor"
default ZRAM_DEF_COMP_LZORLE
@@ -34,12 +41,17 @@ config ZRAM_DEF_COMP_LZO
bool "lzo"
depends on ZRAM_BACKEND_LZO

+config ZRAM_DEF_COMP_LZ4
+ bool "lz4"
+ depends on ZRAM_BACKEND_LZ4
+
endchoice

config ZRAM_DEF_COMP
string
default "lzo-rle" if ZRAM_DEF_COMP_LZORLE
default "lzo" if ZRAM_DEF_COMP_LZO
+ default "lz4" if ZRAM_DEF_COMP_LZ4
default "unset-value"

config ZRAM_WRITEBACK
diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile
index 2dcbc9b75d91..1be5d2657960 100644
--- a/drivers/block/zram/Makefile
+++ b/drivers/block/zram/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only

obj-$(CONFIG_ZRAM_BACKEND_LZO) += backend_lzorle.o backend_lzo.o
+obj-$(CONFIG_ZRAM_BACKEND_LZ4) += backend_lz4.o

zram-y := zcomp.o zram_drv.o

diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
new file mode 100644
index 000000000000..697592dbabe2
--- /dev/null
+++ b/drivers/block/zram/backend_lz4.c
@@ -0,0 +1,47 @@
+#include <linux/kernel.h>
+#include <linux/lz4.h>
+#include <linux/vmalloc.h>
+
+#include "backend_lz4.h"
+
+static void *lz4_create(void)
+{
+ return vmalloc(LZ4_MEM_COMPRESS);
+}
+
+static void lz4_destroy(void *ctx)
+{
+ vfree(ctx);
+}
+
+static int lz4_compress(void *ctx, const unsigned char *src,
+ unsigned char *dst, size_t *dst_len)
+{
+ int ret;
+
+ ret = LZ4_compress_default(src, dst, PAGE_SIZE, *dst_len, ctx);
+ if (!ret)
+ return -EINVAL;
+ *dst_len = ret;
+ return 0;
+}
+
+static int lz4_decompress(void *ctx, const unsigned char *src,
+ size_t src_len, unsigned char *dst)
+{
+ int dst_len = PAGE_SIZE;
+ int ret;
+
+ ret = LZ4_decompress_safe(src, dst, src_len, dst_len);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+}
+
+struct zcomp_backend backend_lz4 = {
+ .compress = lz4_compress,
+ .decompress = lz4_decompress,
+ .create_ctx = lz4_create,
+ .destroy_ctx = lz4_destroy,
+ .name = "lz4",
+};
diff --git a/drivers/block/zram/backend_lz4.h b/drivers/block/zram/backend_lz4.h
new file mode 100644
index 000000000000..a5fb5564835c
--- /dev/null
+++ b/drivers/block/zram/backend_lz4.h
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __BACKEND_LZ4_H__
+#define __BACKEND_LZ4_H__
+
+#include "zcomp.h"
+
+extern struct zcomp_backend backend_lz4;
+
+#endif /* __BACKEND_LZ4_H__ */
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 58fb3ac91f4b..902bdaf7e299 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -17,11 +17,15 @@

#include "backend_lzo.h"
#include "backend_lzorle.h"
+#include "backend_lz4.h"

static struct zcomp_backend *backends[] = {
#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
&backend_lzorle,
&backend_lzo,
+#endif
+#if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4)
+ &backend_lz4,
#endif
NULL
};
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:28:39

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 14/14] Documentation/zram: add documentation for algorithm parameters

Document brief description of compression algorithms' parameters:
compression level and pre-trained dictionary.

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
Documentation/admin-guide/blockdev/zram.rst | 38 ++++++++++++++++-----
1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index 091e8bb38887..58d79f9099e3 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -102,15 +102,26 @@ Examples::
#select lzo compression algorithm
echo lzo > /sys/block/zram0/comp_algorithm

-For the time being, the `comp_algorithm` content does not necessarily
-show every compression algorithm supported by the kernel. We keep this
-list primarily to simplify device configuration and one can configure
-a new device with a compression algorithm that is not listed in
-`comp_algorithm`. The thing is that, internally, ZRAM uses Crypto API
-and, if some of the algorithms were built as modules, it's impossible
-to list all of them using, for instance, /proc/crypto or any other
-method. This, however, has an advantage of permitting the usage of
-custom crypto compression modules (implementing S/W or H/W compression).
+For the time being, the `comp_algorithm` content shows only compression
+algorithms that are supported by zram.
+
+It is also possible to pass algorithm specific configuration parameters::
+
+ #set compression level to 8
+ echo "zstd level=8" > /sys/block/zram0/comp_algorithm
+
+Note that `comp_algorithm` also supports `algo=name` format::
+
+ #set compression level to 8
+ echo "algo=zstd level=8" > /sys/block/zram0/comp_algorithm
+
+Certain compression algorithms support pre-trained dictionaries, which
+significantly change algorithms' characteristics. In order to configure
+compression algorithm to use external pre-trained dictionary, pass full
+path to the dictionary along with other parameters::
+
+ #pass path to pre-trained dictionary
+ echo "algo=zstd dict=/etc/dictioary" > /sys/block/zram0/comp_algorithm

4) Set Disksize
===============
@@ -442,6 +453,15 @@ configuration:::
#select deflate recompression algorithm, priority 2
echo "algo=deflate priority=2" > /sys/block/zramX/recomp_algorithm

+The `recomp_algorithm` also supports algorithm configuration parameters, e.g.
+compression level and pre-trained dircionary::
+
+ #pass compression level
+ echo "algo=zstd level=8" > /sys/block/zramX/recomp_algorithm
+
+ #pass path to pre-trained dictionary
+ echo "algo=zstd dict=/etc/dictioary" > /sys/block/zramX/recomp_algorithm
+
Another device attribute that CONFIG_ZRAM_MULTI_COMP enables is recompress,
which controls recompression.

--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-03 09:28:43

by Sergey Senozhatsky

[permalink] [raw]
Subject: [PATCH 13/14] zram: add dictionary support to zstd backend

This adds support for pre-trained zstd dictionaries [1]
Dictionary is loaded once (per-config) and then loaded to Cctx
and Dctx by reference, so we don't allocate extra memory.

The patch is a little non-trivial, as it seems that noone
ever attempted to use dictionaries in the linux kernel
port of zstd.

It also uses GFP_KERNEL gfp in Cctx customAlloc(). We probably
would want to do something about it. Either make sure that we
always (somehow) fully setup all Cctx contexts from non-atomic
context before we attempt to use them, come up with some sort
of custom allocator or stop calling zcomp_compress() from atomic
context.

[1] https://github.com/facebook/zstd/blob/dev/programs/zstd.1.md#dictionary-builder

Signed-off-by: Sergey Senozhatsky <[email protected]>
---
drivers/block/zram/backend_zstd.c | 119 ++++++++++++++++++++++++------
1 file changed, 96 insertions(+), 23 deletions(-)

diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index b2fb94902bef..6220c154e54e 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -12,23 +12,47 @@ struct zstd_ctx {
zstd_dctx *dctx;
void *cctx_mem;
void *dctx_mem;
+ ZSTD_customMem cctx_cmem;
+ ZSTD_customMem dctx_cmem;
+ ZSTD_CDict *cdict;
+ ZSTD_DDict *ddict;
s32 level;
};

+/*
+ * Cctx allocator.customAlloc() is called from zcom_compress(), which is
+ * called under local-lock (per-CPU compression stream), so we need to
+ * use GFP_ATOMIC here.
+ */
+static void *zstd_cctx_alloc(void *opaque, size_t size)
+{
+ return kvzalloc(size, GFP_ATOMIC);
+}
+
+static void *zstd_dctx_alloc(void *opaque, size_t size)
+{
+ return kvzalloc(size, GFP_KERNEL);
+}
+
+static void zstd_ctx_free(void *opaque, void *address)
+{
+ kvfree(address);
+}
+
static void zstd_destroy(void *ctx)
{
struct zstd_ctx *zctx = ctx;

vfree(zctx->cctx_mem);
vfree(zctx->dctx_mem);
+ ZSTD_freeCDict(zctx->cdict);
+ ZSTD_freeDDict(zctx->ddict);
kfree(zctx);
}

static void *zstd_create(struct zcomp_config *config)
{
- zstd_parameters params;
struct zstd_ctx *ctx;
- size_t sz;

ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -39,24 +63,64 @@ static void *zstd_create(struct zcomp_config *config)
else
ctx->level = ZSTD_defaultCLevel();

- params = zstd_get_params(ctx->level, PAGE_SIZE);
- sz = zstd_cctx_workspace_bound(&params.cParams);
- ctx->cctx_mem = vzalloc(sz);
- if (!ctx->cctx_mem)
- goto error;
-
- ctx->cctx = zstd_init_cctx(ctx->cctx_mem, sz);
- if (!ctx->cctx)
- goto error;
-
- sz = zstd_dctx_workspace_bound();
- ctx->dctx_mem = vzalloc(sz);
- if (!ctx->dctx_mem)
- goto error;
-
- ctx->dctx = zstd_init_dctx(ctx->dctx_mem, sz);
- if (!ctx->dctx)
- goto error;
+ ctx->cctx_cmem.customAlloc = zstd_cctx_alloc;
+ ctx->cctx_cmem.customFree = zstd_ctx_free;
+ ctx->dctx_cmem.customAlloc = zstd_dctx_alloc;
+ ctx->dctx_cmem.customFree = zstd_ctx_free;
+
+ if (config->dict_sz == 0) {
+ zstd_parameters params;
+ size_t sz;
+
+ params = zstd_get_params(ctx->level, PAGE_SIZE);
+ sz = zstd_cctx_workspace_bound(&params.cParams);
+ ctx->cctx_mem = vzalloc(sz);
+ if (!ctx->cctx_mem)
+ goto error;
+
+ ctx->cctx = zstd_init_cctx(ctx->cctx_mem, sz);
+ if (!ctx->cctx)
+ goto error;
+
+ sz = zstd_dctx_workspace_bound();
+ ctx->dctx_mem = vzalloc(sz);
+ if (!ctx->dctx_mem)
+ goto error;
+
+ ctx->dctx = zstd_init_dctx(ctx->dctx_mem, sz);
+ if (!ctx->dctx)
+ goto error;
+ } else {
+ ZSTD_compressionParameters params;
+
+ ctx->cctx = ZSTD_createCCtx_advanced(ctx->cctx_cmem);
+ if (!ctx->cctx)
+ goto error;
+
+ ctx->dctx = ZSTD_createDCtx_advanced(ctx->dctx_cmem);
+ if (!ctx->dctx)
+ goto error;
+
+ params = ZSTD_getCParams(ctx->level, PAGE_SIZE,
+ config->dict_sz);
+
+ ctx->cdict = ZSTD_createCDict_advanced(config->dict,
+ config->dict_sz,
+ ZSTD_dlm_byRef,
+ ZSTD_dct_auto,
+ params,
+ ctx->cctx_cmem);
+ if (!ctx->cdict)
+ goto error;
+
+ ctx->ddict = ZSTD_createDDict_advanced(config->dict,
+ config->dict_sz,
+ ZSTD_dlm_byRef,
+ ZSTD_dct_auto,
+ ctx->dctx_cmem);
+ if (!ctx->ddict)
+ goto error;
+ }

return ctx;

@@ -72,8 +136,12 @@ static int zstd_compress(void *ctx, const unsigned char *src,
const zstd_parameters params = zstd_get_params(zctx->level, PAGE_SIZE);
size_t ret;

- ret = zstd_compress_cctx(zctx->cctx, dst, *dst_len,
- src, PAGE_SIZE, &params);
+ if (!zctx->cdict)
+ ret = zstd_compress_cctx(zctx->cctx, dst, *dst_len,
+ src, PAGE_SIZE, &params);
+ else
+ ret = ZSTD_compress_usingCDict(zctx->cctx, dst, *dst_len,
+ src, PAGE_SIZE, zctx->cdict);
if (zstd_is_error(ret))
return -EINVAL;
*dst_len = ret;
@@ -86,7 +154,12 @@ static int zstd_decompress(void *ctx, const unsigned char *src, size_t src_len,
struct zstd_ctx *zctx = ctx;
size_t ret;

- ret = zstd_decompress_dctx(zctx->dctx, dst, PAGE_SIZE, src, src_len);
+ if (!zctx->ddict)
+ ret = zstd_decompress_dctx(zctx->dctx, dst, PAGE_SIZE,
+ src, src_len);
+ else
+ ret = ZSTD_decompress_usingDDict(zctx->dctx, dst, PAGE_SIZE,
+ src, src_len, zctx->ddict);
if (zstd_is_error(ret))
return -EINVAL;
return 0;
--
2.45.0.rc1.225.g2a3ae87e7f-goog


2024-05-04 06:02:27

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 13/14] zram: add dictionary support to zstd backend

On (24/05/03 18:17), Sergey Senozhatsky wrote:
> This adds support for pre-trained zstd dictionaries [1]
> Dictionary is loaded once (per-config) and then loaded to Cctx
> and Dctx by reference, so we don't allocate extra memory.
>
> The patch is a little non-trivial, as it seems that noone
> ever attempted to use dictionaries in the linux kernel
> port of zstd.
>
> It also uses GFP_KERNEL gfp in Cctx customAlloc(). We probably
> would want to do something about it. Either make sure that we
> always (somehow) fully setup all Cctx contexts from non-atomic
> context before we attempt to use them, come up with some sort
> of custom allocator or stop calling zcomp_compress() from atomic
> context.
>
> [1] https://github.com/facebook/zstd/blob/dev/programs/zstd.1.md#dictionary-builder

JFI
I reworked this patch quite significantly in v2 of the series.
I guess I'll post it soon.

2024-05-04 06:55:33

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

Hi Sergey,

kernel test robot noticed the following build errors:

[auto build test ERROR on axboe-block/for-next]
[also build test ERROR on akpm-mm/mm-everything linus/master v6.9-rc6 next-20240503]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Sergey-Senozhatsky/zram-move-from-crypto-API-to-custom-comp-backends-API/20240503-172335
base: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
patch link: https://lore.kernel.org/r/20240503091823.3616962-9-senozhatsky%40chromium.org
patch subject: [PATCH 08/14] zram: check that backends array has at least one backend
config: s390-defconfig (https://download.01.org/0day-ci/archive/20240504/[email protected]/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 37ae4ad0eef338776c7e2cffb3896153d43dcd90)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240504/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from drivers/block/zram/zcomp.c:12:
In file included from include/linux/cpu.h:17:
In file included from include/linux/node.h:18:
In file included from include/linux/device.h:32:
In file included from include/linux/device/driver.h:21:
In file included from include/linux/module.h:19:
In file included from include/linux/elf.h:6:
In file included from arch/s390/include/asm/elf.h:173:
In file included from arch/s390/include/asm/mmu_context.h:11:
In file included from arch/s390/include/asm/pgalloc.h:18:
In file included from include/linux/mm.h:2208:
include/linux/vmstat.h:508:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
508 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
509 | item];
| ~~~~
include/linux/vmstat.h:515:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
515 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
516 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
include/linux/vmstat.h:522:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
522 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
| ~~~~~~~~~~~ ^ ~~~
include/linux/vmstat.h:527:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
527 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
528 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
include/linux/vmstat.h:536:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
536 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
537 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
>> drivers/block/zram/zcomp.c:214:2: error: call to '__compiletime_assert_285' declared with 'error' attribute: BUILD_BUG_ON failed: ARRAY_SIZE(backends) <= 1
214 | BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
| ^
include/linux/build_bug.h:50:2: note: expanded from macro 'BUILD_BUG_ON'
50 | BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
| ^
include/linux/build_bug.h:39:37: note: expanded from macro 'BUILD_BUG_ON_MSG'
39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
| ^
include/linux/compiler_types.h:449:2: note: expanded from macro 'compiletime_assert'
449 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^
include/linux/compiler_types.h:437:2: note: expanded from macro '_compiletime_assert'
437 | __compiletime_assert(condition, msg, prefix, suffix)
| ^
include/linux/compiler_types.h:430:4: note: expanded from macro '__compiletime_assert'
430 | prefix ## suffix(); \
| ^
<scratch space>:97:1: note: expanded from here
97 | __compiletime_assert_285
| ^
5 warnings and 1 error generated.


vim +214 drivers/block/zram/zcomp.c

202
203 struct zcomp *zcomp_create(const char *alg)
204 {
205 struct zcomp *comp;
206 int error;
207
208 /*
209 * The backends array has a sentinel NULL value, so the minimum
210 * size is 1. In order to be valid the array, apart from the
211 * sentinel NULL element, should have at least one compression
212 * backend selected.
213 */
> 214 BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2024-05-04 07:14:53

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/04 14:54), kernel test robot wrote:
> | ~~~~~~~~~~~~~~~~~~~~~~
> >> drivers/block/zram/zcomp.c:214:2: error: call to '__compiletime_assert_285' declared with 'error' attribute: BUILD_BUG_ON failed: ARRAY_SIZE(backends) <= 1
> 214 | BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
> | ^

So this is what that BUILD_BUG_ON() is supposed to catch. You don't
have any backends selected in your .config:

# CONFIG_ZRAM_BACKEND_LZO is not set
# CONFIG_ZRAM_BACKEND_LZ4 is not set
# CONFIG_ZRAM_BACKEND_LZ4HC is not set
# CONFIG_ZRAM_BACKEND_ZSTD is not set
# CONFIG_ZRAM_BACKEND_DEFLATE is not set
CONFIG_ZRAM_DEF_COMP="unset-value"

Which is invalid configuration because it means that zram has no
compression enabled.

2024-05-04 07:17:07

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

Hi Sergey,

kernel test robot noticed the following build errors:

[auto build test ERROR on axboe-block/for-next]
[also build test ERROR on akpm-mm/mm-everything linus/master v6.9-rc6 next-20240503]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Sergey-Senozhatsky/zram-move-from-crypto-API-to-custom-comp-backends-API/20240503-172335
base: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
patch link: https://lore.kernel.org/r/20240503091823.3616962-9-senozhatsky%40chromium.org
patch subject: [PATCH 08/14] zram: check that backends array has at least one backend
config: x86_64-rhel-8.3 (https://download.01.org/0day-ci/archive/20240504/[email protected]/config)
compiler: gcc-13 (Ubuntu 13.2.0-4ubuntu3) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240504/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from <command-line>:
drivers/block/zram/zcomp.c: In function 'zcomp_create':
>> include/linux/compiler_types.h:449:45: error: call to '__compiletime_assert_419' declared with attribute error: BUILD_BUG_ON failed: ARRAY_SIZE(backends) <= 1
449 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^
include/linux/compiler_types.h:430:25: note: in definition of macro '__compiletime_assert'
430 | prefix ## suffix(); \
| ^~~~~~
include/linux/compiler_types.h:449:9: note: in expansion of macro '_compiletime_assert'
449 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:39:37: note: in expansion of macro 'compiletime_assert'
39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
| ^~~~~~~~~~~~~~~~~~
include/linux/build_bug.h:50:9: note: in expansion of macro 'BUILD_BUG_ON_MSG'
50 | BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
| ^~~~~~~~~~~~~~~~
drivers/block/zram/zcomp.c:214:9: note: in expansion of macro 'BUILD_BUG_ON'
214 | BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
| ^~~~~~~~~~~~


vim +/__compiletime_assert_419 +449 include/linux/compiler_types.h

eb5c2d4b45e3d2 Will Deacon 2020-07-21 435
eb5c2d4b45e3d2 Will Deacon 2020-07-21 436 #define _compiletime_assert(condition, msg, prefix, suffix) \
eb5c2d4b45e3d2 Will Deacon 2020-07-21 437 __compiletime_assert(condition, msg, prefix, suffix)
eb5c2d4b45e3d2 Will Deacon 2020-07-21 438
eb5c2d4b45e3d2 Will Deacon 2020-07-21 439 /**
eb5c2d4b45e3d2 Will Deacon 2020-07-21 440 * compiletime_assert - break build and emit msg if condition is false
eb5c2d4b45e3d2 Will Deacon 2020-07-21 441 * @condition: a compile-time constant condition to check
eb5c2d4b45e3d2 Will Deacon 2020-07-21 442 * @msg: a message to emit if condition is false
eb5c2d4b45e3d2 Will Deacon 2020-07-21 443 *
eb5c2d4b45e3d2 Will Deacon 2020-07-21 444 * In tradition of POSIX assert, this macro will break the build if the
eb5c2d4b45e3d2 Will Deacon 2020-07-21 445 * supplied condition is *false*, emitting the supplied error message if the
eb5c2d4b45e3d2 Will Deacon 2020-07-21 446 * compiler has support to do so.
eb5c2d4b45e3d2 Will Deacon 2020-07-21 447 */
eb5c2d4b45e3d2 Will Deacon 2020-07-21 448 #define compiletime_assert(condition, msg) \
eb5c2d4b45e3d2 Will Deacon 2020-07-21 @449 _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
eb5c2d4b45e3d2 Will Deacon 2020-07-21 450

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2024-05-04 23:10:27

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On Sat, 4 May 2024 16:14:16 +0900 Sergey Senozhatsky <[email protected]> wrote:

> On (24/05/04 14:54), kernel test robot wrote:
> > | ~~~~~~~~~~~~~~~~~~~~~~
> > >> drivers/block/zram/zcomp.c:214:2: error: call to '__compiletime_assert_285' declared with 'error' attribute: BUILD_BUG_ON failed: ARRAY_SIZE(backends) <= 1
> > 214 | BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
> > | ^
>
> So this is what that BUILD_BUG_ON() is supposed to catch. You don't
> have any backends selected in your .config:
>
> # CONFIG_ZRAM_BACKEND_LZO is not set
> # CONFIG_ZRAM_BACKEND_LZ4 is not set
> # CONFIG_ZRAM_BACKEND_LZ4HC is not set
> # CONFIG_ZRAM_BACKEND_ZSTD is not set
> # CONFIG_ZRAM_BACKEND_DEFLATE is not set
> CONFIG_ZRAM_DEF_COMP="unset-value"
>
> Which is invalid configuration because it means that zram has no
> compression enabled.

We don't want s390 defconfig to be doing this!

I guess just pick one if none were selected.

2024-05-05 04:40:13

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/04 16:10), Andrew Morton wrote:
> > On (24/05/04 14:54), kernel test robot wrote:
> > > | ~~~~~~~~~~~~~~~~~~~~~~
> > > >> drivers/block/zram/zcomp.c:214:2: error: call to '__compiletime_assert_285' declared with 'error' attribute: BUILD_BUG_ON failed: ARRAY_SIZE(backends) <= 1
> > > 214 | BUILD_BUG_ON(ARRAY_SIZE(backends) <= 1);
> > > | ^
> >
> > So this is what that BUILD_BUG_ON() is supposed to catch. You don't
> > have any backends selected in your .config:
> >
> > # CONFIG_ZRAM_BACKEND_LZO is not set
> > # CONFIG_ZRAM_BACKEND_LZ4 is not set
> > # CONFIG_ZRAM_BACKEND_LZ4HC is not set
> > # CONFIG_ZRAM_BACKEND_ZSTD is not set
> > # CONFIG_ZRAM_BACKEND_DEFLATE is not set
> > CONFIG_ZRAM_DEF_COMP="unset-value"
> >
> > Which is invalid configuration because it means that zram has no
> > compression enabled.
>
> We don't want s390 defconfig to be doing this!
>
> I guess just pick one if none were selected.

I'm looking into it.

We used to have "zram depends on crypto compression algorithm"

: config ZRAM
: tristate "Compressed RAM block device support"
: depends on BLOCK && SYSFS && MMU
: depends on CRYPTO_LZO || CRYPTO_ZSTD || CRYPTO_LZ4 || CRYPTO_LZ4HC || CRYPTO_842

I sort of wanted to change it and make zram select compression algorithm,
instead of depending on some comp algorithm being already selected.
But I can probably keep the old behaviour

: config ZRAM
: tristate "Compressed RAM block device support"
: depends on BLOCK && SYSFS && MMU
: select ZSMALLOC
: depends on (LZO_COMPRESS && LZO_DECOMPRESS) || \
: (LZ4_COMPRESS && LZ4_DECOMPRESS) || \
: (LZ4HC_COMPRESS && LZ4_DECOMPRESS) || \
: (ZSTD_COMPRESS && ZSTD_DECOMPRESS) || \
: (ZLIB_DEFLATE && ZLIB_INFLATE)

2024-05-05 05:13:20

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/05 13:39), Sergey Senozhatsky wrote:
[..]
> > I guess just pick one if none were selected.

How do I pick one if none were selected? Does Kconfig support
something like that?

> : config ZRAM
> : tristate "Compressed RAM block device support"
> : depends on BLOCK && SYSFS && MMU
> : select ZSMALLOC
> : depends on (LZO_COMPRESS && LZO_DECOMPRESS) || \
> : (LZ4_COMPRESS && LZ4_DECOMPRESS) || \
> : (LZ4HC_COMPRESS && LZ4_DECOMPRESS) || \
> : (ZSTD_COMPRESS && ZSTD_DECOMPRESS) || \
> : (ZLIB_DEFLATE && ZLIB_INFLATE)

The problem I'm having with this is that FOO_COMPRESS can be M while
zram needs Y.

2024-05-05 06:48:49

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/05 14:13), Sergey Senozhatsky wrote:
> On (24/05/05 13:39), Sergey Senozhatsky wrote:
> [..]
> > > I guess just pick one if none were selected.
>
> How do I pick one if none were selected? Does Kconfig support
> something like that?

This triggers Kconfig error:

config ZRAM_EMPTY_BACKENDS_FIXUP
bool
depends on ZRAM && !ZRAM_BACKEND_LZO && !ZRAM_BACKEND_LZ4 && \
!ZRAM_BACKEND_LZ4HC && !ZRAM_BACKEND_ZSTD && \
!ZRAM_BACKEND_DEFLATE
select ZRAM_BACKEND_LZO


drivers/block/zram/Kconfig:17:error: recursive dependency detected!
drivers/block/zram/Kconfig:17: symbol ZRAM_BACKEND_LZO is selected by ZRAM_EMPTY_BACKENDS_FIXUP
drivers/block/zram/Kconfig:52: symbol ZRAM_EMPTY_BACKENDS_FIXUP depends on ZRAM_BACKEND_LZO


I'm a little surprised by this - EMPTY_BACKENDS_FIXUP does not depend
on ZRAM_BACKEND_LZO, it depends on NOT ZRAM_BACKEND_LZO.

Let me Cc linux-kbuild. Kbuild folks, how do I workaround this?

2024-05-06 03:22:24

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/05 15:48), Sergey Senozhatsky wrote:
> On (24/05/05 14:13), Sergey Senozhatsky wrote:
> > On (24/05/05 13:39), Sergey Senozhatsky wrote:
> > [..]
> > > > I guess just pick one if none were selected.
> >
> > How do I pick one if none were selected? Does Kconfig support
> > something like that?
>
> This triggers Kconfig error:
>
> config ZRAM_EMPTY_BACKENDS_FIXUP
> bool
> depends on ZRAM && !ZRAM_BACKEND_LZO && !ZRAM_BACKEND_LZ4 && \
> !ZRAM_BACKEND_LZ4HC && !ZRAM_BACKEND_ZSTD && \
> !ZRAM_BACKEND_DEFLATE
> select ZRAM_BACKEND_LZO
>
>
> drivers/block/zram/Kconfig:17:error: recursive dependency detected!
> drivers/block/zram/Kconfig:17: symbol ZRAM_BACKEND_LZO is selected by ZRAM_EMPTY_BACKENDS_FIXUP
> drivers/block/zram/Kconfig:52: symbol ZRAM_EMPTY_BACKENDS_FIXUP depends on ZRAM_BACKEND_LZO
>
>
> I'm a little surprised by this - EMPTY_BACKENDS_FIXUP does not depend
> on ZRAM_BACKEND_LZO, it depends on NOT ZRAM_BACKEND_LZO.
>
> Let me Cc linux-kbuild. Kbuild folks, how do I workaround this?

Is this how one does it?

config ZRAM_BACKEND_LZO
bool "lzo and lzo-rle compression support"
depends on ZRAM
default y if !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
!ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE
default n
select LZO_COMPRESS
select LZO_DECOMPRESS


User still can select N and then we'll have empty backends, but
at least default is Y if none of the algorithms were selected.
Is it good enough?

2024-05-06 05:21:52

by Masahiro Yamada

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On Mon, May 6, 2024 at 12:22 PM Sergey Senozhatsky
<[email protected]> wrote:
>
> On (24/05/05 15:48), Sergey Senozhatsky wrote:
> > On (24/05/05 14:13), Sergey Senozhatsky wrote:
> > > On (24/05/05 13:39), Sergey Senozhatsky wrote:
> > > [..]
> > > > > I guess just pick one if none were selected.
> > >
> > > How do I pick one if none were selected? Does Kconfig support
> > > something like that?
> >
> > This triggers Kconfig error:
> >
> > config ZRAM_EMPTY_BACKENDS_FIXUP
> > bool
> > depends on ZRAM && !ZRAM_BACKEND_LZO && !ZRAM_BACKEND_LZ4 && \
> > !ZRAM_BACKEND_LZ4HC && !ZRAM_BACKEND_ZSTD && \
> > !ZRAM_BACKEND_DEFLATE
> > select ZRAM_BACKEND_LZO
> >
> >
> > drivers/block/zram/Kconfig:17:error: recursive dependency detected!
> > drivers/block/zram/Kconfig:17: symbol ZRAM_BACKEND_LZO is selected by ZRAM_EMPTY_BACKENDS_FIXUP
> > drivers/block/zram/Kconfig:52: symbol ZRAM_EMPTY_BACKENDS_FIXUP depends on ZRAM_BACKEND_LZO
> >
> >
> > I'm a little surprised by this - EMPTY_BACKENDS_FIXUP does not depend
> > on ZRAM_BACKEND_LZO, it depends on NOT ZRAM_BACKEND_LZO.
> >
> > Let me Cc linux-kbuild. Kbuild folks, how do I workaround this?
>
> Is this how one does it?
>
> config ZRAM_BACKEND_LZO
> bool "lzo and lzo-rle compression support"
> depends on ZRAM
> default y if !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
> !ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE
> default n
> select LZO_COMPRESS
> select LZO_DECOMPRESS
>
>
> User still can select N and then we'll have empty backends, but
> at least default is Y if none of the algorithms were selected.
> Is it good enough?


I interpret this sentence into:

"randconfig will eventually disable all ZRAM_BACKEND_*,
causing the build error again.
Is it good enough, Arnd?"



Some possible solutions:



config ZRAM_BACKEND_FORCE_LZO
def_bool !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
!ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE
depends on ZRAM
select ZRAM_BACKEND_LZO

config ZRAM_BACKEND_LZO
bool "lzo and lzo-rle compression support"
depends on ZRAM
select LZO_COMPRESS
select LZO_DECOMPRESS


OR


config ZRAM_BACKEND_FORCE_LZO
def_bool !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
!ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE

config ZRAM_BACKEND_LZO
bool "lzo and lzo-rle compression support" if !ZRAM_BACKEND_FORCE_LZO
depends on ZRAM
default ZRAM_BACKEND_FORCE_LZO
select LZO_COMPRESS
select LZO_DECOMPRESS




BTW, "default n" you are adding are redundant.

--
Best Regards
Masahiro Yamada

2024-05-06 06:43:53

by Sergey Senozhatsky

[permalink] [raw]
Subject: Re: [PATCH 08/14] zram: check that backends array has at least one backend

On (24/05/06 14:20), Masahiro Yamada wrote:
> config ZRAM_BACKEND_FORCE_LZO
> def_bool !ZRAM_BACKEND_LZ4 && !ZRAM_BACKEND_LZ4HC && \
> !ZRAM_BACKEND_ZSTD && !ZRAM_BACKEND_DEFLATE
>
> config ZRAM_BACKEND_LZO
> bool "lzo and lzo-rle compression support" if !ZRAM_BACKEND_FORCE_LZO
> depends on ZRAM
> default ZRAM_BACKEND_FORCE_LZO
> select LZO_COMPRESS
> select LZO_DECOMPRESS

I'll take this one. Thank you.

> BTW, "default n" you are adding are redundant.

OK.