From: Hao Jia <jiahao.kernel@gmail.com>
To: akpm@linux-foundation.org, tj@kernel.org, hannes@cmpxchg.org,
shakeel.butt@linux.dev, mhocko@kernel.org, yosry@kernel.org,
mkoutny@suse.com, nphamcs@gmail.com, chengming.zhou@linux.dev,
muchun.song@linux.dev, roman.gushchin@linux.dev
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, Hao Jia <jiahao1@lixiang.com>
Subject: [PATCH v5 3/6] mm/zswap: Extract a reusable writeback helper from shrink_worker()
Date: Mon, 29 Jun 2026 19:20:29 +0800 [thread overview]
Message-ID: <20260629112032.20423-4-jiahao.kernel@gmail.com> (raw)
In-Reply-To: <20260629112032.20423-1-jiahao.kernel@gmail.com>
From: Hao Jia <jiahao1@lixiang.com>
Extract a reusable writeback helper zswap_shrink_one_memcg() from
shrink_worker(). This helper will be reused by the upcoming proactive
writeback feature.
zswap_shrink_one_memcg() takes one step of a memcg-tree writeback walk
driven by the caller's iterator. Consequently, shrink_worker() now only
needs to calculate the acceptance threshold, drive its own iteration
based on this helper, and abort the walk when zswap_shrink_one_memcg()
returns -EBUSY.
Suggested-by: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Hao Jia <jiahao1@lixiang.com>
---
mm/zswap.c | 118 +++++++++++++++++++++++++++++++----------------------
1 file changed, 69 insertions(+), 49 deletions(-)
diff --git a/mm/zswap.c b/mm/zswap.c
index e2c2a3f1e061..ba01bf0e44e9 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -1351,12 +1351,70 @@ static long shrink_memcg(struct mem_cgroup *memcg, unsigned long nr_to_scan)
return walk_arg.bytes_written;
}
+/* Track progress of a memcg-tree writeback walk. */
+struct zswap_shrink_state {
+ int scans;
+ int failures;
+};
+
+/*
+ * Take one step of a memcg-tree writeback walk driven by the caller's
+ * iterator, and fold the result into @s, the retry bookkeeping shared
+ * across steps. @memcg is the iterator's current memcg, or NULL once
+ * it has wrapped around after a full pass over the tree.
+ *
+ * The function returns -EBUSY to signal the caller to abort the walk after
+ * encountering either of the following MAX_RECLAIM_RETRIES times:
+ * - No writeback-candidate memcgs were found in a memcg tree walk.
+ * - Shrinking a writeback-candidate memcg failed.
+ *
+ * Return: The number of compressed bytes written back (>= 0), or -EBUSY
+ * when the caller should abort the walk.
+ */
+static long zswap_shrink_one_memcg(struct mem_cgroup *memcg,
+ struct zswap_shrink_state *s)
+{
+ long shrunk;
+
+ /*
+ * Reaching a NULL memcg means a full hierarchy pass completed.
+ * Exclude the memcg-disabled case, where it is always NULL, and
+ * fall through to shrink the root LRU directly.
+ */
+ if (!memcg && !mem_cgroup_disabled()) {
+ /*
+ * Continue shrinking without incrementing failures if we found
+ * candidate memcgs in the last tree walk.
+ */
+ if (!s->scans && ++s->failures == MAX_RECLAIM_RETRIES)
+ return -EBUSY;
+ s->scans = 0;
+ return 0;
+ }
+
+ shrunk = shrink_memcg(memcg, NR_ZSWAP_WB_BATCH);
+
+ /*
+ * There are no writeback-candidate pages in the memcg. With memcg
+ * enabled this is not an issue as long as we can find another memcg
+ * with pages in zswap, so skip without counting it as a candidate.
+ * With memcg disabled the root LRU is the only target, so we should
+ * abort if it has no writeback-candidate pages.
+ */
+ if (shrunk == -ENOENT)
+ return mem_cgroup_disabled() ? -EBUSY : 0;
+ s->scans++;
+
+ if (shrunk <= 0 && ++s->failures == MAX_RECLAIM_RETRIES)
+ return -EBUSY;
+
+ return shrunk;
+}
+
static void shrink_worker(struct work_struct *w)
{
- struct mem_cgroup *memcg;
- int failures = 0, attempts = 0;
+ struct zswap_shrink_state s = {};
unsigned long thr;
- long ret;
/* Reclaim down to the accept threshold */
thr = zswap_accept_thr_pages();
@@ -1367,11 +1425,6 @@ static void shrink_worker(struct work_struct *w)
* writeback-disabled memcgs (memory.zswap.writeback=0) are not
* candidates for shrinking.
*
- * Shrinking will be aborted if we encounter the following
- * MAX_RECLAIM_RETRIES times:
- * - No writeback-candidate memcgs found in a memcg tree walk.
- * - Shrinking a writeback-candidate memcg failed.
- *
* We save iteration cursor memcg into zswap_next_shrink,
* which can be modified by the offline memcg cleaner
* zswap_memcg_offline_cleanup().
@@ -1386,7 +1439,11 @@ static void shrink_worker(struct work_struct *w)
* offline memcg left in zswap_next_shrink will hold the reference
* until the next run of shrink_worker().
*/
- do {
+ while (zswap_total_pages() > thr) {
+ struct mem_cgroup *memcg;
+ long ret;
+
+ cond_resched();
/*
* Start shrinking from the next memcg after zswap_next_shrink.
* When the offline cleaner has already advanced the cursor,
@@ -1405,49 +1462,12 @@ static void shrink_worker(struct work_struct *w)
} while (memcg && !mem_cgroup_tryget_online(memcg));
spin_unlock(&zswap_shrink_lock);
- /*
- * Reaching a NULL memcg means a full hierarchy pass completed.
- * Exclude the memcg-disabled case, where it is always NULL, and
- * fall through to shrink the root LRU directly.
- */
- if (!memcg && !mem_cgroup_disabled()) {
- /*
- * Continue shrinking without incrementing failures if
- * we found candidate memcgs in the last tree walk.
- */
- if (!attempts && ++failures == MAX_RECLAIM_RETRIES)
- break;
-
- attempts = 0;
- goto resched;
- }
-
- ret = shrink_memcg(memcg, NR_ZSWAP_WB_BATCH);
+ ret = zswap_shrink_one_memcg(memcg, &s);
/* drop the extra reference */
mem_cgroup_put(memcg);
-
- /*
- * There are no writeback-candidate pages in the memcg.
- * This is not an issue as long as we can find another memcg
- * with pages in zswap. Skip this without incrementing attempts
- * and failures.
- */
- if (ret == -ENOENT) {
- /*
- * With memcg disabled the root LRU is the only target, so
- * we should abort if it has no writeback-candidate pages.
- */
- if (mem_cgroup_disabled())
- break;
- continue;
- }
- ++attempts;
-
- if (ret <= 0 && ++failures == MAX_RECLAIM_RETRIES)
+ if (ret == -EBUSY)
break;
-resched:
- cond_resched();
- } while (zswap_total_pages() > thr);
+ }
}
/*********************************
--
2.34.1
next prev parent reply other threads:[~2026-06-29 11:21 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 11:20 [PATCH v5 0/6] mm/zswap: Implement per-cgroup proactive writeback Hao Jia
2026-06-29 11:20 ` [PATCH v5 1/6] mm/zswap: Fix global shrinker when memory cgroup is disabled Hao Jia
2026-06-29 18:37 ` Nhat Pham
2026-06-30 10:51 ` Hao Jia
2026-06-30 16:02 ` Yosry Ahmed
2026-06-29 11:20 ` [PATCH v5 2/6] mm/zswap: Support batch writeback in shrink_memcg() Hao Jia
2026-06-30 0:21 ` Yosry Ahmed
2026-06-30 1:18 ` Hao Jia
2026-06-29 11:20 ` Hao Jia [this message]
2026-06-29 11:20 ` [PATCH v5 4/6] mm/zswap: Implement proactive writeback Hao Jia
2026-06-30 0:15 ` Yosry Ahmed
2026-06-30 1:49 ` Hao Jia
2026-06-30 16:10 ` Yosry Ahmed
2026-06-29 11:20 ` [PATCH v5 5/6] mm/zswap: Add per-memcg stat for " Hao Jia
2026-06-29 11:20 ` [PATCH v5 6/6] selftests/cgroup: Add tests for zswap " Hao Jia
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260629112032.20423-4-jiahao.kernel@gmail.com \
--to=jiahao.kernel@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=chengming.zhou@linux.dev \
--cc=hannes@cmpxchg.org \
--cc=jiahao1@lixiang.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@kernel.org \
--cc=mkoutny@suse.com \
--cc=muchun.song@linux.dev \
--cc=nphamcs@gmail.com \
--cc=roman.gushchin@linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=tj@kernel.org \
--cc=yosry@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox