]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
zram: do not slot_free() written-back slots
authorSergey Senozhatsky <senozhatsky@chromium.org>
Thu, 19 Mar 2026 03:44:56 +0000 (12:44 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 22 Mar 2026 00:36:33 +0000 (17:36 -0700)
slot_free() basically completely resets the slots by clearing all of
its flags and attributes.  While zram_writeback_complete() restores
some of flags back (those that are necessary for async read
decompression) we still lose a lot of slot's metadata.  For example,
slot's ac-time, or ZRAM_INCOMPRESSIBLE.

More importantly, restoring flags/attrs requires extra attention as
some of the flags are directly affecting zram device stats.  And the
original code did not pay that attention.  Namely ZRAM_HUGE slots
handling in zram_writeback_complete().  The call to slot_free() would
decrement ->huge_pages, however when zram_writeback_complete() restored
the slot's ZRAM_HUGE flag, it would not get reflected in an incremented
->huge_pages.  So when the slot would finally get freed, slot_free()
would decrement ->huge_pages again, leading to underflow.

Fix this by open-coding the required memory free and stats updates in
zram_writeback_complete(), rather than calling the destructive
slot_free().  Since we now preserve the ZRAM_HUGE flag on written-back
slots (for the deferred decompression path), we also update slot_free()
to skip decrementing ->huge_pages if ZRAM_WB is set.

Link: https://lkml.kernel.org/r/20260320023143.2372879-1-senozhatsky@chromium.org
Link: https://lkml.kernel.org/r/20260319034912.1894770-1-senozhatsky@chromium.org
Fixes: d38fab605c667 ("zram: introduce compressed data writeback")
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Acked-by: Minchan Kim <minchan@kernel.org>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Richard Chang <richardycc@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
drivers/block/zram/zram_drv.c

index a324ede6206d3a99eb102f87b929700a41ee5b3b..af679375b193598a836e14dbc1cebb16804c0050 100644 (file)
@@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram)
 
 static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
 {
-       u32 size, index = req->pps->index;
-       int err, prio;
-       bool huge;
+       u32 index = req->pps->index;
+       int err;
 
        err = blk_status_to_errno(req->bio.bi_status);
        if (err) {
@@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
                goto out;
        }
 
-       if (zram->compressed_wb) {
-               /*
-                * ZRAM_WB slots get freed, we need to preserve data required
-                * for read decompression.
-                */
-               size = get_slot_size(zram, index);
-               prio = get_slot_comp_priority(zram, index);
-               huge = test_slot_flag(zram, index, ZRAM_HUGE);
-       }
-
-       slot_free(zram, index);
-       set_slot_flag(zram, index, ZRAM_WB);
+       clear_slot_flag(zram, index, ZRAM_IDLE);
+       if (test_slot_flag(zram, index, ZRAM_HUGE))
+               atomic64_dec(&zram->stats.huge_pages);
+       atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size);
+       zs_free(zram->mem_pool, get_slot_handle(zram, index));
        set_slot_handle(zram, index, req->blk_idx);
-
-       if (zram->compressed_wb) {
-               if (huge)
-                       set_slot_flag(zram, index, ZRAM_HUGE);
-               set_slot_size(zram, index, size);
-               set_slot_comp_priority(zram, index, prio);
-       }
-
-       atomic64_inc(&zram->stats.pages_stored);
+       set_slot_flag(zram, index, ZRAM_WB);
 
 out:
        slot_unlock(zram, index);
@@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index)
        set_slot_comp_priority(zram, index, 0);
 
        if (test_slot_flag(zram, index, ZRAM_HUGE)) {
+               /*
+                * Writeback completion decrements ->huge_pages but keeps
+                * ZRAM_HUGE flag for deferred decompression path.
+                */
+               if (!test_slot_flag(zram, index, ZRAM_WB))
+                       atomic64_dec(&zram->stats.huge_pages);
                clear_slot_flag(zram, index, ZRAM_HUGE);
-               atomic64_dec(&zram->stats.huge_pages);
        }
 
        if (test_slot_flag(zram, index, ZRAM_WB)) {