All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv5 00/13] zram: Support multiple compression streams
@ 2022-11-09 11:50 Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 01/13] zram: Preparation for multi-zcomp support Sergey Senozhatsky
                   ` (13 more replies)
  0 siblings, 14 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Hello,

	This series adds support for multiple compression streams.
The main idea is that different compression algorithms have different
characteristics and zram may benefit when it uses a combination of
algorithms: a default algorithm that is faster but have lower
compression rate and a secondary algorithm that can use higher
compression rate at a price of slower compression/decompression.

	There are several use-case for this functionality:

- huge pages re-compression: zstd or deflate can successfully
compress huge pages (~50% of huge pages on my synthetic ChromeOS
tests), IOW pages that lzo was not able to compress.

- idle pages re-compression: idle/cold pages sit in the memory
and we may reduce zsmalloc memory usage if we recompress those
idle pages.

	User-space has a number of ways to control the behavior
and impact of zram recompression: what type of pages should be
recompressed, size watermarks, etc. Please refer to documentation
patch.

v5:
-- Addressed (very valuable) review feedback from Minchan
-- Extended documentation
-- We now do chain recompression, tryin algos in order of their priority
-- Support up to 4 compression streams
-- Added named parameters to recomp_algorithm and recompress sysfs knobs
-- Cherry-picked patch from Alexey
-- Store algo priority in mete flags
-- Renamed some fo the flags
-- Added incompressible bit to block state output
-- Added incompressible writeback
-- etc.

v4:
-- added IS_ERR_VALUE patch (Andrew)
-- documented SIZE units (bytes) (Andrew)
-- re-phrased writeback BIO error comment (Andrew)
-- return zs_malloc() error code from zram_recompress()
-- do not lose zram_recompress() error in recompress_store()
-- corrected a typo
-- fixed previous rebase errors
-- rebased the series

v3:
-- conditionally reschedule during recompression loop so that
   we don't stall RCU grace periods
-- fixed a false-positive WARN_ON

v2:
-- rebased
-- mark completely incompressible pages (neither default nor secondary
   algorithm can compress them) with a new flag so that we don't attempt
   to recompress them all the time

Alexey Romanov (1):
  zram: add size class equals check into recompression

Sergey Senozhatsky (12):
  zram: Preparation for multi-zcomp support
  zram: Add recompression algorithm sysfs knob
  zram: Factor out WB and non-WB zram read functions
  zram: Introduce recompress sysfs knob
  zram: Add recompress flag to read_block_state()
  zram: Clarify writeback_store() comment
  zram: Use IS_ERR_VALUE() to check for zs_malloc() errors
  zram: remove redundant checks from zram_recompress()
  zram: Add algo parameter support to zram_recompress()
  documentation: Add zram recompression documentation
  zram: add incompressible writeback
  zram: Add incompressible flag to read_block_state()

 Documentation/admin-guide/blockdev/zram.rst | 100 +++-
 drivers/block/zram/Kconfig                  |   9 +
 drivers/block/zram/zcomp.c                  |   6 +-
 drivers/block/zram/zcomp.h                  |   2 +-
 drivers/block/zram/zram_drv.c               | 604 +++++++++++++++++---
 drivers/block/zram/zram_drv.h               |  22 +-
 include/linux/zsmalloc.h                    |   2 +
 mm/zsmalloc.c                               |  21 +
 8 files changed, 685 insertions(+), 81 deletions(-)

-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCHv5 01/13] zram: Preparation for multi-zcomp support
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 02/13] zram: Add recompression algorithm sysfs knob Sergey Senozhatsky
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

The patch turns compression streams and compressor algorithm
name struct zram members into arrays, so that we can have
multiple compression streams support (in the next patches).

The patch uses a rather explicit API for compressor selection:

- Get primary (default) compression stream
	zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP])
- Get secondary compression stream
	zcomp_stream_get(zram->comps[ZRAM_SECONDARY_COMP])

We use similar API for compression streams put().

At this point we always have just one compression stream,
since CONFIG_ZRAM_MULTI_COMP is not yet defined.

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zcomp.c    |  6 +--
 drivers/block/zram/zcomp.h    |  2 +-
 drivers/block/zram/zram_drv.c | 90 +++++++++++++++++++++++++----------
 drivers/block/zram/zram_drv.h | 14 +++++-
 4 files changed, 80 insertions(+), 32 deletions(-)

diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 0916de952e09..55af4efd7983 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -206,7 +206,7 @@ void zcomp_destroy(struct zcomp *comp)
  * case of allocation error, or any other error potentially
  * returned by zcomp_init().
  */
-struct zcomp *zcomp_create(const char *compress)
+struct zcomp *zcomp_create(const char *alg)
 {
 	struct zcomp *comp;
 	int error;
@@ -216,14 +216,14 @@ struct zcomp *zcomp_create(const char *compress)
 	 * 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(compress))
+	if (!zcomp_available_algorithm(alg))
 		return ERR_PTR(-EINVAL);
 
 	comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
 	if (!comp)
 		return ERR_PTR(-ENOMEM);
 
-	comp->name = compress;
+	comp->name = alg;
 	error = zcomp_init(comp);
 	if (error) {
 		kfree(comp);
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 40f6420f4b2e..cdefdef93da8 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -27,7 +27,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 *comp);
+struct zcomp *zcomp_create(const char *alg);
 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 966aab902d19..5371ed63c785 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1007,36 +1007,53 @@ static ssize_t comp_algorithm_show(struct device *dev,
 	struct zram *zram = dev_to_zram(dev);
 
 	down_read(&zram->init_lock);
-	sz = zcomp_available_show(zram->compressor, buf);
+	sz = zcomp_available_show(zram->comp_algs[ZRAM_PRIMARY_COMP], 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)
 {
 	struct zram *zram = dev_to_zram(dev);
-	char compressor[ARRAY_SIZE(zram->compressor)];
+	char *compressor;
 	size_t sz;
 
-	strscpy(compressor, buf, sizeof(compressor));
+	sz = strlen(buf);
+	if (sz >= CRYPTO_MAX_ALG_NAME)
+		return -E2BIG;
+
+	compressor = kstrdup(buf, GFP_KERNEL);
+	if (!compressor)
+		return -ENOMEM;
+
 	/* ignore trailing newline */
-	sz = strlen(compressor);
 	if (sz > 0 && compressor[sz - 1] == '\n')
 		compressor[sz - 1] = 0x00;
 
-	if (!zcomp_available_algorithm(compressor))
+	if (!zcomp_available_algorithm(compressor)) {
+		kfree(compressor);
 		return -EINVAL;
+	}
 
 	down_write(&zram->init_lock);
 	if (init_done(zram)) {
 		up_write(&zram->init_lock);
+		kfree(compressor);
 		pr_info("Can't change algorithm for initialized device\n");
 		return -EBUSY;
 	}
 
-	strcpy(zram->compressor, compressor);
+	comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, compressor);
 	up_write(&zram->init_lock);
 	return len;
 }
@@ -1284,7 +1301,7 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 	size = zram_get_obj_size(zram, index);
 
 	if (size != PAGE_SIZE)
-		zstrm = zcomp_stream_get(zram->comp);
+		zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
 
 	src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
 	if (size == PAGE_SIZE) {
@@ -1296,7 +1313,7 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 		dst = kmap_atomic(page);
 		ret = zcomp_decompress(zstrm, src, size, dst);
 		kunmap_atomic(dst);
-		zcomp_stream_put(zram->comp);
+		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 	}
 	zs_unmap_object(zram->mem_pool, handle);
 	zram_slot_unlock(zram, index);
@@ -1363,13 +1380,13 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 	kunmap_atomic(mem);
 
 compress_again:
-	zstrm = zcomp_stream_get(zram->comp);
+	zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
 	src = kmap_atomic(page);
 	ret = zcomp_compress(zstrm, src, &comp_len);
 	kunmap_atomic(src);
 
 	if (unlikely(ret)) {
-		zcomp_stream_put(zram->comp);
+		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 		pr_err("Compression failed! err=%d\n", ret);
 		zs_free(zram->mem_pool, handle);
 		return ret;
@@ -1397,7 +1414,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 				__GFP_HIGHMEM |
 				__GFP_MOVABLE);
 	if (IS_ERR((void *)handle)) {
-		zcomp_stream_put(zram->comp);
+		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 		atomic64_inc(&zram->stats.writestall);
 		handle = zs_malloc(zram->mem_pool, comp_len,
 				GFP_NOIO | __GFP_HIGHMEM |
@@ -1414,14 +1431,14 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 		 * zstrm buffer back. It is necessary that the dereferencing
 		 * of the zstrm variable below occurs correctly.
 		 */
-		zstrm = zcomp_stream_get(zram->comp);
+		zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
 	}
 
 	alloced_pages = zs_get_total_pages(zram->mem_pool);
 	update_used_max(zram, alloced_pages);
 
 	if (zram->limit_pages && alloced_pages > zram->limit_pages) {
-		zcomp_stream_put(zram->comp);
+		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 		zs_free(zram->mem_pool, handle);
 		return -ENOMEM;
 	}
@@ -1435,7 +1452,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 	if (comp_len == PAGE_SIZE)
 		kunmap_atomic(src);
 
-	zcomp_stream_put(zram->comp);
+	zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 	zs_unmap_object(zram->mem_pool, handle);
 	atomic64_add(comp_len, &zram->stats.compr_data_size);
 out:
@@ -1710,6 +1727,20 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
 	return ret;
 }
 
+static void zram_destroy_comps(struct zram *zram)
+{
+	u32 prio;
+
+	for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) {
+		struct zcomp *comp = zram->comps[prio];
+
+		zram->comps[prio] = NULL;
+		if (!comp)
+			continue;
+		zcomp_destroy(comp);
+	}
+}
+
 static void zram_reset_device(struct zram *zram)
 {
 	down_write(&zram->init_lock);
@@ -1727,11 +1758,11 @@ static void zram_reset_device(struct zram *zram)
 	/* I/O operation under all of CPU are done so let's free */
 	zram_meta_free(zram, zram->disksize);
 	zram->disksize = 0;
+	zram_destroy_comps(zram);
 	memset(&zram->stats, 0, sizeof(zram->stats));
-	zcomp_destroy(zram->comp);
-	zram->comp = NULL;
 	reset_bdev(zram);
 
+	comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor);
 	up_write(&zram->init_lock);
 }
 
@@ -1742,6 +1773,7 @@ static ssize_t disksize_store(struct device *dev,
 	struct zcomp *comp;
 	struct zram *zram = dev_to_zram(dev);
 	int err;
+	u32 prio;
 
 	disksize = memparse(buf, NULL);
 	if (!disksize)
@@ -1760,22 +1792,28 @@ static ssize_t disksize_store(struct device *dev,
 		goto out_unlock;
 	}
 
-	comp = zcomp_create(zram->compressor);
-	if (IS_ERR(comp)) {
-		pr_err("Cannot initialise %s compressing backend\n",
-				zram->compressor);
-		err = PTR_ERR(comp);
-		goto out_free_meta;
-	}
+	for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) {
+		if (!zram->comp_algs[prio])
+			continue;
+
+		comp = zcomp_create(zram->comp_algs[prio]);
+		if (IS_ERR(comp)) {
+			pr_err("Cannot initialise %s compressing backend\n",
+			       zram->comp_algs[prio]);
+			err = PTR_ERR(comp);
+			goto out_free_comps;
+		}
 
-	zram->comp = comp;
+		zram->comps[prio] = comp;
+	}
 	zram->disksize = disksize;
 	set_capacity_and_notify(zram->disk, zram->disksize >> SECTOR_SHIFT);
 	up_write(&zram->init_lock);
 
 	return len;
 
-out_free_meta:
+out_free_comps:
+	zram_destroy_comps(zram);
 	zram_meta_free(zram, disksize);
 out_unlock:
 	up_write(&zram->init_lock);
@@ -1962,7 +2000,7 @@ static int zram_add(void)
 	if (ret)
 		goto out_cleanup_disk;
 
-	strscpy(zram->compressor, default_compressor, sizeof(zram->compressor));
+	zram->comp_algs[ZRAM_PRIMARY_COMP] = default_compressor;
 
 	zram_debugfs_register(zram);
 	pr_info("Added device: %s\n", zram->disk->disk_name);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index a2bda53020fd..7a643c8c38ec 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -89,10 +89,20 @@ struct zram_stats {
 #endif
 };
 
+#ifdef CONFIG_ZRAM_MULTI_COMP
+#define ZRAM_PRIMARY_COMP	0U
+#define ZRAM_SECONDARY_COMP	1U
+#define ZRAM_MAX_COMPS	4U
+#else
+#define ZRAM_PRIMARY_COMP	0U
+#define ZRAM_SECONDARY_COMP	0U
+#define ZRAM_MAX_COMPS	1U
+#endif
+
 struct zram {
 	struct zram_table_entry *table;
 	struct zs_pool *mem_pool;
-	struct zcomp *comp;
+	struct zcomp *comps[ZRAM_MAX_COMPS];
 	struct gendisk *disk;
 	/* Prevent concurrent execution of device init */
 	struct rw_semaphore init_lock;
@@ -107,7 +117,7 @@ struct zram {
 	 * we can store in a disk.
 	 */
 	u64 disksize;	/* bytes */
-	char compressor[CRYPTO_MAX_ALG_NAME];
+	const char *comp_algs[ZRAM_MAX_COMPS];
 	/*
 	 * zram is claimed so open request will be failed
 	 */
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 02/13] zram: Add recompression algorithm sysfs knob
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 01/13] zram: Preparation for multi-zcomp support Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 03/13] zram: Factor out WB and non-WB zram read functions Sergey Senozhatsky
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

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.

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 124 ++++++++++++++++++++++++++++------
 1 file changed, 105 insertions(+), 19 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 5371ed63c785..56026a6deb70 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1000,31 +1000,28 @@ static ssize_t max_comp_streams_store(struct device *dev,
 	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)
+static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf)
 {
-	/* 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)
-{
-	struct zram *zram = dev_to_zram(dev);
 	char *compressor;
 	size_t sz;
 
@@ -1053,11 +1050,94 @@ static ssize_t comp_algorithm_store(struct device *dev,
 		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, &param, &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)
 {
@@ -1898,6 +1978,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,
@@ -1921,6 +2004,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,
 };
 
@@ -2000,7 +2086,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);
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 03/13] zram: Factor out WB and non-WB zram read functions
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 01/13] zram: Preparation for multi-zcomp support Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 02/13] zram: Add recompression algorithm sysfs knob Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

We will use non-WB variant in ZRAM page recompression path.

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 72 ++++++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 23 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 56026a6deb70..a6a5fd2474d7 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1339,8 +1339,29 @@ static void zram_free_page(struct zram *zram, size_t index)
 		~(1UL << ZRAM_LOCK | 1UL << ZRAM_UNDER_WB));
 }
 
-static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
-				struct bio *bio, bool partial_io)
+/*
+ * Reads a page from the writeback devices. Corresponding ZRAM slot
+ * should be unlocked.
+ */
+static int zram_bvec_read_from_bdev(struct zram *zram, struct page *page,
+				    u32 index, struct bio *bio, bool partial_io)
+{
+	struct bio_vec bvec = {
+		.bv_page = page,
+		.bv_len = PAGE_SIZE,
+		.bv_offset = 0,
+	};
+
+	return read_from_bdev(zram, &bvec, zram_get_element(zram, index), bio,
+			      partial_io);
+}
+
+/*
+ * Reads (decompresses if needed) a page from zspool (zsmalloc).
+ * Corresponding ZRAM slot should be locked.
+ */
+static int zram_read_from_zspool(struct zram *zram, struct page *page,
+				 u32 index)
 {
 	struct zcomp_strm *zstrm;
 	unsigned long handle;
@@ -1348,23 +1369,6 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 	void *src, *dst;
 	int ret;
 
-	zram_slot_lock(zram, index);
-	if (zram_test_flag(zram, index, ZRAM_WB)) {
-		struct bio_vec bvec;
-
-		zram_slot_unlock(zram, index);
-		/* A null bio means rw_page was used, we must fallback to bio */
-		if (!bio)
-			return -EOPNOTSUPP;
-
-		bvec.bv_page = page;
-		bvec.bv_len = PAGE_SIZE;
-		bvec.bv_offset = 0;
-		return read_from_bdev(zram, &bvec,
-				zram_get_element(zram, index),
-				bio, partial_io);
-	}
-
 	handle = zram_get_handle(zram, index);
 	if (!handle || zram_test_flag(zram, index, ZRAM_SAME)) {
 		unsigned long value;
@@ -1374,7 +1378,6 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 		mem = kmap_atomic(page);
 		zram_fill_page(mem, PAGE_SIZE, value);
 		kunmap_atomic(mem);
-		zram_slot_unlock(zram, index);
 		return 0;
 	}
 
@@ -1396,17 +1399,40 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 	}
 	zs_unmap_object(zram->mem_pool, handle);
-	zram_slot_unlock(zram, index);
+	return ret;
+}
+
+static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
+			    struct bio *bio, bool partial_io)
+{
+	int ret;
+
+	zram_slot_lock(zram, index);
+	if (!zram_test_flag(zram, index, ZRAM_WB)) {
+		/* Slot should be locked through out the function call */
+		ret = zram_read_from_zspool(zram, page, index);
+		zram_slot_unlock(zram, index);
+	} else {
+		/* Slot should be unlocked before the function call */
+		zram_slot_unlock(zram, index);
+
+		/* A null bio means rw_page was used, we must fallback to bio */
+		if (!bio)
+			return -EOPNOTSUPP;
+
+		ret = zram_bvec_read_from_bdev(zram, page, index, bio,
+					       partial_io);
+	}
 
 	/* Should NEVER happen. Return bio error if it does. */
-	if (WARN_ON(ret))
+	if (WARN_ON(ret < 0))
 		pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
 
 	return ret;
 }
 
 static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
-				u32 index, int offset, struct bio *bio)
+			  u32 index, int offset, struct bio *bio)
 {
 	int ret;
 	struct page *page;
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 04/13] zram: Introduce recompress sysfs knob
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (2 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 03/13] zram: Factor out WB and non-WB zram read functions Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-10 13:09   ` Nathan Chancellor
                     ` (2 more replies)
  2022-11-09 11:50 ` [PATCHv5 05/13] zram: Add recompress flag to read_block_state() Sergey Senozhatsky
                   ` (9 subsequent siblings)
  13 siblings, 3 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Allow zram to recompress (using secondary compression streams)
pages.

Re-compression algorithms (we support up to 3 at this stage)
are selected via recomp_algorithm:

  echo "algo=zstd priority=1" > /sys/block/zramX/recomp_algorithm

Please read documentation for more details.

We support several recompression modes:

1) IDLE pages recompression is activated by `idle` mode

  echo "type=idle" > /sys/block/zram0/recompress

2) Since there may be many idle pages user-space may pass a size
threshold value (in bytes) and we will recompress pages only
of equal or greater size:

  echo "threshold=888" > /sys/block/zram0/recompress

3) HUGE pages recompression is activated by `huge` mode

  echo "type=huge" > /sys/block/zram0/recompress

4) HUGE_IDLE pages recompression is activated by `huge_idle` mode

  echo "type=huge_idle" > /sys/block/zram0/recompress

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/Kconfig    |   9 ++
 drivers/block/zram/zram_drv.c | 264 +++++++++++++++++++++++++++++++++-
 drivers/block/zram/zram_drv.h |   7 +
 3 files changed, 277 insertions(+), 3 deletions(-)

diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig
index d4100b0c083e..0386b7da02aa 100644
--- a/drivers/block/zram/Kconfig
+++ b/drivers/block/zram/Kconfig
@@ -78,3 +78,12 @@ config ZRAM_MEMORY_TRACKING
 	  /sys/kernel/debug/zram/zramX/block_state.
 
 	  See Documentation/admin-guide/blockdev/zram.rst for more information.
+
+config ZRAM_MULTI_COMP
+	bool "Enable multiple compression streams"
+	depends on ZRAM
+	help
+	  This will enable multi-compression streams, so that ZRAM can
+	  re-compress pages using a potentially slower but more effective
+	  compression algorithm. Note, that IDLE page recompression
+	  requires ZRAM_MEMORY_TRACKING.
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a6a5fd2474d7..749e4266dd72 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -155,6 +155,25 @@ static inline bool is_partial_io(struct bio_vec *bvec)
 }
 #endif
 
+static inline void zram_set_priority(struct zram *zram, u32 index, u32 prio)
+{
+	prio &= ZRAM_COMP_PRIORITY_MASK;
+	/*
+	 * Clear previous priority value first, in case if we recompress
+	 * further an already recompressed page
+	 */
+	zram->table[index].flags &= ~(ZRAM_COMP_PRIORITY_MASK <<
+				      ZRAM_COMP_PRIORITY_BIT1);
+	zram->table[index].flags |= (prio << ZRAM_COMP_PRIORITY_BIT1);
+}
+
+static inline u32 zram_get_priority(struct zram *zram, u32 index)
+{
+	u32 prio = zram->table[index].flags >> ZRAM_COMP_PRIORITY_BIT1;
+
+	return prio & ZRAM_COMP_PRIORITY_MASK;
+}
+
 /*
  * Check if request is within bounds and aligned on zram logical blocks.
  */
@@ -1307,6 +1326,11 @@ static void zram_free_page(struct zram *zram, size_t index)
 		atomic64_dec(&zram->stats.huge_pages);
 	}
 
+	if (zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+		zram_clear_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+
+	zram_set_priority(zram, index, 0);
+
 	if (zram_test_flag(zram, index, ZRAM_WB)) {
 		zram_clear_flag(zram, index, ZRAM_WB);
 		free_block_bdev(zram, zram_get_element(zram, index));
@@ -1367,6 +1391,7 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page,
 	unsigned long handle;
 	unsigned int size;
 	void *src, *dst;
+	u32 prio;
 	int ret;
 
 	handle = zram_get_handle(zram, index);
@@ -1383,8 +1408,10 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page,
 
 	size = zram_get_obj_size(zram, index);
 
-	if (size != PAGE_SIZE)
-		zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
+	if (size != PAGE_SIZE) {
+		prio = zram_get_priority(zram, index);
+		zstrm = zcomp_stream_get(zram->comps[prio]);
+	}
 
 	src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
 	if (size == PAGE_SIZE) {
@@ -1396,7 +1423,7 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page,
 		dst = kmap_atomic(page);
 		ret = zcomp_decompress(zstrm, src, size, dst);
 		kunmap_atomic(dst);
-		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
+		zcomp_stream_put(zram->comps[prio]);
 	}
 	zs_unmap_object(zram->mem_pool, handle);
 	return ret;
@@ -1627,6 +1654,235 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 	return ret;
 }
 
+#ifdef CONFIG_ZRAM_MULTI_COMP
+/*
+ * This function will decompress (unless it's ZRAM_HUGE) the page and then
+ * attempt to compress it using provided compression algorithm priority
+ * (which is potentially more effective).
+ *
+ * Corresponding ZRAM slot should be locked.
+ */
+static int zram_recompress(struct zram *zram, u32 index, struct page *page,
+			   u32 threshold, u32 prio, u32 prio_max)
+{
+	struct zcomp_strm *zstrm = NULL;
+	unsigned long handle_old;
+	unsigned long handle_new;
+	unsigned int comp_len_old;
+	unsigned int comp_len_new;
+	void *src, *dst;
+	int ret;
+
+	handle_old = zram_get_handle(zram, index);
+	if (!handle_old)
+		return -EINVAL;
+
+	comp_len_old = zram_get_obj_size(zram, index);
+	/*
+	 * Do not recompress objects that are already "small enough".
+	 */
+	if (comp_len_old < threshold)
+		return 0;
+
+	ret = zram_read_from_zspool(zram, page, index);
+	if (ret)
+		return ret;
+
+	/*
+	 * Iterate the secondary comp algorithms list (in order of priority)
+	 * and try to recompress the page.
+	 */
+	for (; prio < prio_max; prio++) {
+		if (!zram->comps[prio])
+			continue;
+
+		/*
+		 * Skip if the object is already re-compressed with a higher
+		 * priority algorithm (or same algorithm).
+		 */
+		if (prio <= zram_get_priority(zram, index))
+			continue;
+
+		zstrm = zcomp_stream_get(zram->comps[prio]);
+		src = kmap_atomic(page);
+		ret = zcomp_compress(zstrm, src, &comp_len_new);
+		kunmap_atomic(src);
+
+		if (ret) {
+			zcomp_stream_put(zram->comps[prio]);
+			return ret;
+		}
+
+		/* Continue until we make progress */
+		if (comp_len_new >= huge_class_size ||
+		    comp_len_new >= comp_len_old ||
+		    (threshold && comp_len_new >= threshold)) {
+			zcomp_stream_put(zram->comps[prio]);
+			continue;
+		}
+
+		/* Recompression was successful so break out */
+		break;
+	}
+
+	/*
+	 * We did not try to recompress, e.g. when we have only one
+	 * secondary algorithm and the page is already recompressed
+	 * using that algorithm
+	 */
+	if (!zstrm)
+		return 0;
+
+	/*
+	 * All secondary algorithms failed to re-compress the page in a way
+	 * that would save memory, mark the object as incompressible so that
+	 * we will not try to compress it again.
+	 */
+	if (comp_len_new >= huge_class_size || comp_len_new >= comp_len_old) {
+		zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+		return 0;
+	}
+
+	/* Successful recompression but above threshold */
+	if (threshold && comp_len_new >= threshold)
+		return 0;
+
+	/*
+	 * No direct reclaim (slow path) for handle allocation and no
+	 * re-compression attempt (unlike in __zram_bvec_write()) since
+	 * we already have stored that object in zsmalloc. If we cannot
+	 * alloc memory for recompressed object then we bail out and
+	 * simply keep the old (existing) object in zsmalloc.
+	 */
+	handle_new = zs_malloc(zram->mem_pool, comp_len_new,
+			       __GFP_KSWAPD_RECLAIM |
+			       __GFP_NOWARN |
+			       __GFP_HIGHMEM |
+			       __GFP_MOVABLE);
+	if (IS_ERR_VALUE(handle_new)) {
+		zcomp_stream_put(zram->comps[prio]);
+		return PTR_ERR((void *)handle_new);
+	}
+
+	dst = zs_map_object(zram->mem_pool, handle_new, ZS_MM_WO);
+	memcpy(dst, zstrm->buffer, comp_len_new);
+	zcomp_stream_put(zram->comps[prio]);
+
+	zs_unmap_object(zram->mem_pool, handle_new);
+
+	zram_free_page(zram, index);
+	zram_set_handle(zram, index, handle_new);
+	zram_set_obj_size(zram, index, comp_len_new);
+	zram_set_priority(zram, index, prio);
+
+	atomic64_add(comp_len_new, &zram->stats.compr_data_size);
+	atomic64_inc(&zram->stats.pages_stored);
+
+	return 0;
+}
+
+#define RECOMPRESS_IDLE		(1 << 0)
+#define RECOMPRESS_HUGE		(1 << 1)
+
+static ssize_t recompress_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct zram *zram = dev_to_zram(dev);
+	u32 mode = 0, threshold = 0, prio = ZRAM_SECONDARY_COMP;
+	unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
+	char *args, *param, *val;
+	unsigned long index;
+	struct page *page;
+	ssize_t ret;
+
+	args = skip_spaces(buf);
+	while (*args) {
+		args = next_arg(args, &param, &val);
+
+		if (!*val)
+			return -EINVAL;
+
+		if (!strcmp(param, "type")) {
+			if (!strcmp(val, "idle"))
+				mode = RECOMPRESS_IDLE;
+			if (!strcmp(val, "huge"))
+				mode = RECOMPRESS_HUGE;
+			if (!strcmp(val, "huge_idle"))
+				mode = RECOMPRESS_IDLE | RECOMPRESS_HUGE;
+			continue;
+		}
+
+		if (!strcmp(param, "threshold")) {
+			/*
+			 * We will re-compress only idle objects equal or
+			 * greater in size than watermark.
+			 */
+			ret = kstrtouint(val, 10, &threshold);
+			if (ret)
+				return ret;
+			continue;
+		}
+	}
+
+	if (threshold >= PAGE_SIZE)
+		return -EINVAL;
+
+	down_read(&zram->init_lock);
+	if (!init_done(zram)) {
+		ret = -EINVAL;
+		goto release_init_lock;
+	}
+
+	page = alloc_page(GFP_KERNEL);
+	if (!page) {
+		ret = -ENOMEM;
+		goto release_init_lock;
+	}
+
+	ret = len;
+	for (index = 0; index < nr_pages; index++) {
+		int err;
+
+		zram_slot_lock(zram, index);
+
+		if (!zram_allocated(zram, index))
+			goto next;
+
+		if (mode & RECOMPRESS_IDLE &&
+		    !zram_test_flag(zram, index, ZRAM_IDLE))
+			goto next;
+
+		if (mode & RECOMPRESS_HUGE &&
+		    !zram_test_flag(zram, index, ZRAM_HUGE))
+			goto next;
+
+		if (zram_test_flag(zram, index, ZRAM_WB) ||
+		    zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
+		    zram_test_flag(zram, index, ZRAM_SAME) ||
+		    zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+			goto next;
+
+		err = zram_recompress(zram, index, page, threshold,
+				      prio, ZRAM_MAX_COMPS);
+next:
+		zram_slot_unlock(zram, index);
+		if (err) {
+			ret = err;
+			break;
+		}
+
+		cond_resched();
+	}
+
+	__free_page(page);
+
+release_init_lock:
+	up_read(&zram->init_lock);
+	return ret;
+}
+#endif
+
 /*
  * zram_bio_discard - handler on discard request
  * @index: physical block index in PAGE_SIZE units
@@ -2006,6 +2262,7 @@ static DEVICE_ATTR_RW(writeback_limit_enable);
 #endif
 #ifdef CONFIG_ZRAM_MULTI_COMP
 static DEVICE_ATTR_RW(recomp_algorithm);
+static DEVICE_ATTR_WO(recompress);
 #endif
 
 static struct attribute *zram_disk_attrs[] = {
@@ -2032,6 +2289,7 @@ static struct attribute *zram_disk_attrs[] = {
 	&dev_attr_debug_stat.attr,
 #ifdef CONFIG_ZRAM_MULTI_COMP
 	&dev_attr_recomp_algorithm.attr,
+	&dev_attr_recompress.attr,
 #endif
 	NULL,
 };
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 7a643c8c38ec..b80faae76835 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -40,6 +40,9 @@
  */
 #define ZRAM_FLAG_SHIFT (PAGE_SHIFT + 1)
 
+/* Only 2 bits are allowed for comp priority index */
+#define ZRAM_COMP_PRIORITY_MASK	0x3
+
 /* Flags for zram pages (table[page_no].flags) */
 enum zram_pageflags {
 	/* zram slot is locked */
@@ -49,6 +52,10 @@ enum zram_pageflags {
 	ZRAM_UNDER_WB,	/* page is under writeback */
 	ZRAM_HUGE,	/* Incompressible page */
 	ZRAM_IDLE,	/* not accessed page since last idle marking */
+	ZRAM_INCOMPRESSIBLE, /* none of the algorithms could compress it */
+
+	ZRAM_COMP_PRIORITY_BIT1, /* First bit of comp priority index */
+	ZRAM_COMP_PRIORITY_BIT2, /* Second bit of comp priority index */
 
 	__NR_ZRAM_PAGEFLAGS,
 };
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 05/13] zram: Add recompress flag to read_block_state()
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (3 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 06/13] zram: Clarify writeback_store() comment Sergey Senozhatsky
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Add a new flag to zram block state that shows if the page
was recompressed (using alternative compression algorithm).

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 Documentation/admin-guide/blockdev/zram.rst | 9 ++++++---
 drivers/block/zram/zram_drv.c               | 5 +++--
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index c73b16930449..177a142c3146 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -411,9 +411,10 @@ pages of the process with*pagemap.
 If you enable the feature, you could see block state via
 /sys/kernel/debug/zram/zram0/block_state". The output is as follows::
 
-	  300    75.033841 .wh.
-	  301    63.806904 s...
-	  302    63.806919 ..hi
+	  300    75.033841 .wh..
+	  301    63.806904 s....
+	  302    63.806919 ..hi.
+	  303    62.801919 ....r
 
 First column
 	zram's block index.
@@ -430,6 +431,8 @@ Third column
 		huge page
 	i:
 		idle page
+	r:
+		recompressed page (secondary compression algorithm)
 
 First line of above example says 300th block is accessed at 75.033841sec
 and the block's state is huge so it is written back to the backing
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 749e4266dd72..560e2932021e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -939,13 +939,14 @@ static ssize_t read_block_state(struct file *file, char __user *buf,
 
 		ts = ktime_to_timespec64(zram->table[index].ac_time);
 		copied = snprintf(kbuf + written, count,
-			"%12zd %12lld.%06lu %c%c%c%c\n",
+			"%12zd %12lld.%06lu %c%c%c%c%c\n",
 			index, (s64)ts.tv_sec,
 			ts.tv_nsec / NSEC_PER_USEC,
 			zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.',
 			zram_test_flag(zram, index, ZRAM_WB) ? 'w' : '.',
 			zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.',
-			zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.');
+			zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.',
+			zram_get_priority(zram, index) ? 'r' : '.');
 
 		if (count <= copied) {
 			zram_slot_unlock(zram, index);
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 06/13] zram: Clarify writeback_store() comment
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (4 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 05/13] zram: Add recompress flag to read_block_state() Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 07/13] zram: Use IS_ERR_VALUE() to check for zs_malloc() errors Sergey Senozhatsky
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Re-phrase writeback BIO error comment.

Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 560e2932021e..a5d2ce0bcd5d 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -772,8 +772,12 @@ static ssize_t writeback_store(struct device *dev,
 			zram_clear_flag(zram, index, ZRAM_IDLE);
 			zram_slot_unlock(zram, index);
 			/*
-			 * Return last IO error unless every IO were
-			 * not suceeded.
+			 * BIO errors are not fatal, we continue and simply
+			 * attempt to writeback the remaining objects (pages).
+			 * At the same time we need to signal user-space that
+			 * some writes (at least one, but also could be all of
+			 * them) were not successful and we do so by returning
+			 * the most recent BIO error.
 			 */
 			ret = err;
 			continue;
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 07/13] zram: Use IS_ERR_VALUE() to check for zs_malloc() errors
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (5 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 06/13] zram: Clarify writeback_store() comment Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 08/13] zram: add size class equals check into recompression Sergey Senozhatsky
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Avoid type casts that are needed for IS_ERR() and use
IS_ERR_VALUE() instead.

Suggested-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a5d2ce0bcd5d..9561569273fe 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1545,19 +1545,19 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 	 * if we have a 'non-null' handle here then we are coming
 	 * from the slow path and handle has already been allocated.
 	 */
-	if (IS_ERR((void *)handle))
+	if (IS_ERR_VALUE(handle))
 		handle = zs_malloc(zram->mem_pool, comp_len,
 				__GFP_KSWAPD_RECLAIM |
 				__GFP_NOWARN |
 				__GFP_HIGHMEM |
 				__GFP_MOVABLE);
-	if (IS_ERR((void *)handle)) {
+	if (IS_ERR_VALUE(handle)) {
 		zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
 		atomic64_inc(&zram->stats.writestall);
 		handle = zs_malloc(zram->mem_pool, comp_len,
 				GFP_NOIO | __GFP_HIGHMEM |
 				__GFP_MOVABLE);
-		if (IS_ERR((void *)handle))
+		if (IS_ERR_VALUE(handle))
 			return PTR_ERR((void *)handle);
 
 		if (comp_len != PAGE_SIZE)
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 08/13] zram: add size class equals check into recompression
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (6 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 07/13] zram: Use IS_ERR_VALUE() to check for zs_malloc() errors Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 09/13] zram: remove redundant checks from zram_recompress() Sergey Senozhatsky
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky, Alexey Romanov

From: Alexey Romanov <avromanov@sberdevices.ru>

It makes no sense for us to recompress the object if it will be in the
same size class.  We anyway don't get any memory gain.  But, at the same
time, we get a CPU time overhead when inserting this object into zspage
and decompressing it afterwards.

[senozhatsky: rebased and fixed conflicts]
Signed-off-by: Alexey Romanov <avromanov@sberdevices.ru>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 11 ++++++++++-
 include/linux/zsmalloc.h      |  2 ++
 mm/zsmalloc.c                 | 21 +++++++++++++++++++++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 9561569273fe..383d967ef4c7 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1675,6 +1675,8 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	unsigned long handle_new;
 	unsigned int comp_len_old;
 	unsigned int comp_len_new;
+	unsigned int class_index_old;
+	unsigned int class_index_new;
 	void *src, *dst;
 	int ret;
 
@@ -1693,6 +1695,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	if (ret)
 		return ret;
 
+	class_index_old = zs_lookup_class_index(zram->mem_pool, comp_len_old);
 	/*
 	 * Iterate the secondary comp algorithms list (in order of priority)
 	 * and try to recompress the page.
@@ -1718,9 +1721,13 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 			return ret;
 		}
 
+		class_index_new = zs_lookup_class_index(zram->mem_pool,
+							comp_len_new);
+
 		/* Continue until we make progress */
 		if (comp_len_new >= huge_class_size ||
 		    comp_len_new >= comp_len_old ||
+		    class_index_new >= class_index_old ||
 		    (threshold && comp_len_new >= threshold)) {
 			zcomp_stream_put(zram->comps[prio]);
 			continue;
@@ -1743,7 +1750,9 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	 * that would save memory, mark the object as incompressible so that
 	 * we will not try to compress it again.
 	 */
-	if (comp_len_new >= huge_class_size || comp_len_new >= comp_len_old) {
+	if (comp_len_new >= huge_class_size ||
+	    comp_len_new >= comp_len_old ||
+	    class_index_new >= class_index_old) {
 		zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
 		return 0;
 	}
diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h
index 2a430e713ce5..a48cd0ffe57d 100644
--- a/include/linux/zsmalloc.h
+++ b/include/linux/zsmalloc.h
@@ -55,5 +55,7 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
 unsigned long zs_get_total_pages(struct zs_pool *pool);
 unsigned long zs_compact(struct zs_pool *pool);
 
+unsigned int zs_lookup_class_index(struct zs_pool *pool, unsigned int size);
+
 void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats);
 #endif
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index d03941cace2c..065744b7e9d8 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -1205,6 +1205,27 @@ static bool zspage_full(struct size_class *class, struct zspage *zspage)
 	return get_zspage_inuse(zspage) == class->objs_per_zspage;
 }
 
+/**
+ * zs_lookup_class_index() - Returns index of the zsmalloc &size_class
+ * that hold objects of the provided size.
+ * @pool: zsmalloc pool to use
+ * @size: object size
+ *
+ * Context: Any context.
+ *
+ * Return: the index of the zsmalloc &size_class that hold objects of the
+ * provided size.
+ */
+unsigned int zs_lookup_class_index(struct zs_pool *pool, unsigned int size)
+{
+	struct size_class *class;
+
+	class = pool->size_class[get_size_class_index(size)];
+
+	return class->index;
+}
+EXPORT_SYMBOL_GPL(zs_lookup_class_index);
+
 unsigned long zs_get_total_pages(struct zs_pool *pool)
 {
 	return atomic_long_read(&pool->pages_allocated);
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 09/13] zram: remove redundant checks from zram_recompress()
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (7 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 08/13] zram: add size class equals check into recompression Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 10/13] zram: Add algo parameter support to zram_recompress() Sergey Senozhatsky
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Size class index comparison is powerful enough so we can
remove object size comparisons.

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 383d967ef4c7..67b58f2255db 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1725,9 +1725,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 							comp_len_new);
 
 		/* Continue until we make progress */
-		if (comp_len_new >= huge_class_size ||
-		    comp_len_new >= comp_len_old ||
-		    class_index_new >= class_index_old ||
+		if (class_index_new >= class_index_old ||
 		    (threshold && comp_len_new >= threshold)) {
 			zcomp_stream_put(zram->comps[prio]);
 			continue;
@@ -1750,9 +1748,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	 * that would save memory, mark the object as incompressible so that
 	 * we will not try to compress it again.
 	 */
-	if (comp_len_new >= huge_class_size ||
-	    comp_len_new >= comp_len_old ||
-	    class_index_new >= class_index_old) {
+	if (class_index_new >= class_index_old) {
 		zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
 		return 0;
 	}
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 10/13] zram: Add algo parameter support to zram_recompress()
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (8 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 09/13] zram: remove redundant checks from zram_recompress() Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 11/13] documentation: Add zram recompression documentation Sergey Senozhatsky
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Recompression iterates through all the registered secondary
compression algorithms in order of their priorities so that
we have higher chances of finding the algorithm that compresses
a particular page. This, however, may not always be best
approach and sometimes we may want to limit recompression to
only one particular algorithm. For instance, when a higher
priority algorithm uses too much power and device has a
relatively low battery level we may want to limit recompression
to use only a lower priority algorithm, which uses less power.

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

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

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 54 +++++++++++++++++++++++++++++------
 drivers/block/zram/zram_drv.h |  1 +
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 67b58f2255db..89d25f60b33e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1677,6 +1677,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	unsigned int comp_len_new;
 	unsigned int class_index_old;
 	unsigned int class_index_new;
+	u32 num_recomps = 0;
 	void *src, *dst;
 	int ret;
 
@@ -1711,6 +1712,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 		if (prio <= zram_get_priority(zram, index))
 			continue;
 
+		num_recomps++;
 		zstrm = zcomp_stream_get(zram->comps[prio]);
 		src = kmap_atomic(page);
 		ret = zcomp_compress(zstrm, src, &comp_len_new);
@@ -1743,13 +1745,19 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	if (!zstrm)
 		return 0;
 
-	/*
-	 * All secondary algorithms failed to re-compress the page in a way
-	 * that would save memory, mark the object as incompressible so that
-	 * we will not try to compress it again.
-	 */
 	if (class_index_new >= class_index_old) {
-		zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+		/*
+		 * Secondary algorithms failed to re-compress the page
+		 * in a way that would save memory, mark the object as
+		 * incompressible so that we will not try to compress
+		 * it again.
+		 *
+		 * We need to make sure that all secondary algorithms have
+		 * failed, so we test if the number of recompressions matches
+		 * the number of active secondary algorithms.
+		 */
+		if (num_recomps == zram->num_active_comps - 1)
+			zram_set_flag(zram, index, ZRAM_INCOMPRESSIBLE);
 		return 0;
 	}
 
@@ -1798,10 +1806,11 @@ static ssize_t recompress_store(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t len)
 {
+	u32 prio = ZRAM_SECONDARY_COMP, prio_max = ZRAM_MAX_COMPS;
 	struct zram *zram = dev_to_zram(dev);
-	u32 mode = 0, threshold = 0, prio = ZRAM_SECONDARY_COMP;
 	unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
-	char *args, *param, *val;
+	char *args, *param, *val, *algo = NULL;
+	u32 mode = 0, threshold = 0;
 	unsigned long index;
 	struct page *page;
 	ssize_t ret;
@@ -1833,6 +1842,11 @@ static ssize_t recompress_store(struct device *dev,
 				return ret;
 			continue;
 		}
+
+		if (!strcmp(param, "algo")) {
+			algo = val;
+			continue;
+		}
 	}
 
 	if (threshold >= PAGE_SIZE)
@@ -1844,6 +1858,26 @@ static ssize_t recompress_store(struct device *dev,
 		goto release_init_lock;
 	}
 
+	if (algo) {
+		bool found = false;
+
+		for (; prio < ZRAM_MAX_COMPS; prio++) {
+			if (!zram->comp_algs[prio])
+				continue;
+
+			if (!strcmp(zram->comp_algs[prio], algo)) {
+				prio_max = min(prio + 1, ZRAM_MAX_COMPS);
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			ret = -EINVAL;
+			goto release_init_lock;
+		}
+	}
+
 	page = alloc_page(GFP_KERNEL);
 	if (!page) {
 		ret = -ENOMEM;
@@ -1874,7 +1908,7 @@ static ssize_t recompress_store(struct device *dev,
 			goto next;
 
 		err = zram_recompress(zram, index, page, threshold,
-				      prio, ZRAM_MAX_COMPS);
+				      prio, prio_max);
 next:
 		zram_slot_unlock(zram, index);
 		if (err) {
@@ -2110,6 +2144,7 @@ static void zram_destroy_comps(struct zram *zram)
 		if (!comp)
 			continue;
 		zcomp_destroy(comp);
+		zram->num_active_comps--;
 	}
 }
 
@@ -2177,6 +2212,7 @@ static ssize_t disksize_store(struct device *dev,
 		}
 
 		zram->comps[prio] = comp;
+		zram->num_active_comps++;
 	}
 	zram->disksize = disksize;
 	set_capacity_and_notify(zram->disk, zram->disksize >> SECTOR_SHIFT);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index b80faae76835..473325415a74 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -125,6 +125,7 @@ struct zram {
 	 */
 	u64 disksize;	/* bytes */
 	const char *comp_algs[ZRAM_MAX_COMPS];
+	s8 num_active_comps;
 	/*
 	 * zram is claimed so open request will be failed
 	 */
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 11/13] documentation: Add zram recompression documentation
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (9 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 10/13] zram: Add algo parameter support to zram_recompress() Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 12/13] zram: add incompressible writeback Sergey Senozhatsky
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Document user-space visible device attributes that
are enabled by ZRAM_MULTI_COMP.

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 Documentation/admin-guide/blockdev/zram.rst | 81 +++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index 177a142c3146..d898b7ace33d 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -401,6 +401,87 @@ budget in next setting is user's job.
 If admin wants to measure writeback count in a certain period, they could
 know it via /sys/block/zram0/bd_stat's 3rd column.
 
+recompression
+-------------
+
+With CONFIG_ZRAM_MULTI_COMP, zram can recompress pages using alternative
+(secondary) compression algorithms. The basic idea is that alternative
+compression algorithm can provide better compression ratio at a price of
+(potentially) slower compression/decompression speeds. Alternative compression
+algorithm can, for example, be more successful compressing huge pages (those
+that default algorithm failed to compress). Another application is idle pages
+recompression - pages that are cold and sit in the memory can be recompressed
+using more effective algorithm and, hence, reduce zsmalloc memory usage.
+
+With CONFIG_ZRAM_MULTI_COMP, zram supports up to 4 compression algorithms:
+one primary and up to 3 secondary ones. Primary zram compressor is explained
+in "3) Select compression algorithm", secondary algorithms are configured
+using recomp_algorithm device attribute.
+
+Example:::
+
+	#show supported recompression algorithms
+	cat /sys/block/zramX/recomp_algorithm
+	#1: lzo lzo-rle lz4 lz4hc [zstd]
+	#2: lzo lzo-rle lz4 [lz4hc] zstd
+
+Alternative compression algorithms are sorted by priority. In the example
+above, zstd is used as the first alternative algorithm, which has priority
+of 1, while lz4hc is configured as a compression algorithm with priority 2.
+Alternative compression algorithm's priority is provided during algorithms
+configuration:::
+
+	#select zstd recompression algorithm, priority 1
+	echo "algo=zstd priority=1" > /sys/block/zramX/recomp_algorithm
+
+	#select deflate recompression algorithm, priority 2
+	echo "algo=deflate priority=2" > /sys/block/zramX/recomp_algorithm
+
+Another device attribute that CONFIG_ZRAM_MULTI_COMP enables is recompress,
+which controls recompression.
+
+Examples:::
+
+	#IDLE pages recompression is activated by `idle` mode
+	echo "type=idle" > /sys/block/zramX/recompress
+
+	#HUGE pages recompression is activated by `huge` mode
+	echo "type=huge" > /sys/block/zram0/recompress
+
+	#HUGE_IDLE pages recompression is activated by `huge_idle` mode
+	echo "type=huge_idle" > /sys/block/zramX/recompress
+
+The number of idle pages can be significant, so user-space can pass a size
+threshold (in bytes) to the recompress knob: zram will recompress only pages
+of equal or greater size:::
+
+	#recompress all pages larger than 3000 bytes
+	echo "threshold=3000" > /sys/block/zramX/recompress
+
+	#recompress idle pages larger than 2000 bytes
+	echo "type=idle threshold=2000" > /sys/block/zramX/recompress
+
+Recompression of idle pages requires memory tracking.
+
+During re-compression for every page, that matches re-compression criteria,
+ZRAM iterates the list of registered alternative compression algorithms in
+order of their priorities. ZRAM stops either when re-compression was
+successful (re-compressed object is smaller in size than the original one)
+and matches re-compression criteria (e.g. size threshold) or when there are
+no secondary algorithms left to try. If none of the secondary algorithms can
+successfully re-compressed the page such a page is marked as incompressible,
+so ZRAM will not attempt to re-compress it in the future.
+
+This re-compression behaviour, when it iterates through the list of
+registered compression algorithms, increases our chances of finding the
+algorithm that successfully compresses a particular page. Sometimes, however,
+it is convenient (and sometimes even necessary) to limit recompression to
+only one particular algorithm so that it will not try any other algorithms.
+This can be achieved by providing a algo=NAME parameter:::
+
+	#use zstd algorithm only (if registered)
+	echo "type=huge algo=zstd" > /sys/block/zramX/recompress
+
 memory tracking
 ===============
 
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 12/13] zram: add incompressible writeback
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (10 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 11/13] documentation: Add zram recompression documentation Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 11:50 ` [PATCHv5 13/13] zram: Add incompressible flag to read_block_state() Sergey Senozhatsky
  2022-11-09 21:46 ` [PATCHv5 00/13] zram: Support multiple compression streams Minchan Kim
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Add support for incompressible pages writeback:

  echo incompressible > /sys/block/zramX/writeback

Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 Documentation/admin-guide/blockdev/zram.rst |  7 ++++++-
 drivers/block/zram/zram_drv.c               | 18 ++++++++++++------
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index d898b7ace33d..f14c8c2e42f3 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -348,8 +348,13 @@ this can be accomplished with::
 
         echo huge_idle > /sys/block/zramX/writeback
 
+If a user chooses to writeback only incompressible pages (pages that none of
+algorithms can compress) this can be accomplished with::
+
+	echo incompressible > /sys/block/zramX/writeback
+
 If an admin wants to write a specific page in zram device to the backing device,
-they could write a page index into the interface.
+they could write a page index into the interface::
 
 	echo "page_index=1251" > /sys/block/zramX/writeback
 
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 89d25f60b33e..2e4ef1ba1973 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -648,10 +648,10 @@ static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec,
 
 #define PAGE_WB_SIG "page_index="
 
-#define PAGE_WRITEBACK 0
-#define HUGE_WRITEBACK (1<<0)
-#define IDLE_WRITEBACK (1<<1)
-
+#define PAGE_WRITEBACK			0
+#define HUGE_WRITEBACK			(1<<0)
+#define IDLE_WRITEBACK			(1<<1)
+#define INCOMPRESSIBLE_WRITEBACK	(1<<2)
 
 static ssize_t writeback_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t len)
@@ -672,6 +672,8 @@ static ssize_t writeback_store(struct device *dev,
 		mode = HUGE_WRITEBACK;
 	else if (sysfs_streq(buf, "huge_idle"))
 		mode = IDLE_WRITEBACK | HUGE_WRITEBACK;
+	else if (sysfs_streq(buf, "incompressible"))
+		mode = INCOMPRESSIBLE_WRITEBACK;
 	else {
 		if (strncmp(buf, PAGE_WB_SIG, sizeof(PAGE_WB_SIG) - 1))
 			return -EINVAL;
@@ -734,11 +736,15 @@ static ssize_t writeback_store(struct device *dev,
 			goto next;
 
 		if (mode & IDLE_WRITEBACK &&
-			  !zram_test_flag(zram, index, ZRAM_IDLE))
+		    !zram_test_flag(zram, index, ZRAM_IDLE))
 			goto next;
 		if (mode & HUGE_WRITEBACK &&
-			  !zram_test_flag(zram, index, ZRAM_HUGE))
+		    !zram_test_flag(zram, index, ZRAM_HUGE))
 			goto next;
+		if (mode & INCOMPRESSIBLE_WRITEBACK &&
+		    !zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+			goto next;
+
 		/*
 		 * Clearing ZRAM_UNDER_WB is duty of caller.
 		 * IOW, zram_free_page never clear it.
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCHv5 13/13] zram: Add incompressible flag to read_block_state()
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (11 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 12/13] zram: add incompressible writeback Sergey Senozhatsky
@ 2022-11-09 11:50 ` Sergey Senozhatsky
  2022-11-09 21:46 ` [PATCHv5 00/13] zram: Support multiple compression streams Minchan Kim
  13 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-09 11:50 UTC (permalink / raw)
  To: Minchan Kim, Andrew Morton
  Cc: Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm,
	Sergey Senozhatsky

Add a new flag to zram block state that shows if the page
is incompressible: that none of the algorithm (including
secondary ones) could compress it.

Suggested-by: Minchan Kim <minchan@kernel.org>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 Documentation/admin-guide/blockdev/zram.rst | 11 +++++++----
 drivers/block/zram/zram_drv.c               |  6 ++++--
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index f14c8c2e42f3..e4551579cb12 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -497,10 +497,11 @@ pages of the process with*pagemap.
 If you enable the feature, you could see block state via
 /sys/kernel/debug/zram/zram0/block_state". The output is as follows::
 
-	  300    75.033841 .wh..
-	  301    63.806904 s....
-	  302    63.806919 ..hi.
-	  303    62.801919 ....r
+	  300    75.033841 .wh...
+	  301    63.806904 s.....
+	  302    63.806919 ..hi..
+	  303    62.801919 ....r.
+	  304   146.781902 ..hi.n
 
 First column
 	zram's block index.
@@ -519,6 +520,8 @@ Third column
 		idle page
 	r:
 		recompressed page (secondary compression algorithm)
+	n:
+		none (including secondary) of algorithms could compress it
 
 First line of above example says 300th block is accessed at 75.033841sec
 and the block's state is huge so it is written back to the backing
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 2e4ef1ba1973..3447df3ca75e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -949,14 +949,16 @@ static ssize_t read_block_state(struct file *file, char __user *buf,
 
 		ts = ktime_to_timespec64(zram->table[index].ac_time);
 		copied = snprintf(kbuf + written, count,
-			"%12zd %12lld.%06lu %c%c%c%c%c\n",
+			"%12zd %12lld.%06lu %c%c%c%c%c%c\n",
 			index, (s64)ts.tv_sec,
 			ts.tv_nsec / NSEC_PER_USEC,
 			zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.',
 			zram_test_flag(zram, index, ZRAM_WB) ? 'w' : '.',
 			zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.',
 			zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.',
-			zram_get_priority(zram, index) ? 'r' : '.');
+			zram_get_priority(zram, index) ? 'r' : '.',
+			zram_test_flag(zram, index,
+				       ZRAM_INCOMPRESSIBLE) ? 'n' : '.');
 
 		if (count <= copied) {
 			zram_slot_unlock(zram, index);
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCHv5 00/13] zram: Support multiple compression streams
  2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
                   ` (12 preceding siblings ...)
  2022-11-09 11:50 ` [PATCHv5 13/13] zram: Add incompressible flag to read_block_state() Sergey Senozhatsky
@ 2022-11-09 21:46 ` Minchan Kim
  13 siblings, 0 replies; 23+ messages in thread
From: Minchan Kim @ 2022-11-09 21:46 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Andrew Morton, Nitin Gupta, Suleiman Souhlal, linux-kernel, linux-mm

On Wed, Nov 09, 2022 at 08:50:34PM +0900, Sergey Senozhatsky wrote:
> Hello,
> 
> 	This series adds support for multiple compression streams.
> The main idea is that different compression algorithms have different
> characteristics and zram may benefit when it uses a combination of
> algorithms: a default algorithm that is faster but have lower
> compression rate and a secondary algorithm that can use higher
> compression rate at a price of slower compression/decompression.
> 
> 	There are several use-case for this functionality:
> 
> - huge pages re-compression: zstd or deflate can successfully
> compress huge pages (~50% of huge pages on my synthetic ChromeOS
> tests), IOW pages that lzo was not able to compress.
> 
> - idle pages re-compression: idle/cold pages sit in the memory
> and we may reduce zsmalloc memory usage if we recompress those
> idle pages.
> 
> 	User-space has a number of ways to control the behavior
> and impact of zram recompression: what type of pages should be
> recompressed, size watermarks, etc. Please refer to documentation
> patch.
> 
> v5:
> -- Addressed (very valuable) review feedback from Minchan
> -- Extended documentation
> -- We now do chain recompression, tryin algos in order of their priority
> -- Support up to 4 compression streams
> -- Added named parameters to recomp_algorithm and recompress sysfs knobs
> -- Cherry-picked patch from Alexey
> -- Store algo priority in mete flags
> -- Renamed some fo the flags
> -- Added incompressible bit to block state output
> -- Added incompressible writeback
> -- etc.
> 
> v4:
> -- added IS_ERR_VALUE patch (Andrew)
> -- documented SIZE units (bytes) (Andrew)
> -- re-phrased writeback BIO error comment (Andrew)
> -- return zs_malloc() error code from zram_recompress()
> -- do not lose zram_recompress() error in recompress_store()
> -- corrected a typo
> -- fixed previous rebase errors
> -- rebased the series
> 
> v3:
> -- conditionally reschedule during recompression loop so that
>    we don't stall RCU grace periods
> -- fixed a false-positive WARN_ON
> 
> v2:
> -- rebased
> -- mark completely incompressible pages (neither default nor secondary
>    algorithm can compress them) with a new flag so that we don't attempt
>    to recompress them all the time
> 
> Alexey Romanov (1):
>   zram: add size class equals check into recompression
> 
> Sergey Senozhatsky (12):
>   zram: Preparation for multi-zcomp support
>   zram: Add recompression algorithm sysfs knob
>   zram: Factor out WB and non-WB zram read functions
>   zram: Introduce recompress sysfs knob
>   zram: Add recompress flag to read_block_state()
>   zram: Clarify writeback_store() comment
>   zram: Use IS_ERR_VALUE() to check for zs_malloc() errors
>   zram: remove redundant checks from zram_recompress()
>   zram: Add algo parameter support to zram_recompress()
>   documentation: Add zram recompression documentation
>   zram: add incompressible writeback
>   zram: Add incompressible flag to read_block_state()
> 
>  Documentation/admin-guide/blockdev/zram.rst | 100 +++-
>  drivers/block/zram/Kconfig                  |   9 +
>  drivers/block/zram/zcomp.c                  |   6 +-
>  drivers/block/zram/zcomp.h                  |   2 +-
>  drivers/block/zram/zram_drv.c               | 604 +++++++++++++++++---
>  drivers/block/zram/zram_drv.h               |  22 +-
>  include/linux/zsmalloc.h                    |   2 +
>  mm/zsmalloc.c                               |  21 +
>  8 files changed, 685 insertions(+), 81 deletions(-)

Acked-by: Minchan Kim <minchan@kernel.org>

Thanks!

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCHv5 04/13] zram: Introduce recompress sysfs knob
  2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
@ 2022-11-10 13:09   ` Nathan Chancellor
  2022-11-10 14:31     ` Sergey Senozhatsky
  2022-11-10 14:34   ` [PATCH] zram: we should always zero out err variable in recompress loop Sergey Senozhatsky
  2022-11-14  2:14   ` [PATCH] zram: explicitly limit prio_max for static analyzers Sergey Senozhatsky
  2 siblings, 1 reply; 23+ messages in thread
From: Nathan Chancellor @ 2022-11-10 13:09 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Minchan Kim, Andrew Morton, Nitin Gupta, Suleiman Souhlal,
	linux-kernel, linux-mm, llvm

Hi Sergey,

On Wed, Nov 09, 2022 at 08:50:38PM +0900, Sergey Senozhatsky wrote:
> Allow zram to recompress (using secondary compression streams)
> pages.
> 
> Re-compression algorithms (we support up to 3 at this stage)
> are selected via recomp_algorithm:
> 
>   echo "algo=zstd priority=1" > /sys/block/zramX/recomp_algorithm
> 
> Please read documentation for more details.
> 
> We support several recompression modes:
> 
> 1) IDLE pages recompression is activated by `idle` mode
> 
>   echo "type=idle" > /sys/block/zram0/recompress
> 
> 2) Since there may be many idle pages user-space may pass a size
> threshold value (in bytes) and we will recompress pages only
> of equal or greater size:
> 
>   echo "threshold=888" > /sys/block/zram0/recompress
> 
> 3) HUGE pages recompression is activated by `huge` mode
> 
>   echo "type=huge" > /sys/block/zram0/recompress
> 
> 4) HUGE_IDLE pages recompression is activated by `huge_idle` mode
> 
>   echo "type=huge_idle" > /sys/block/zram0/recompress
> 
> Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
...
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index a6a5fd2474d7..749e4266dd72 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
...
> +	for (index = 0; index < nr_pages; index++) {
> +		int err;
> +
> +		zram_slot_lock(zram, index);
> +
> +		if (!zram_allocated(zram, index))
> +			goto next;
> +
> +		if (mode & RECOMPRESS_IDLE &&
> +		    !zram_test_flag(zram, index, ZRAM_IDLE))
> +			goto next;
> +
> +		if (mode & RECOMPRESS_HUGE &&
> +		    !zram_test_flag(zram, index, ZRAM_HUGE))
> +			goto next;
> +
> +		if (zram_test_flag(zram, index, ZRAM_WB) ||
> +		    zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
> +		    zram_test_flag(zram, index, ZRAM_SAME) ||
> +		    zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
> +			goto next;
> +
> +		err = zram_recompress(zram, index, page, threshold,
> +				      prio, ZRAM_MAX_COMPS);
> +next:
> +		zram_slot_unlock(zram, index);
> +		if (err) {
> +			ret = err;
> +			break;
> +		}
> +
> +		cond_resched();
> +	}

This commit is now in -next as commit 03e6c729aa64 ("zram: introduce
recompress sysfs knob"), where it introduces the following clang
warnings:

drivers/block/zram/zram_drv.c:1909:7: error: variable 'err' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1909:3: note: remove the 'if' if its condition is always false
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1909:7: error: variable 'err' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized]
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1909:7: note: remove the '||' if its condition is always false
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1909:7: error: variable 'err' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized]
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1909:7: note: remove the '||' if its condition is always false
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1909:7: error: variable 'err' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized]
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1909:7: note: remove the '||' if its condition is always false
                if (zram_test_flag(zram, index, ZRAM_WB) ||
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1905:7: error: variable 'err' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
                if (mode & RECOMPRESS_HUGE &&
                    ^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1905:3: note: remove the 'if' if its condition is always false
                if (mode & RECOMPRESS_HUGE &&
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1901:7: error: variable 'err' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
                if (mode & RECOMPRESS_IDLE &&
                    ^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1901:3: note: remove the 'if' if its condition is always false
                if (mode & RECOMPRESS_IDLE &&
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1898:7: error: variable 'err' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
                if (!zram_allocated(zram, index))
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1919:7: note: uninitialized use occurs here
                if (err) {
                    ^~~
drivers/block/zram/zram_drv.c:1898:3: note: remove the 'if' if its condition is always false
                if (!zram_allocated(zram, index))
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/block/zram/zram_drv.c:1894:10: note: initialize the variable 'err' to silence this warning
                int err;
                       ^
                        = 0
7 errors generated.

Is the fix just to initialize err to 0 as it suggests or should there be
a different fix?

Cheers,
Nathan

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCHv5 04/13] zram: Introduce recompress sysfs knob
  2022-11-10 13:09   ` Nathan Chancellor
@ 2022-11-10 14:31     ` Sergey Senozhatsky
  2022-11-10 14:38       ` Sergey Senozhatsky
  0 siblings, 1 reply; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-10 14:31 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Sergey Senozhatsky, Minchan Kim, Andrew Morton, Nitin Gupta,
	Suleiman Souhlal, linux-kernel, linux-mm, llvm

On (22/11/10 06:09), Nathan Chancellor wrote:
[..]
> drivers/block/zram/zram_drv.c:1894:10: note: initialize the variable 'err' to silence this warning
>                 int err;
>                        ^
>                         = 0
> 7 errors generated.
> 
> Is the fix just to initialize err to 0 as it suggests or should there be
> a different fix?

Yes, that's the correct fix. Thanks for catching this. We had "err = 0"
in v4 of this patch set, but it somehow didn't make it to v5.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH] zram: we should always zero out err variable in recompress loop
  2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
  2022-11-10 13:09   ` Nathan Chancellor
@ 2022-11-10 14:34   ` Sergey Senozhatsky
  2022-11-14  2:14   ` [PATCH] zram: explicitly limit prio_max for static analyzers Sergey Senozhatsky
  2 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-10 14:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Minchan Kim, Nitin Gupta, Suleiman Souhlal, linux-kernel,
	linux-mm, llvm, Sergey Senozhatsky, Nathan Chancellor

Reported-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 171eccc2249d..9d33801e8ba8 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1891,7 +1891,7 @@ static ssize_t recompress_store(struct device *dev,
 
 	ret = len;
 	for (index = 0; index < nr_pages; index++) {
-		int err;
+		int err = 0;
 
 		zram_slot_lock(zram, index);
 
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCHv5 04/13] zram: Introduce recompress sysfs knob
  2022-11-10 14:31     ` Sergey Senozhatsky
@ 2022-11-10 14:38       ` Sergey Senozhatsky
  2022-11-10 15:18         ` Nathan Chancellor
  0 siblings, 1 reply; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-10 14:38 UTC (permalink / raw)
  To: Nathan Chancellor, Andrew Morton
  Cc: Minchan Kim, Nitin Gupta, Suleiman Souhlal, linux-kernel,
	linux-mm, llvm, Sergey Senozhatsky

On (22/11/10 23:31), Sergey Senozhatsky wrote:
> On (22/11/10 06:09), Nathan Chancellor wrote:
> [..]
> > drivers/block/zram/zram_drv.c:1894:10: note: initialize the variable 'err' to silence this warning
> >                 int err;
> >                        ^
> >                         = 0
> > 7 errors generated.
> > 
> > Is the fix just to initialize err to 0 as it suggests or should there be
> > a different fix?
> 
> Yes, that's the correct fix. Thanks for catching this. We had "err = 0"
> in v4 of this patch set, but it somehow didn't make it to v5.

Nathan, I just sent a simple one-liner patch. If you don't mind,
may we ask Andrew to take it as a fixup (folded) patch?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCHv5 04/13] zram: Introduce recompress sysfs knob
  2022-11-10 14:38       ` Sergey Senozhatsky
@ 2022-11-10 15:18         ` Nathan Chancellor
  0 siblings, 0 replies; 23+ messages in thread
From: Nathan Chancellor @ 2022-11-10 15:18 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Andrew Morton, Minchan Kim, Nitin Gupta, Suleiman Souhlal,
	linux-kernel, linux-mm, llvm

On Thu, Nov 10, 2022 at 11:38:57PM +0900, Sergey Senozhatsky wrote:
> On (22/11/10 23:31), Sergey Senozhatsky wrote:
> > On (22/11/10 06:09), Nathan Chancellor wrote:
> > [..]
> > > drivers/block/zram/zram_drv.c:1894:10: note: initialize the variable 'err' to silence this warning
> > >                 int err;
> > >                        ^
> > >                         = 0
> > > 7 errors generated.
> > > 
> > > Is the fix just to initialize err to 0 as it suggests or should there be
> > > a different fix?
> > 
> > Yes, that's the correct fix. Thanks for catching this. We had "err = 0"
> > in v4 of this patch set, but it somehow didn't make it to v5.
> 
> Nathan, I just sent a simple one-liner patch. If you don't mind,
> may we ask Andrew to take it as a fixup (folded) patch?

Yup, sounds like a plan to me, thanks for the quick response and fix!

Cheers,
Nathan

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH] zram: explicitly limit prio_max for static analyzers
  2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
  2022-11-10 13:09   ` Nathan Chancellor
  2022-11-10 14:34   ` [PATCH] zram: we should always zero out err variable in recompress loop Sergey Senozhatsky
@ 2022-11-14  2:14   ` Sergey Senozhatsky
  2022-11-15  0:41     ` Andrew Morton
  2 siblings, 1 reply; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-14  2:14 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Minchan Kim, Nitin Gupta, Suleiman Souhlal, linux-kernel,
	linux-mm, Sergey Senozhatsky, coverity-bot

Reported-by: coverity-bot <keescook+coverity-bot@chromium.org>
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
 drivers/block/zram/zram_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 9d33801e8ba8..e67a124f2e88 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1706,6 +1706,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
 	 * Iterate the secondary comp algorithms list (in order of priority)
 	 * and try to recompress the page.
 	 */
+	prio_max = min(prio_max, ZRAM_MAX_COMPS);
 	for (; prio < prio_max; prio++) {
 		if (!zram->comps[prio])
 			continue;
-- 
2.38.1.431.g37b22c650d-goog


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] zram: explicitly limit prio_max for static analyzers
  2022-11-14  2:14   ` [PATCH] zram: explicitly limit prio_max for static analyzers Sergey Senozhatsky
@ 2022-11-15  0:41     ` Andrew Morton
  2022-11-15  0:47       ` Sergey Senozhatsky
  0 siblings, 1 reply; 23+ messages in thread
From: Andrew Morton @ 2022-11-15  0:41 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: Minchan Kim, Nitin Gupta, Suleiman Souhlal, linux-kernel,
	linux-mm, coverity-bot

On Mon, 14 Nov 2022 11:14:20 +0900 Sergey Senozhatsky <senozhatsky@chromium.org> wrote:

> Reported-by: coverity-bot <keescook+coverity-bot@chromium.org>
> Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> ---
>  drivers/block/zram/zram_drv.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> index 9d33801e8ba8..e67a124f2e88 100644
> --- a/drivers/block/zram/zram_drv.c
> +++ b/drivers/block/zram/zram_drv.c
> @@ -1706,6 +1706,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
>  	 * Iterate the secondary comp algorithms list (in order of priority)
>  	 * and try to recompress the page.
>  	 */
> +	prio_max = min(prio_max, ZRAM_MAX_COMPS);
>  	for (; prio < prio_max; prio++) {
>  		if (!zram->comps[prio])
>  			continue;

I'll queue this as a fix to "zram: introduce recompress sysfs knob".

What's it do?  A little changelog would be nice, or at least a link to
the coverity report?


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] zram: explicitly limit prio_max for static analyzers
  2022-11-15  0:41     ` Andrew Morton
@ 2022-11-15  0:47       ` Sergey Senozhatsky
  0 siblings, 0 replies; 23+ messages in thread
From: Sergey Senozhatsky @ 2022-11-15  0:47 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Sergey Senozhatsky, Minchan Kim, Nitin Gupta, Suleiman Souhlal,
	linux-kernel, linux-mm, coverity-bot

On (22/11/14 16:41), Andrew Morton wrote:
> >  drivers/block/zram/zram_drv.c | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> > index 9d33801e8ba8..e67a124f2e88 100644
> > --- a/drivers/block/zram/zram_drv.c
> > +++ b/drivers/block/zram/zram_drv.c
> > @@ -1706,6 +1706,7 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
> >  	 * Iterate the secondary comp algorithms list (in order of priority)
> >  	 * and try to recompress the page.
> >  	 */
> > +	prio_max = min(prio_max, ZRAM_MAX_COMPS);
> >  	for (; prio < prio_max; prio++) {
> >  		if (!zram->comps[prio])
> >  			continue;
> 
> I'll queue this as a fix to "zram: introduce recompress sysfs knob".
> 
> What's it do?  A little changelog would be nice, or at least a link to
> the coverity report?

It doesn't do much, coverity (static analyzer?) got confused by
the code, so this simply is supposed to help coverity figure out
that we never do an out of bounds access in comps[] array:
https://lore.kernel.org/lkml/202211100847.388C61B3@keescook/

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2022-11-15  0:47 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-09 11:50 [PATCHv5 00/13] zram: Support multiple compression streams Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 01/13] zram: Preparation for multi-zcomp support Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 02/13] zram: Add recompression algorithm sysfs knob Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 03/13] zram: Factor out WB and non-WB zram read functions Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 04/13] zram: Introduce recompress sysfs knob Sergey Senozhatsky
2022-11-10 13:09   ` Nathan Chancellor
2022-11-10 14:31     ` Sergey Senozhatsky
2022-11-10 14:38       ` Sergey Senozhatsky
2022-11-10 15:18         ` Nathan Chancellor
2022-11-10 14:34   ` [PATCH] zram: we should always zero out err variable in recompress loop Sergey Senozhatsky
2022-11-14  2:14   ` [PATCH] zram: explicitly limit prio_max for static analyzers Sergey Senozhatsky
2022-11-15  0:41     ` Andrew Morton
2022-11-15  0:47       ` Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 05/13] zram: Add recompress flag to read_block_state() Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 06/13] zram: Clarify writeback_store() comment Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 07/13] zram: Use IS_ERR_VALUE() to check for zs_malloc() errors Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 08/13] zram: add size class equals check into recompression Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 09/13] zram: remove redundant checks from zram_recompress() Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 10/13] zram: Add algo parameter support to zram_recompress() Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 11/13] documentation: Add zram recompression documentation Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 12/13] zram: add incompressible writeback Sergey Senozhatsky
2022-11-09 11:50 ` [PATCHv5 13/13] zram: Add incompressible flag to read_block_state() Sergey Senozhatsky
2022-11-09 21:46 ` [PATCHv5 00/13] zram: Support multiple compression streams Minchan Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.