Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Jiayuan Chen" <jiayuan.chen@linux.dev>, linux-mm@kvack.org
Cc: "Johannes Weiner" <hannes@cmpxchg.org>,
	"Michal Hocko" <mhocko@kernel.org>,
	"Roman Gushchin" <roman.gushchin@linux.dev>,
	"Shakeel Butt" <shakeel.butt@linux.dev>,
	"Muchun Song" <muchun.song@linux.dev>,
	"Yosry Ahmed" <yosry@kernel.org>, "Nhat Pham" <nphamcs@gmail.com>,
	"Chengming Zhou" <chengming.zhou@linux.dev>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Chris Li" <chrisl@kernel.org>,
	"Kairui Song" <kasong@tencent.com>,
	"Kemeng Shi" <shikemeng@huaweicloud.com>,
	"Baoquan He" <baoquan.he@linux.dev>,
	"Barry Song" <baohua@kernel.org>,
	"Youngjun Park" <youngjun.park@lge.com>,
	"David Hildenbrand" <david@kernel.org>,
	"Qi Zheng" <qi.zheng@linux.dev>,
	"Lorenzo Stoakes" <ljs@kernel.org>,
	"Axel Rasmussen" <axelrasmussen@google.com>,
	"Yuanchu Xie" <yuanchu@google.com>, "Wei Xu" <weixugc@google.com>,
	"Baolin Wang" <baolin.wang@linux.alibaba.com>,
	tj@kernel.org, mkoutny@suse.com
Subject: Re: [PATCH mm-new v1 2/2] mm: vmscan: skip anon folios zswap would refuse when writeback is off
Date: Sat, 31 Oct 2026 09:53:12 +0000	[thread overview]
Message-ID: <sashiko-outbox-191879@kernel.org> (raw)
In-Reply-To: <20261030095223.325309-3-jiayuan.chen@linux.dev>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] mm: vmscan: unmapped swapcache folios bypass swap_writeout_blocked()
- [Medium] mm: vmscan: large and split head folios bypass swap_writeout_blocked()
--

commit 6d6f21b971f8e3a837e970c969d5f1fdbeb97cbe
Author: Jiayuan Chen <jiayuan.chen@linux.dev>

mm: vmscan: skip anon folios zswap would refuse when writeback is off

This commit adds swap_writeout_blocked() and zswap_store_blocked() to detect
when a memcg with memory.zswap.writeback=0 cannot store pages in zswap. In
shrink_folio_list(), non-zero-filled anonymous folios are activated early
before allocating swap slots and unmapping them when swap writeout is
blocked.

> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 7ddef3b488b3d..591a98cd9ef59 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -1169,6 +1169,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
>  	unsigned int nr_reclaimed = 0, nr_demoted = 0;
>  	unsigned int pgactivate = 0;
>  	bool do_demote_pass;
> +	int swap_blocked = -1;
>  	struct swap_io_ctx ctx = {};
>  
>  	folio_batch_init(&free_folios);
> @@ -1355,6 +1356,22 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
>  			continue;
>  		}
>  
> +		/*
> +		 * swap_writeout() would only activate this folio. Do that now,
> +		 * before it costs a swap slot and an unmap. Zero-filled folios
> +		 * are marked in the swap table without a store, an unmapped one
> +		 * may only need its stale slot dropped and a large one may still
> +		 * be split, let them go on.
> +		 */
> +		if (folio_test_anon(folio) && folio_test_swapbacked(folio) &&
> +		    folio_mapped(folio) && !folio_test_large(folio) &&
> +		    (!folio_test_swapcache(folio) || folio_test_dirty(folio))) {
> +			if (swap_blocked < 0)
> +				swap_blocked = swap_writeout_blocked(memcg);
> +			if (swap_blocked && !is_folio_zero_filled(folio))
> +				goto activate_locked;
> +		}

[Severity: Medium]
Does requiring folio_mapped(folio) allow unmapped dirty swap-cache folios
with active swap PTEs to bypass this check on subsequent reclaim passes?

When try_to_unmap() unmaps an anonymous folio during reclaim,
try_to_unmap_one() installs non-present swap PTEs via folio_dup_swap() and
removes the present PTEs. Once swap_writeout() rejects the folio with
AOP_WRITEPAGE_ACTIVATE (for example, when a clean swap-cache folio had a
dirty PTE settled by unmap, or when a folio was in the batch as zswap
became full), the folio stays in the swap cache marked dirty with
folio_mapped(folio) == false and folio_maybe_swapped(folio) == true.

If userspace does not fault the cold folio back in, folio_mapped(folio)
remains false on every subsequent pass through shrink_folio_list(), so the
folio skips this check and enters pageout() -> swap_writeout():

mm/page_io.c:swap_writeout() {
    if (folio_free_swap(folio))
        goto out_unlock;
    if (is_folio_zero_filled(folio)) {
        ...
    }
    swap_zeromap_folio_clear(folio);
    if (zswap_store(folio)) {
        ...
    }
    if (!mem_cgroup_zswap_writeback_enabled(folio_memcg(folio)))
        return AOP_WRITEPAGE_ACTIVATE;
}

Because folio_free_swap() checks folio_maybe_swapped(folio), it returns
false when swap PTEs still reference the slot:

mm/swapfile.c:folio_free_swap() {
    if (!folio_swapcache_freeable(folio))
        return false;
    if (folio_maybe_swapped(folio))
        return false;
    ...
}

Wouldn't those unmapped swap-cache folios repeatedly run
is_folio_zero_filled(), swap_zeromap_folio_clear(), and zswap_store() on
every reclaim cycle instead of being activated early?

[Severity: Medium]
How does !folio_test_large(folio) interact with CONFIG_THP_SWAP and with
the head folio left behind by split_folio_to_list()?

First, when CONFIG_THP_SWAP is enabled, a normal fully-mapped large
anonymous folio is not split before folio_alloc_swap():

mm/vmscan.c:shrink_folio_list() {
    if (folio_test_large(folio)) {
        if (folio_expected_ref_count(folio) !=
            folio_ref_count(folio) - 1)
            goto activate_locked;
        if (data_race(!list_empty(&folio->_deferred_list) &&
            folio_test_partially_mapped(folio)) &&
            split_folio_to_list(folio, folio_list))
            goto activate_locked;
    }
    ret = folio_alloc_swap(folio);
}

When folio_alloc_swap() succeeds for the large folio without returning
-E2BIG, the entire large folio is unmapped by try_to_unmap() and rejected
in swap_writeout() with AOP_WRITEPAGE_ACTIVATE, and remains a large folio
on subsequent passes.

Second, even when split_folio_to_list(folio, folio_list) splits a large
folio (either for a partially-mapped folio on _deferred_list or when
folio_alloc_swap() returns -E2BIG), only the tail pages are queued onto
folio_list to re-enter the loop. The head folio (now order-0) continues
directly to folio_alloc_swap(folio) and try_to_unmap() in the current
iteration without passing through the swap_writeout_blocked() check.

Should large folios and split head folios also be checked against
swap_writeout_blocked() before allocating swap and unmapping?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261030095223.325309-1-jiayuan.chen@linux.dev?part=2


      parent reply	other threads:[~2026-10-31  9:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30  9:52 [PATCH mm-new v1 0/2] mm: vmscan: skip anon folios zswap would refuse when writeback is off Jiayuan Chen
2026-10-30  9:52 ` [PATCH mm-new v1 1/2] mm: memcontrol: split mem_cgroup_may_zswap() out of obj_cgroup_may_zswap() Jiayuan Chen
2026-10-30  9:52 ` [PATCH mm-new v1 2/2] mm: vmscan: skip anon folios zswap would refuse when writeback is off Jiayuan Chen
2026-10-30 17:52   ` Yosry Ahmed
2026-10-30 19:03     ` Barry Song
2026-10-30 22:32       ` Yosry Ahmed
2026-10-31  9:53   ` sashiko-bot [this message]

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=sashiko-outbox-191879@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=baohua@kernel.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=baoquan.he@linux.dev \
    --cc=chengming.zhou@linux.dev \
    --cc=chrisl@kernel.org \
    --cc=david@kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=jiayuan.chen@linux.dev \
    --cc=kasong@tencent.com \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=mhocko@kernel.org \
    --cc=mkoutny@suse.com \
    --cc=muchun.song@linux.dev \
    --cc=nphamcs@gmail.com \
    --cc=qi.zheng@linux.dev \
    --cc=roman.gushchin@linux.dev \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=shikemeng@huaweicloud.com \
    --cc=tj@kernel.org \
    --cc=weixugc@google.com \
    --cc=yosry@kernel.org \
    --cc=youngjun.park@lge.com \
    --cc=yuanchu@google.com \
    /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