Re: [PATCH v4] mm/memcg: clear folio memcg after changing per memcg stats

From: Kairui Song

Date: Tue Sep 08 2026 - 03:38:45 EST


On Sun, Sep 6, 2026 at 3:34 AM Bingfang Guo via B4 Relay
<devnull+bingfangguo.tencent.com@xxxxxxxxxx> wrote:
>
> From: Bingfang Guo <bingfangguo@xxxxxxxxxxx>
>
> I notice extremely high swapcached count in the per memcg level
> memory.stat when running tests with cgroupv1 setup by swapping pages in
> and out. It seems that the counter never gets decreased so the value is
> rather useless and confusing to users reading it. So I think fixing it
> so that the value can reflect the actual swapcache usage correctly could
> be helpful.
>
> __memcg1_swapout() transfers the memsw charge of a folio to its swap
> entry and clears folio->memcg_data as part of that. In the vmscan
> swapout path it runs before __swap_cache_del_folio(), which then
> decrements the swapcache stats through lruvec_stat_mod_folio(). Since
> folio->memcg_data has already been cleared, folio_memcg() returns NULL
> and the NR_SWAPCACHE decrement only updates the node-level counter
> instead of the memcg's lruvec, leaking the per-memcg swapcache count.
>
> Move the __memcg1_swapout() call into __swap_cache_del_folio(), after
> the NR_FILE_PAGES and NR_SWAPCACHE updates but before
> __swap_cache_do_del_folio() removes the folio from the swap cache. This
> keeps the stats attributed to the folio's memcg while still recording
> the swap cgroup with a valid folio->swap. Add a swapout parameter so
> the plain swap_cache_del_folio() path is left unchanged.
>
> Fixes: 2732acda82c9 ("mm, swap: use swap cache as the swap in synchronize layer")
> Signed-off-by: Bingfang Guo <bingfangguo@xxxxxxxxxxx>
> ---

...

> diff --git a/mm/swap_state.c b/mm/swap_state.c
> index 305877e1f4d7..38916ea96ac5 100644
> --- a/mm/swap_state.c
> +++ b/mm/swap_state.c
> @@ -306,21 +306,28 @@ static void __swap_cache_do_del_folio(struct swap_cluster_info *ci,
> * @folio: The folio.
> * @entry: The first swap entry that the folio corresponds to.
> * @shadow: shadow value to be filled in the swap cache.
> + * @swapout: whether this operation swaps out the folio.

This reads a bit strange, I think you mean "whether this folio is
being reclaimed after swapout".

> *
> * Removes a folio from the swap cache and fills a shadow in place.
> * This won't put the folio's refcount. The caller has to do that.
> *
> * Context: Caller must ensure the folio is locked and in the swap cache
> * using the index of @entry, and lock the cluster that holds the entries.
> + * If @swapout is set, the folio should be in reclaim path and IRQs
> + * should be disabled.
> */
> void __swap_cache_del_folio(struct swap_cluster_info *ci, struct folio *folio,
> - swp_entry_t entry, void *shadow)
> + swp_entry_t entry, void *shadow, bool swapout)
> {
> unsigned long nr_pages = folio_nr_pages(folio);
>
> - __swap_cache_do_del_folio(ci, folio, entry, shadow);
> node_stat_mod_folio(folio, NR_FILE_PAGES, -nr_pages);
> lruvec_stat_mod_folio(folio, NR_SWAPCACHE, -nr_pages);
> +
> + if (swapout)
> + __memcg1_swapout(folio, ci);
> +
> + __swap_cache_do_del_folio(ci, folio, entry, shadow);
> }
>
> /**
> @@ -339,7 +346,7 @@ void swap_cache_del_folio(struct folio *folio)
> swp_entry_t entry = folio->swap;
>
> ci = swap_cluster_lock(__swap_entry_to_info(entry), swp_offset(entry));
> - __swap_cache_del_folio(ci, folio, entry, NULL);
> + __swap_cache_del_folio(ci, folio, entry, NULL, false);
> swap_cluster_unlock(ci);
>
> folio_ref_sub(folio, folio_nr_pages(folio));
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 245f68c75b28..29bced43b0ce 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -755,8 +755,7 @@ static int __remove_mapping(struct address_space *mapping, struct folio *folio,
>
> if (reclaimed && !mapping_exiting(mapping))
> shadow = workingset_eviction(folio, target_memcg);
> - __memcg1_swapout(folio, ci);
> - __swap_cache_del_folio(ci, folio, swap, shadow);
> + __swap_cache_del_folio(ci, folio, swap, shadow, true);
> swap_cluster_unlock_irq(ci);
> } else {
> void (*free_folio)(struct folio *);
>
> ---
> base-commit: b5529903123d9535bcf74386c1f4e185e8632dd9
> change-id: 20260828-memcg-swapcache-stats-fix-1beef3dc3afb
>
> Best regards,
> --
> Bingfang Guo <bingfangguo@xxxxxxxxxxx>
>

Other than that this looks good!

Acked-by: Kairui Song <kasong@xxxxxxxxxxx>