* [PATCHv5 0/7] zram: optimal post-processing target selection
@ 2024-09-17 2:09 Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 1/7] zram: introduce ZRAM_PP_SLOT flag Sergey Senozhatsky
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
Problem:
--------
Both recompression and writeback perform a very simple linear scan
of all zram slots in search for post-processing (writeback or
recompress) candidate slots. This often means that we pick the
worst candidate for pp (post-processing), e.g. a 48 bytes object for
writeback, which is nearly useless, because it only releases 48
bytes from zsmalloc pool, but consumes an entire 4K slot in the
backing device. Similarly, recompression of an 48 bytes objects
is unlikely to save more memory that recompression of a 3000 bytes
object. Both recompression and writeback consume constrained
resources (CPU time, batter, backing device storage space) and
quite often have a (daily) limit on the number of items they
post-process, so we should utilize those constrained resources in
the most optimal way.
Solution:
---------
This patch reworks the way we select pp targets. We, quite clearly,
want to sort all the candidates and always pick the largest, be it
recompression or writeback. Especially for writeback, because the
larger object we writeback the more memory we release. This series
introduces concept of pp buckets and pp scan/selection.
The scan step is a simple iteration over all zram->table entries,
just like what we currently do, but we don't post-process a candidate
slot immediately. Instead we assign it to a PP (post-processing)
bucket. PP bucket is, basically, a list which holds pp candidate
slots that belong to the same size class. PP buckets are 64 bytes
apart, slots are not strictly sorted within a bucket there is a
64 bytes variance.
The select step simply iterates over pp buckets from highest to lowest
and picks all candidate slots a particular buckets contains. So this
gives us sorted candidates (in linear time) and allows us to select
most optimal (largest) candidates for post-processing first.
v4..v5:
-- removed UNDER_WB flag and simplified writeback
Sergey Senozhatsky (7):
zram: introduce ZRAM_PP_SLOT flag
zram: permit only one post-processing operation at a time
zram: rework recompress target selection strategy
zram: rework writeback target selection strategy
zram: do not mark idle slots that cannot be idle
zram: reshuffle zram_free_page() flags operations
zram: remove UNDER_WB and simplify writeback
Documentation/admin-guide/blockdev/zram.rst | 2 +
drivers/block/zram/zram_drv.c | 366 +++++++++++++++-----
drivers/block/zram/zram_drv.h | 3 +-
3 files changed, 278 insertions(+), 93 deletions(-)
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv5 1/7] zram: introduce ZRAM_PP_SLOT flag
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 2/7] zram: permit only one post-processing operation at a time Sergey Senozhatsky
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
This flag indicates that the slot was selected as a
candidate slot for post-processing (pp) and was assigned
to a pp bucket. It does not necessarily mean that the
slot is currently under post-processing, but may mean
so. The slot can loose its PP_SLOT flag, while still
being in the pp-bucket, if it's accessed or slot_free-ed.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 2 ++
drivers/block/zram/zram_drv.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ee2a279c5f25..d170bf6cdcd8 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -178,6 +178,7 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index)
static void zram_accessed(struct zram *zram, u32 index)
{
zram_clear_flag(zram, index, ZRAM_IDLE);
+ zram_clear_flag(zram, index, ZRAM_PP_SLOT);
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
zram->table[index].ac_time = ktime_get_boottime();
#endif
@@ -1354,6 +1355,7 @@ static void zram_free_page(struct zram *zram, size_t index)
zram_clear_flag(zram, index, ZRAM_INCOMPRESSIBLE);
zram_set_priority(zram, index, 0);
+ zram_clear_flag(zram, index, ZRAM_PP_SLOT);
if (zram_test_flag(zram, index, ZRAM_WB)) {
zram_clear_flag(zram, index, ZRAM_WB);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index cfc8c059db63..914cb6629969 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -48,6 +48,7 @@ enum zram_pageflags {
ZRAM_SAME = ZRAM_FLAG_SHIFT, /* Page consists the same element */
ZRAM_WB, /* page is stored on backing_device */
ZRAM_UNDER_WB, /* page is under writeback */
+ ZRAM_PP_SLOT, /* Selected for post-processing */
ZRAM_HUGE, /* Incompressible page */
ZRAM_IDLE, /* not accessed page since last idle marking */
ZRAM_INCOMPRESSIBLE, /* none of the algorithms could compress it */
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 2/7] zram: permit only one post-processing operation at a time
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 1/7] zram: introduce ZRAM_PP_SLOT flag Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 3/7] zram: rework recompress target selection strategy Sergey Senozhatsky
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
Both recompress and writeback soon will unlock slots
during processing, which makes things too complex wrt
possible race-conditions. We still want to clear PP_SLOT
in slot_free, because this is how we figure out that
slot that was selected for post-processing has been
released under us and when we start post-processing we
check if slot still has PP_SLOT set. At the same time,
theoretically, we can have something like this:
CPU0 CPU1
recompress
scan slots
set PP_SLOT
unlock slot
slot_free
clear PP_SLOT
allocate PP_SLOT
writeback
scan slots
set PP_SLOT
unlock slot
select PP-slot
test PP_SLOT
So recompress will not detect that slot has been re-used
and re-selected for concurrent writeback post-processing.
Make sure that we only permit on post-processing operation
at a time. So now recompress and writeback post-processing
don't race against each other, we only need to handle slot
re-use (slot_free and write), which is handled individually
by each pp operation.
Having recompress and writeback competing for the same slots
is not exactly good anyway (can't imagine anyone doing that).
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
Documentation/admin-guide/blockdev/zram.rst | 2 ++
drivers/block/zram/zram_drv.c | 16 ++++++++++++++++
drivers/block/zram/zram_drv.h | 1 +
3 files changed, 19 insertions(+)
diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst
index 678d70d6e1c3..714a5171bfc0 100644
--- a/Documentation/admin-guide/blockdev/zram.rst
+++ b/Documentation/admin-guide/blockdev/zram.rst
@@ -47,6 +47,8 @@ The list of possible return codes:
-ENOMEM zram was not able to allocate enough memory to fulfil your
needs.
-EINVAL invalid input has been provided.
+-EAGAIN re-try operation later (e.g. when attempting to run recompress
+ and writeback simultaneously).
======== =============================================================
If you use 'echo', the returned value is set by the 'echo' utility,
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index d170bf6cdcd8..37622268104e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -627,6 +627,12 @@ static ssize_t writeback_store(struct device *dev,
goto release_init_lock;
}
+ /* Do not permit concurrent post-processing actions. */
+ if (atomic_xchg(&zram->pp_in_progress, 1)) {
+ up_read(&zram->init_lock);
+ return -EAGAIN;
+ }
+
if (!zram->backing_dev) {
ret = -ENODEV;
goto release_init_lock;
@@ -753,6 +759,7 @@ static ssize_t writeback_store(struct device *dev,
free_block_bdev(zram, blk_idx);
__free_page(page);
release_init_lock:
+ atomic_set(&zram->pp_in_progress, 0);
up_read(&zram->init_lock);
return ret;
@@ -1883,6 +1890,12 @@ static ssize_t recompress_store(struct device *dev,
goto release_init_lock;
}
+ /* Do not permit concurrent post-processing actions. */
+ if (atomic_xchg(&zram->pp_in_progress, 1)) {
+ up_read(&zram->init_lock);
+ return -EAGAIN;
+ }
+
if (algo) {
bool found = false;
@@ -1950,6 +1963,7 @@ static ssize_t recompress_store(struct device *dev,
__free_page(page);
release_init_lock:
+ atomic_set(&zram->pp_in_progress, 0);
up_read(&zram->init_lock);
return ret;
}
@@ -2146,6 +2160,7 @@ static void zram_reset_device(struct zram *zram)
zram->disksize = 0;
zram_destroy_comps(zram);
memset(&zram->stats, 0, sizeof(zram->stats));
+ atomic_set(&zram->pp_in_progress, 0);
reset_bdev(zram);
comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor);
@@ -2383,6 +2398,7 @@ static int zram_add(void)
zram->disk->fops = &zram_devops;
zram->disk->private_data = zram;
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
+ atomic_set(&zram->pp_in_progress, 0);
/* Actual capacity set using sysfs (/sys/block/zram<id>/disksize */
set_capacity(zram->disk, 0);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 914cb6629969..73a9d47d76ba 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -140,5 +140,6 @@ struct zram {
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
struct dentry *debugfs_dir;
#endif
+ atomic_t pp_in_progress;
};
#endif
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 3/7] zram: rework recompress target selection strategy
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 1/7] zram: introduce ZRAM_PP_SLOT flag Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 2/7] zram: permit only one post-processing operation at a time Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-10-01 7:42 ` Dan Carpenter
2024-09-17 2:09 ` [PATCHv5 4/7] zram: rework writeback " Sergey Senozhatsky
` (3 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
Target slot selection for recompression is just a simple
iteration over zram->table entries (stored pages) from
slot 0 to max slot. Given that zram->table slots are
written in random order and are not sorted by size, a
simple iteration over slots selects suboptimal targets
for recompression. This is not a problem if we recompress
every single zram->table slot, but we never do that in
reality. In reality we limit the number of slots we
can recompress (via max_pages parameter) and hence proper
slot selection becomes very important. The strategy is
quite simple, suppose we have two candidate slots for
recompression, one of size 48 bytes and one of size 2800
bytes, and we can recompress only one, then it certainly
makes more sense to pick 2800 entry for recompression.
Because even if we manage to compress 48 bytes objects
even further the savings are going to be very small.
Potential savings after good re-compression of 2800 bytes
objects are much higher.
This patch reworks slot selection and introduces the
strategy described above: among candidate slots always
select the biggest ones first.
For that the patch introduces zram_pp_ctl (post-processing)
structure which holds NUM_PP_BUCKETS pp buckets of slots.
Slots are assigned to a particular group based on their
sizes - the larger the size of the slot the higher the group
index. This, basically, sorts slots by size in liner time
(we still perform just one iteration over zram->table slots).
When we select slot for recompression we always first lookup
in higher pp buckets (those that hold the largest slots).
Which achieves the desired behavior.
TEST
====
A very simple demonstration: zram is configured with zstd, and
zstd with dict as a recompression stream. A limited (max 4096
pages) recompression is performed then, with a log of sizes of
slots that were recompressed. You can see that patched zram
selects slots for recompression in significantly different
manner, which leads to higher memory savings (see column #2 of
mm_stat output).
BASE
----
*** initial state of zram device
/sys/block/zram0/mm_stat
1750994944 504491413 514203648 0 514203648 1 0 34204 34204
*** recompress idle max_pages=4096
/sys/block/zram0/mm_stat
1750994944 504262229 514953216 0 514203648 1 0 34204 34204
Sizes of selected objects for recompression:
... 45 58 24 226 91 40 24 24 24 424 2104 93 2078 2078 2078 959 154 ...
PATCHED
-------
*** initial state of zram device
/sys/block/zram0/mm_stat
1750982656 504492801 514170880 0 514170880 1 0 34204 34204
*** recompress idle max_pages=4096
/sys/block/zram0/mm_stat
1750982656 503716710 517586944 0 514170880 1 0 34204 34204
Sizes of selected objects for recompression:
... 3680 3694 3667 3590 3614 3553 3537 3548 3550 3542 3543 3537 ...
Note, pp-slots are not strictly sorted, there is a PP_BUCKET_SIZE_RANGE
variation of sizes within particular bucket.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 187 +++++++++++++++++++++++++++++-----
1 file changed, 160 insertions(+), 27 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 37622268104e..6688f70b2140 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -184,6 +184,99 @@ static void zram_accessed(struct zram *zram, u32 index)
#endif
}
+#ifdef CONFIG_ZRAM_MULTI_COMP
+struct zram_pp_slot {
+ unsigned long index;
+ struct list_head entry;
+};
+
+/*
+ * A post-processing bucket is, essentially, a size class, this defines
+ * the range (in bytes) of pp-slots sizes in particular bucket.
+ */
+#define PP_BUCKET_SIZE_RANGE 64
+#define NUM_PP_BUCKETS ((PAGE_SIZE / PP_BUCKET_SIZE_RANGE) + 1)
+
+struct zram_pp_ctl {
+ struct list_head pp_buckets[NUM_PP_BUCKETS];
+};
+
+static struct zram_pp_ctl *init_pp_ctl(void)
+{
+ struct zram_pp_ctl *ctl;
+ u32 idx;
+
+ ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
+ if (!ctl)
+ return NULL;
+
+ for (idx = 0; idx < NUM_PP_BUCKETS; idx++)
+ INIT_LIST_HEAD(&ctl->pp_buckets[idx]);
+ return ctl;
+}
+
+static void release_pp_slot(struct zram *zram, struct zram_pp_slot *pps)
+{
+ list_del_init(&pps->entry);
+
+ zram_slot_lock(zram, pps->index);
+ zram_clear_flag(zram, pps->index, ZRAM_PP_SLOT);
+ zram_slot_unlock(zram, pps->index);
+
+ kfree(pps);
+}
+
+static void release_pp_ctl(struct zram *zram, struct zram_pp_ctl *ctl)
+{
+ u32 idx;
+
+ if (!ctl)
+ return;
+
+ for (idx = 0; idx < NUM_PP_BUCKETS; idx++) {
+ while (!list_empty(&ctl->pp_buckets[idx])) {
+ struct zram_pp_slot *pps;
+
+ pps = list_first_entry(&ctl->pp_buckets[idx],
+ struct zram_pp_slot,
+ entry);
+ release_pp_slot(zram, pps);
+ }
+ }
+
+ kfree(ctl);
+}
+
+static void place_pp_slot(struct zram *zram, struct zram_pp_ctl *ctl,
+ struct zram_pp_slot *pps)
+{
+ u32 idx;
+
+ idx = zram_get_obj_size(zram, pps->index) / PP_BUCKET_SIZE_RANGE;
+ list_add(&pps->entry, &ctl->pp_buckets[idx]);
+
+ zram_set_flag(zram, pps->index, ZRAM_PP_SLOT);
+}
+
+static struct zram_pp_slot *select_pp_slot(struct zram_pp_ctl *ctl)
+{
+ struct zram_pp_slot *pps = NULL;
+ s32 idx = NUM_PP_BUCKETS - 1;
+
+ /* The higher the bucket id the more optimal slot post-processing is */
+ while (idx > 0) {
+ pps = list_first_entry_or_null(&ctl->pp_buckets[idx],
+ struct zram_pp_slot,
+ entry);
+ if (pps)
+ break;
+
+ idx--;
+ }
+ return pps;
+}
+#endif
+
static inline void update_used_max(struct zram *zram,
const unsigned long pages)
{
@@ -1657,6 +1750,52 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
}
#ifdef CONFIG_ZRAM_MULTI_COMP
+#define RECOMPRESS_IDLE (1 << 0)
+#define RECOMPRESS_HUGE (1 << 1)
+
+static int scan_slots_for_recompress(struct zram *zram, u32 mode,
+ struct zram_pp_ctl *ctl)
+{
+ unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
+ struct zram_pp_slot *pps = NULL;
+ unsigned long index;
+
+ for (index = 0; index < nr_pages; index++) {
+ if (!pps)
+ pps = kmalloc(sizeof(*pps), GFP_KERNEL);
+ if (!pps)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pps->entry);
+
+ 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_SAME) ||
+ zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+ goto next;
+
+ pps->index = index;
+ place_pp_slot(zram, ctl, pps);
+ pps = NULL;
+next:
+ zram_slot_unlock(zram, index);
+ }
+
+ kfree(pps);
+ return 0;
+}
+
/*
* This function will decompress (unless it's ZRAM_HUGE) the page and then
* attempt to compress it using provided compression algorithm priority
@@ -1664,7 +1803,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
*
* Corresponding ZRAM slot should be locked.
*/
-static int zram_recompress(struct zram *zram, u32 index, struct page *page,
+static int recompress_slot(struct zram *zram, u32 index, struct page *page,
u64 *num_recomp_pages, u32 threshold, u32 prio,
u32 prio_max)
{
@@ -1807,20 +1946,17 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page,
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)
{
u32 prio = ZRAM_SECONDARY_COMP, prio_max = ZRAM_MAX_COMPS;
struct zram *zram = dev_to_zram(dev);
- unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
char *args, *param, *val, *algo = NULL;
u64 num_recomp_pages = ULLONG_MAX;
+ struct zram_pp_ctl *ctl = NULL;
+ struct zram_pp_slot *pps;
u32 mode = 0, threshold = 0;
- unsigned long index;
struct page *page;
ssize_t ret;
@@ -1922,36 +2058,32 @@ static ssize_t recompress_store(struct device *dev,
goto release_init_lock;
}
+ ctl = init_pp_ctl();
+ if (!ctl) {
+ ret = -ENOMEM;
+ goto release_init_lock;
+ }
+
+ scan_slots_for_recompress(zram, mode, ctl);
+
ret = len;
- for (index = 0; index < nr_pages; index++) {
+ while ((pps = select_pp_slot(ctl))) {
int err = 0;
if (!num_recomp_pages)
break;
- zram_slot_lock(zram, index);
-
- if (!zram_allocated(zram, index))
- goto next;
-
- if (mode & RECOMPRESS_IDLE &&
- !zram_test_flag(zram, index, ZRAM_IDLE))
+ zram_slot_lock(zram, pps->index);
+ if (!zram_test_flag(zram, pps->index, ZRAM_PP_SLOT))
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, &num_recomp_pages,
- threshold, prio, prio_max);
+ err = recompress_slot(zram, pps->index, page,
+ &num_recomp_pages, threshold,
+ prio, prio_max);
next:
- zram_slot_unlock(zram, index);
+ zram_slot_unlock(zram, pps->index);
+ release_pp_slot(zram, pps);
+
if (err) {
ret = err;
break;
@@ -1963,6 +2095,7 @@ static ssize_t recompress_store(struct device *dev,
__free_page(page);
release_init_lock:
+ release_pp_ctl(zram, ctl);
atomic_set(&zram->pp_in_progress, 0);
up_read(&zram->init_lock);
return ret;
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 4/7] zram: rework writeback target selection strategy
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
` (2 preceding siblings ...)
2024-09-17 2:09 ` [PATCHv5 3/7] zram: rework recompress target selection strategy Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 5/7] zram: do not mark idle slots that cannot be idle Sergey Senozhatsky
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
Writeback suffers from the same problem as recompression
did before - target slot selection for writeback is just
a simple iteration over zram->table entries (stored pages)
which selects suboptimal targets for writeback. This is
especially problematic for writeback, because we uncompress
objects before writeback so each of them takes 4K out of
limited writeback storage. For example, when we take a
48 bytes slot and store it as a 4K object to writeback device
we only save 48 bytes of memory (release from zsmalloc pool).
We naturally want to pick the largest objects for writeback,
because then each writeback will release the largest amount
of memory.
This patch applies the same solution and strategy as for
recompression target selection: pp control (post-process)
with 16 buckets of candidate pp slots. Slots are assigned to
pp buckets based on sizes - the larger the slot the higher the
group index. This gives us sorted by size lists of candidate
slots (in linear time), so that among post-processing candidate
slots we always select the largest ones first and maximize
the memory saving.
TEST
====
A very simple demonstration: zram is configured with a writeback
device. A limited writeback (wb_limit 2500 pages) is performed
then, with a log of sizes of slots that were written back.
You can see that patched zram selects slots for recompression in
significantly different manner, which leads to higher memory
savings (see column #2 of mm_stat output).
BASE
----
*** initial state of zram device
/sys/block/zram0/mm_stat
1750327296 619765836 631902208 0 631902208 1 0 34278 34278
*** writeback idle wb_limit 2500
/sys/block/zram0/mm_stat
1750327296 617622333 631578624 0 631902208 1 0 34278 34278
Sizes of selected objects for writeback:
... 193 349 46 46 46 46 852 1002 543 162 107 49 34 34 34 ...
PATCHED
-------
*** initial state of zram device
/sys/block/zram0/mm_stat
1750319104 619760957 631992320 0 631992320 1 0 34278 34278
*** writeback idle wb_limit 2500
/sys/block/zram0/mm_stat
1750319104 612672056 626135040 0 631992320 1 0 34278 34278
Sizes of selected objects for writeback:
... 3667 3580 3581 3580 3581 3581 3581 3231 3211 3203 3231 3246 ...
Note, pp-slots are not strictly sorted, there is a PP_BUCKET_SIZE_RANGE
variation of sizes within particular bucket.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 83 +++++++++++++++++++++++++++--------
1 file changed, 64 insertions(+), 19 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 6688f70b2140..8ba994a5f30e 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -184,7 +184,7 @@ static void zram_accessed(struct zram *zram, u32 index)
#endif
}
-#ifdef CONFIG_ZRAM_MULTI_COMP
+#if defined CONFIG_ZRAM_WRITEBACK || defined CONFIG_ZRAM_MULTI_COMP
struct zram_pp_slot {
unsigned long index;
struct list_head entry;
@@ -681,11 +681,57 @@ static void read_from_bdev_async(struct zram *zram, struct page *page,
#define IDLE_WRITEBACK (1<<1)
#define INCOMPRESSIBLE_WRITEBACK (1<<2)
+static int scan_slots_for_writeback(struct zram *zram, u32 mode,
+ unsigned long nr_pages,
+ unsigned long index,
+ struct zram_pp_ctl *ctl)
+{
+ struct zram_pp_slot *pps = NULL;
+
+ for (; nr_pages != 0; index++, nr_pages--) {
+ if (!pps)
+ pps = kmalloc(sizeof(*pps), GFP_KERNEL);
+ if (!pps)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pps->entry);
+
+ zram_slot_lock(zram, index);
+ if (!zram_allocated(zram, index))
+ goto next;
+
+ if (zram_test_flag(zram, index, ZRAM_WB) ||
+ zram_test_flag(zram, index, ZRAM_SAME))
+ goto next;
+
+ if (mode & IDLE_WRITEBACK &&
+ !zram_test_flag(zram, index, ZRAM_IDLE))
+ goto next;
+ if (mode & HUGE_WRITEBACK &&
+ !zram_test_flag(zram, index, ZRAM_HUGE))
+ goto next;
+ if (mode & INCOMPRESSIBLE_WRITEBACK &&
+ !zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+ goto next;
+
+ pps->index = index;
+ place_pp_slot(zram, ctl, pps);
+ pps = NULL;
+next:
+ zram_slot_unlock(zram, index);
+ }
+
+ kfree(pps);
+ return 0;
+}
+
static ssize_t writeback_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
+ struct zram_pp_ctl *ctl = NULL;
+ struct zram_pp_slot *pps;
unsigned long index = 0;
struct bio bio;
struct bio_vec bio_vec;
@@ -737,7 +783,15 @@ static ssize_t writeback_store(struct device *dev,
goto release_init_lock;
}
- for (; nr_pages != 0; index++, nr_pages--) {
+ ctl = init_pp_ctl();
+ if (!ctl) {
+ ret = -ENOMEM;
+ goto release_init_lock;
+ }
+
+ scan_slots_for_writeback(zram, mode, nr_pages, index, ctl);
+
+ while ((pps = select_pp_slot(ctl))) {
spin_lock(&zram->wb_limit_lock);
if (zram->wb_limit_enable && !zram->bd_wb_limit) {
spin_unlock(&zram->wb_limit_lock);
@@ -754,25 +808,10 @@ static ssize_t writeback_store(struct device *dev,
}
}
+ index = pps->index;
zram_slot_lock(zram, index);
- if (!zram_allocated(zram, index))
- goto next;
-
- if (zram_test_flag(zram, index, ZRAM_WB) ||
- zram_test_flag(zram, index, ZRAM_SAME) ||
- zram_test_flag(zram, index, ZRAM_UNDER_WB))
- goto next;
-
- if (mode & IDLE_WRITEBACK &&
- !zram_test_flag(zram, index, ZRAM_IDLE))
- goto next;
- if (mode & HUGE_WRITEBACK &&
- !zram_test_flag(zram, index, ZRAM_HUGE))
- goto next;
- if (mode & INCOMPRESSIBLE_WRITEBACK &&
- !zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE))
+ if (!zram_test_flag(zram, index, ZRAM_PP_SLOT))
goto next;
-
/*
* Clearing ZRAM_UNDER_WB is duty of caller.
* IOW, zram_free_page never clear it.
@@ -786,6 +825,8 @@ static ssize_t writeback_store(struct device *dev,
zram_clear_flag(zram, index, ZRAM_UNDER_WB);
zram_clear_flag(zram, index, ZRAM_IDLE);
zram_slot_unlock(zram, index);
+
+ release_pp_slot(zram, pps);
continue;
}
@@ -804,6 +845,8 @@ static ssize_t writeback_store(struct device *dev,
zram_clear_flag(zram, index, ZRAM_UNDER_WB);
zram_clear_flag(zram, index, ZRAM_IDLE);
zram_slot_unlock(zram, index);
+
+ release_pp_slot(zram, pps);
/*
* BIO errors are not fatal, we continue and simply
* attempt to writeback the remaining objects (pages).
@@ -846,12 +889,14 @@ static ssize_t writeback_store(struct device *dev,
spin_unlock(&zram->wb_limit_lock);
next:
zram_slot_unlock(zram, index);
+ release_pp_slot(zram, pps);
}
if (blk_idx)
free_block_bdev(zram, blk_idx);
__free_page(page);
release_init_lock:
+ release_pp_ctl(zram, ctl);
atomic_set(&zram->pp_in_progress, 0);
up_read(&zram->init_lock);
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 5/7] zram: do not mark idle slots that cannot be idle
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
` (3 preceding siblings ...)
2024-09-17 2:09 ` [PATCHv5 4/7] zram: rework writeback " Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 6/7] zram: reshuffle zram_free_page() flags operations Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 7/7] zram: remove UNDER_WB and simplify writeback Sergey Senozhatsky
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
ZRAM_SAME slots cannot be post-processed (writeback or
recompress) so do not mark them ZRAM_IDLE. Same with
ZRAM_WB slots, they cannot be ZRAM_IDLE because they
are not in zsmalloc pool anymore.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 8ba994a5f30e..e48e2deec685 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -392,17 +392,28 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
/*
* Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race.
* See the comment in writeback_store.
+ *
+ * Also do not mark ZRAM_SAME slots as ZRAM_IDLE, because no
+ * post-processing (recompress, writeback) happens to the
+ * ZRAM_SAME slot.
+ *
+ * And ZRAM_WB slots simply cannot be ZRAM_IDLE.
*/
zram_slot_lock(zram, index);
- if (zram_allocated(zram, index) &&
- !zram_test_flag(zram, index, ZRAM_UNDER_WB)) {
+ if (!zram_allocated(zram, index) ||
+ zram_test_flag(zram, index, ZRAM_WB) ||
+ zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
+ zram_test_flag(zram, index, ZRAM_SAME)) {
+ zram_slot_unlock(zram, index);
+ continue;
+ }
+
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
- is_idle = !cutoff || ktime_after(cutoff,
- zram->table[index].ac_time);
+ is_idle = !cutoff ||
+ ktime_after(cutoff, zram->table[index].ac_time);
#endif
- if (is_idle)
- zram_set_flag(zram, index, ZRAM_IDLE);
- }
+ if (is_idle)
+ zram_set_flag(zram, index, ZRAM_IDLE);
zram_slot_unlock(zram, index);
}
}
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 6/7] zram: reshuffle zram_free_page() flags operations
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
` (4 preceding siblings ...)
2024-09-17 2:09 ` [PATCHv5 5/7] zram: do not mark idle slots that cannot be idle Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 7/7] zram: remove UNDER_WB and simplify writeback Sergey Senozhatsky
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
Drop some redundant zram_test_flag() calls and re-order
zram_clear_flag() calls. Plus two small trivial coding
style fixes. No functional changes.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index e48e2deec685..8f01dc1fc796 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1499,20 +1499,17 @@ static void zram_free_page(struct zram *zram, size_t index)
#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME
zram->table[index].ac_time = 0;
#endif
- if (zram_test_flag(zram, index, ZRAM_IDLE))
- zram_clear_flag(zram, index, ZRAM_IDLE);
+
+ zram_clear_flag(zram, index, ZRAM_IDLE);
+ zram_clear_flag(zram, index, ZRAM_INCOMPRESSIBLE);
+ zram_clear_flag(zram, index, ZRAM_PP_SLOT);
+ zram_set_priority(zram, index, 0);
if (zram_test_flag(zram, index, ZRAM_HUGE)) {
zram_clear_flag(zram, index, ZRAM_HUGE);
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);
- zram_clear_flag(zram, index, ZRAM_PP_SLOT);
-
if (zram_test_flag(zram, index, ZRAM_WB)) {
zram_clear_flag(zram, index, ZRAM_WB);
free_block_bdev(zram, zram_get_element(zram, index));
@@ -1536,13 +1533,12 @@ static void zram_free_page(struct zram *zram, size_t index)
zs_free(zram->mem_pool, handle);
atomic64_sub(zram_get_obj_size(zram, index),
- &zram->stats.compr_data_size);
+ &zram->stats.compr_data_size);
out:
atomic64_dec(&zram->stats.pages_stored);
zram_set_handle(zram, index, 0);
zram_set_obj_size(zram, index, 0);
- WARN_ON_ONCE(zram->table[index].flags &
- ~(1UL << ZRAM_UNDER_WB));
+ WARN_ON_ONCE(zram->table[index].flags & ~(1UL << ZRAM_UNDER_WB));
}
/*
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv5 7/7] zram: remove UNDER_WB and simplify writeback
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
` (5 preceding siblings ...)
2024-09-17 2:09 ` [PATCHv5 6/7] zram: reshuffle zram_free_page() flags operations Sergey Senozhatsky
@ 2024-09-17 2:09 ` Sergey Senozhatsky
6 siblings, 0 replies; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-09-17 2:09 UTC (permalink / raw)
To: Andrew Morton, Minchan Kim; +Cc: linux-kernel, Sergey Senozhatsky
We now have only one active post-processing at any time, so
we don't have same race conditions that we had before. If
slot selected for post-processing gets freed or freed and
reallocated it loses its PP_SLOT flag and there is no way
for such a slot to gain PP_SLOT flag again until current
post-processing terminates.
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
---
drivers/block/zram/zram_drv.c | 53 +++++++++++------------------------
drivers/block/zram/zram_drv.h | 1 -
2 files changed, 16 insertions(+), 38 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 8f01dc1fc796..69458f8afe7a 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -390,10 +390,7 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
for (index = 0; index < nr_pages; index++) {
/*
- * Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race.
- * See the comment in writeback_store.
- *
- * Also do not mark ZRAM_SAME slots as ZRAM_IDLE, because no
+ * Do not mark ZRAM_SAME slots as ZRAM_IDLE, because no
* post-processing (recompress, writeback) happens to the
* ZRAM_SAME slot.
*
@@ -402,7 +399,6 @@ static void mark_idle(struct zram *zram, ktime_t cutoff)
zram_slot_lock(zram, index);
if (!zram_allocated(zram, index) ||
zram_test_flag(zram, index, ZRAM_WB) ||
- zram_test_flag(zram, index, ZRAM_UNDER_WB) ||
zram_test_flag(zram, index, ZRAM_SAME)) {
zram_slot_unlock(zram, index);
continue;
@@ -821,22 +817,17 @@ static ssize_t writeback_store(struct device *dev,
index = pps->index;
zram_slot_lock(zram, index);
- if (!zram_test_flag(zram, index, ZRAM_PP_SLOT))
- goto next;
/*
- * Clearing ZRAM_UNDER_WB is duty of caller.
- * IOW, zram_free_page never clear it.
+ * scan_slots() sets ZRAM_PP_SLOT and relases slot lock, so
+ * slots can change in the meantime. If slots are accessed or
+ * freed they lose ZRAM_PP_SLOT flag and hence we don't
+ * post-process them.
*/
- zram_set_flag(zram, index, ZRAM_UNDER_WB);
- /* Need for hugepage writeback racing */
- zram_set_flag(zram, index, ZRAM_IDLE);
+ if (!zram_test_flag(zram, index, ZRAM_PP_SLOT))
+ goto next;
zram_slot_unlock(zram, index);
- if (zram_read_page(zram, page, index, NULL)) {
- zram_slot_lock(zram, index);
- zram_clear_flag(zram, index, ZRAM_UNDER_WB);
- zram_clear_flag(zram, index, ZRAM_IDLE);
- zram_slot_unlock(zram, index);
+ if (zram_read_page(zram, page, index, NULL)) {
release_pp_slot(zram, pps);
continue;
}
@@ -852,11 +843,6 @@ static ssize_t writeback_store(struct device *dev,
*/
err = submit_bio_wait(&bio);
if (err) {
- zram_slot_lock(zram, index);
- zram_clear_flag(zram, index, ZRAM_UNDER_WB);
- zram_clear_flag(zram, index, ZRAM_IDLE);
- zram_slot_unlock(zram, index);
-
release_pp_slot(zram, pps);
/*
* BIO errors are not fatal, we continue and simply
@@ -871,25 +857,19 @@ static ssize_t writeback_store(struct device *dev,
}
atomic64_inc(&zram->stats.bd_writes);
+ zram_slot_lock(zram, index);
/*
- * We released zram_slot_lock so need to check if the slot was
- * changed. If there is freeing for the slot, we can catch it
- * easily by zram_allocated.
- * A subtle case is the slot is freed/reallocated/marked as
- * ZRAM_IDLE again. To close the race, idle_store doesn't
- * mark ZRAM_IDLE once it found the slot was ZRAM_UNDER_WB.
- * Thus, we could close the race by checking ZRAM_IDLE bit.
+ * Same as above, we release slot lock during writeback so
+ * slot can change under us: slot_free() or slot_free() and
+ * reallocation (zram_write_page()). In both cases slot loses
+ * ZRAM_PP_SLOT flag. No concurrent post-processing can set
+ * ZRAM_PP_SLOT on such slots until current post-processing
+ * finishes.
*/
- zram_slot_lock(zram, index);
- if (!zram_allocated(zram, index) ||
- !zram_test_flag(zram, index, ZRAM_IDLE)) {
- zram_clear_flag(zram, index, ZRAM_UNDER_WB);
- zram_clear_flag(zram, index, ZRAM_IDLE);
+ if (!zram_test_flag(zram, index, ZRAM_PP_SLOT))
goto next;
- }
zram_free_page(zram, index);
- zram_clear_flag(zram, index, ZRAM_UNDER_WB);
zram_set_flag(zram, index, ZRAM_WB);
zram_set_element(zram, index, blk_idx);
blk_idx = 0;
@@ -1538,7 +1518,6 @@ static void zram_free_page(struct zram *zram, size_t index)
atomic64_dec(&zram->stats.pages_stored);
zram_set_handle(zram, index, 0);
zram_set_obj_size(zram, index, 0);
- WARN_ON_ONCE(zram->table[index].flags & ~(1UL << ZRAM_UNDER_WB));
}
/*
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 73a9d47d76ba..134be414e210 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -47,7 +47,6 @@
enum zram_pageflags {
ZRAM_SAME = ZRAM_FLAG_SHIFT, /* Page consists the same element */
ZRAM_WB, /* page is stored on backing_device */
- ZRAM_UNDER_WB, /* page is under writeback */
ZRAM_PP_SLOT, /* Selected for post-processing */
ZRAM_HUGE, /* Incompressible page */
ZRAM_IDLE, /* not accessed page since last idle marking */
--
2.46.0.662.g92d0881bb0-goog
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv5 3/7] zram: rework recompress target selection strategy
2024-09-17 2:09 ` [PATCHv5 3/7] zram: rework recompress target selection strategy Sergey Senozhatsky
@ 2024-10-01 7:42 ` Dan Carpenter
2024-10-01 8:40 ` Sergey Senozhatsky
0 siblings, 1 reply; 11+ messages in thread
From: Dan Carpenter @ 2024-10-01 7:42 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Andrew Morton, Minchan Kim, linux-kernel
On Tue, Sep 17, 2024 at 11:09:08AM +0900, Sergey Senozhatsky wrote:
> +static struct zram_pp_slot *select_pp_slot(struct zram_pp_ctl *ctl)
> +{
> + struct zram_pp_slot *pps = NULL;
> + s32 idx = NUM_PP_BUCKETS - 1;
> +
> + /* The higher the bucket id the more optimal slot post-processing is */
> + while (idx > 0) {
Why is this not idx >= 0? Why skip the first bucket?
regards,
dan carpenter
> + pps = list_first_entry_or_null(&ctl->pp_buckets[idx],
> + struct zram_pp_slot,
> + entry);
> + if (pps)
> + break;
> +
> + idx--;
> + }
> + return pps;
> +}
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv5 3/7] zram: rework recompress target selection strategy
2024-10-01 7:42 ` Dan Carpenter
@ 2024-10-01 8:40 ` Sergey Senozhatsky
2024-10-01 9:16 ` Dan Carpenter
0 siblings, 1 reply; 11+ messages in thread
From: Sergey Senozhatsky @ 2024-10-01 8:40 UTC (permalink / raw)
To: Dan Carpenter
Cc: Sergey Senozhatsky, Andrew Morton, Minchan Kim, linux-kernel
On (24/10/01 10:42), Dan Carpenter wrote:
> On Tue, Sep 17, 2024 at 11:09:08AM +0900, Sergey Senozhatsky wrote:
> > +static struct zram_pp_slot *select_pp_slot(struct zram_pp_ctl *ctl)
> > +{
> > + struct zram_pp_slot *pps = NULL;
> > + s32 idx = NUM_PP_BUCKETS - 1;
> > +
> > + /* The higher the bucket id the more optimal slot post-processing is */
> > + while (idx > 0) {
>
> Why is this not idx >= 0? Why skip the first bucket?
That's a typo, thanks for spotting this. Mind if I send a quick
fixup.patch online liner to Andrew?
Theoretically, we can't do any reasonable post-processing on slots
from bucket 0 (yet), because that bucket is for objects smaller than
64 bytes, but technically we should not skip it.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv5 3/7] zram: rework recompress target selection strategy
2024-10-01 8:40 ` Sergey Senozhatsky
@ 2024-10-01 9:16 ` Dan Carpenter
0 siblings, 0 replies; 11+ messages in thread
From: Dan Carpenter @ 2024-10-01 9:16 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Andrew Morton, Minchan Kim, linux-kernel
On Tue, Oct 01, 2024 at 05:40:57PM +0900, Sergey Senozhatsky wrote:
> On (24/10/01 10:42), Dan Carpenter wrote:
> > On Tue, Sep 17, 2024 at 11:09:08AM +0900, Sergey Senozhatsky wrote:
> > > +static struct zram_pp_slot *select_pp_slot(struct zram_pp_ctl *ctl)
> > > +{
> > > + struct zram_pp_slot *pps = NULL;
> > > + s32 idx = NUM_PP_BUCKETS - 1;
> > > +
> > > + /* The higher the bucket id the more optimal slot post-processing is */
> > > + while (idx > 0) {
> >
> > Why is this not idx >= 0? Why skip the first bucket?
>
> That's a typo, thanks for spotting this. Mind if I send a quick
> fixup.patch online liner to Andrew?
Please do. :)
regards,
dan carpenter
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2024-10-01 9:16 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-17 2:09 [PATCHv5 0/7] zram: optimal post-processing target selection Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 1/7] zram: introduce ZRAM_PP_SLOT flag Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 2/7] zram: permit only one post-processing operation at a time Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 3/7] zram: rework recompress target selection strategy Sergey Senozhatsky
2024-10-01 7:42 ` Dan Carpenter
2024-10-01 8:40 ` Sergey Senozhatsky
2024-10-01 9:16 ` Dan Carpenter
2024-09-17 2:09 ` [PATCHv5 4/7] zram: rework writeback " Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 5/7] zram: do not mark idle slots that cannot be idle Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 6/7] zram: reshuffle zram_free_page() flags operations Sergey Senozhatsky
2024-09-17 2:09 ` [PATCHv5 7/7] zram: remove UNDER_WB and simplify writeback Sergey Senozhatsky
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.