From: Hao Jia <jiahao.kernel@gmail.com>
To: Yosry Ahmed <yosry@kernel.org>
Cc: akpm@linux-foundation.org, tj@kernel.org, hannes@cmpxchg.org,
shakeel.butt@linux.dev, mhocko@kernel.org, mkoutny@suse.com,
nphamcs@gmail.com, chengming.zhou@linux.dev,
muchun.song@linux.dev, roman.gushchin@linux.dev,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, Hao Jia <jiahao1@lixiang.com>
Subject: Re: [PATCH v4 2/5] mm/zswap: Factor writeback loop out of shrink_worker()
Date: Thu, 25 Jun 2026 19:28:06 +0800 [thread overview]
Message-ID: <91297bc0-268c-e9c2-57ae-6066eee5df2f@gmail.com> (raw)
In-Reply-To: <CAO9r8zPSZLaqLXw87V3q4tZa8WD7xCympKqfLMLB+o-++GksJQ@mail.gmail.com>
On 2026/6/25 01:00, Yosry Ahmed wrote:
> On Wed, Jun 24, 2026 at 4:55 AM Hao Jia <jiahao.kernel@gmail.com> wrote:
>>
>>
>>
>> On 2026/6/23 07:36, Yosry Ahmed wrote:
>>
>>
>> Perhaps something like this?
>>
>> struct zswap_shrink_state {
>> int attempts;
>> int failures;
>> bool stop;
>> };
>>
>> static bool zswap_shrink_no_candidate(struct zswap_shrink_state *s)
>> {
>> if (!s->attempts && ++s->failures == MAX_RECLAIM_RETRIES)
>> return true;
>>
>> s->attempts = 0;
>> return false;
>> }
>>
>> static long zswap_shrink_one(struct mem_cgroup *memcg,
>> struct zswap_shrink_state *s)
>> {
>> long shrunk;
>>
>> shrunk = shrink_memcg(memcg, NR_ZSWAP_WB_BATCH);
>> if (shrunk == -ENOENT)
>> return 0;
>>
>> s->attempts++;
>> if (shrunk <= 0 && ++s->failures == MAX_RECLAIM_RETRIES)
>> s->stop = true;
>
> Do we need 'stop' or can we just return a value here to indicate that
> we should stop (e.g. -EBUSY)?
>
Perhaps we could return -EAGAIN instead of -EBUSY? This would align with
the semantics of the memory.reclaim interface, which returns -EAGAIN
when it reclaims fewer bytes than requested.
>>
>> return shrunk;
>> }
>>
>> static void shrink_worker(struct work_struct *w)
>> {
>> struct zswap_shrink_state s = {};
>> unsigned long thr;
>>
>> /* Reclaim down to the accept threshold */
>> thr = zswap_accept_thr_pages();
>>
>> while (zswap_total_pages() > thr) {
>> struct mem_cgroup *memcg;
>>
>> cond_resched();
>>
>> memcg = zswap_iter_global();
>> if (!memcg) {
>> if (zswap_shrink_no_candidate(&s))
>> break;
>> continue;
>> }
>>
>> zswap_shrink_one(memcg, &s);
>> /* Drop the extra reference taken by the iterator. */
>> mem_cgroup_put(memcg);
>> if (s.stop)
>> break;
>> }
>> }
>
> I think splitting the shrink/retry logic over 2 functions makes it
> more difficult to follow, so yeah I think fold
> zswap_shrink_no_candidate() into zswap_shrink_one(). Then the callers
> only need to iterate memcgs (depending on the context) and call
> zswap_shrink_one() for each of them.
So, something like this?
/* Track progress of a memcg-tree writeback walk. */
struct zswap_shrink_state {
int attempts;
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 -EAGAIN to signal the caller to abort the walk
* after encountering the following conditions 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 -EAGAIN
* once the retry budget is exhausted and the caller should abort the walk.
*/
static long zswap_shrink_one(struct mem_cgroup *memcg,
struct zswap_shrink_state *s)
{
long shrunk;
/*
* If the iterator has completed a full pass, update the shrink state
* and check whether we should keep going.
*/
if (!memcg) {
/*
* Continue shrinking without incrementing failures if we found
* candidate memcgs in the last tree walk.
*/
if (!s->attempts && ++s->failures == MAX_RECLAIM_RETRIES)
return -EAGAIN;
s->attempts = 0;
return 0;
}
shrunk = shrink_memcg(memcg, NR_ZSWAP_WB_BATCH);
/*
* 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 (shrunk == -ENOENT)
return 0;
s->attempts++;
if (shrunk <= 0 && ++s->failures == MAX_RECLAIM_RETRIES)
return -EAGAIN;
return shrunk;
}
static void shrink_worker(struct work_struct *w)
{
struct zswap_shrink_state s = {};
unsigned long thr;
/* Reclaim down to the accept threshold */
thr = zswap_accept_thr_pages();
while (zswap_total_pages() > thr) {
struct mem_cgroup *memcg;
long ret;
cond_resched();
memcg = zswap_iter_global();
ret = zswap_shrink_one(memcg, &s);
/* drop the extra reference taken by zswap_iter_global() */
mem_cgroup_put(memcg);
if (ret == -EAGAIN)
break;
}
}
next prev parent reply other threads:[~2026-06-25 11:28 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 4:48 [PATCH v4 0/5] mm/zswap: Implement per-cgroup proactive writeback Hao Jia
2026-06-18 4:48 ` [PATCH v4 1/5] mm/zswap: Extend shrink_memcg() writeback capability Hao Jia
2026-06-22 23:33 ` Yosry Ahmed
2026-06-23 13:22 ` Hao Jia
2026-06-23 18:17 ` Yosry Ahmed
2026-06-24 11:58 ` Hao Jia
2026-06-24 16:57 ` Yosry Ahmed
2026-06-25 11:31 ` Hao Jia
2026-06-18 4:48 ` [PATCH v4 2/5] mm/zswap: Factor writeback loop out of shrink_worker() Hao Jia
2026-06-22 23:36 ` Yosry Ahmed
2026-06-24 11:55 ` Hao Jia
2026-06-24 17:00 ` Yosry Ahmed
2026-06-25 11:28 ` Hao Jia [this message]
2026-06-25 17:59 ` Yosry Ahmed
2026-06-18 4:48 ` [PATCH v4 3/5] mm/zswap: Implement proactive writeback Hao Jia
2026-06-22 23:40 ` Yosry Ahmed
2026-06-18 4:48 ` [PATCH v4 4/5] mm/zswap: Add per-memcg stat for " Hao Jia
2026-06-22 23:42 ` Yosry Ahmed
2026-06-18 4:48 ` [PATCH v4 5/5] selftests/cgroup: Add tests for zswap " Hao Jia
2026-06-21 4:20 ` [PATCH v4 0/5] mm/zswap: Implement per-cgroup " Muchun Song
2026-06-22 6:08 ` Hao Jia
2026-06-22 10:04 ` Youngjun Park
2026-06-22 21:29 ` Yosry Ahmed
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=91297bc0-268c-e9c2-57ae-6066eee5df2f@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