From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794064560; b=5ka1muhXllKG/ke4qPQglTsKTnJZYG429aK1mGsUGYEPHOFql+ingHpzzSSiOtrgTB5W wIOl9YB0E7biYPL7uKYHnVtraUbPgwv5afqSChISHvz8sqBvBOhGJfLMUqwIpO1PbOcZW BsZab4WzumN3obFe9dmPOgtadglVb04vGclh5u0a5XHqG5THvgwAOaNTPk277luR4UDit FCu5f9zcMw4aS99rsOqvh2R7jPpBq8N3+LORoPrFO1HF/1GReeyNfnYNUsvQ1dF/hcxbw YO89t+PjgRRk+ZW/QF65v+r/YlY+fZeYCz2dJLF3lzprkn8A5LiHyaXgE7EZvgVrZxQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794064560; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=tB0sv3O315SfGu9Pj5FPhBjTirpkF7LeNbUm7VKrIMc=; b=e9uXhTlGPNcok2/WLEYH8uEb7QySgAbBsdlbHuoM+zURh1TM0/4P+zdKW16SPWAU/v0I tJUjhuvnrpJf1OE1rkD+gvqqJbxtIYZX9kgdqv0VtpCnyKxfD4kM8H6ud38MSJuSeRZmC X0ifNr+x//nG0zTSgcgeMH3irXATHc9ntdGB8F8f9VyuthhDjTKu8dBbqq2vm1SpfvUF1 p5npeXKGgAXJhvIp+lhIn7UsOnq5B+M5W09AeGvn10VbfwVapkG9JjnhBDaDKLAe8FDQQ uljaVjuUXlgOeOLxeUawfC17zJfGaH82TRjRqJW9ESSGBb390DFOyCXSx5kppQmVGAg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=nNod4p9H; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EBEE4606A32D; Sat, 7 Nov 2026 15:15:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=nNod4p9H Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7B16F1F0089F; Sat, 7 Nov 2026 15:15:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794064559; bh=tB0sv3O315SfGu9Pj5FPhBjTirpkF7LeNbUm7VKrIMc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=nNod4p9Hq4H3BWtZiOyccuEeeaYybFLHEn4//DEqlEglL5uzeyNakeJ7fOU0RmRGG TAOYxOROrLTKIsEnk6GNPAbQGNcf7Mc9FH4cmHB6SfHyrU6NkgvcyWjweXu+Kny5Hz yUwbu3on4EZBvjiIPQJdkKVl3VUVKTnAUMbftMII= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Bingfang Guo , Andrew Morton , Kairui Song , Axel Rasmussen , Baoquan He , Barry Song , Chris Li , David Hildenbrand , Johannes Weiner , Kemeng Shi , Lorenzo Stoakes , Michal Hocko , Nhat Pham , Shakeel Butt , Wei Xu , Yuanchu Xie , Sasha Levin Subject: [PATCH 7.3 0581/1257] mm/memcg: clear folio memcg after changing per memcg stats Date: Sat, 7 Nov 2026 08:47:57 -0500 Message-ID: <20261107134955.400786062@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261107134939.434104957@linuxfoundation.org> References: <20261107134939.434104957@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Bingfang Guo [ Upstream commit 0b1b457ecc4f636d85e1a0fade05f3dee264f59a ] 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. Users using swaps will read totally meaningless swapcache value from per memcg memory.stat, like 200GB of swapcache on a 64GB setup, which is quite confusing and may trigger monitoring alerts, if any. 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. Link: https://lore.kernel.org/20260910-memcg-swapcache-stats-fix-v5-1-033f510ba748@tencent.com Fixes: 2732acda82c9 ("mm, swap: use swap cache as the swap in synchronize layer") Signed-off-by: Bingfang Guo Signed-off-by: Andrew Morton Acked-by: Kairui Song Cc: Axel Rasmussen Cc: Baoquan He Cc: Barry Song Cc: Chris Li Cc: David Hildenbrand Cc: Johannes Weiner Cc: Kemeng Shi Cc: Lorenzo Stoakes Cc: Michal Hocko Cc: Nhat Pham Cc: Shakeel Butt Cc: Wei Xu Cc: Yuanchu Xie Cc: Signed-off-by: Sasha Levin --- mm/swap.h | 6 ++++-- mm/swap_state.c | 13 ++++++++++--- mm/vmscan.c | 3 +-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/mm/swap.h b/mm/swap.h index 90a551a88df63..c9202516b413e 100644 --- a/mm/swap.h +++ b/mm/swap.h @@ -319,7 +319,8 @@ struct folio *swap_cache_alloc_folio(swp_entry_t target_entry, gfp_t gfp_mask, void __swap_cache_add_folio(struct swap_cluster_info *ci, struct folio *folio, swp_entry_t entry); void __swap_cache_del_folio(struct swap_cluster_info *ci, - struct folio *folio, swp_entry_t entry, void *shadow); + struct folio *folio, swp_entry_t entry, void *shadow, + bool swapout); void __swap_cache_replace_folio(struct swap_cluster_info *ci, struct folio *old, struct folio *new); @@ -453,7 +454,8 @@ static inline void swap_cache_del_folio(struct folio *folio) } static inline void __swap_cache_del_folio(struct swap_cluster_info *ci, - struct folio *folio, swp_entry_t entry, void *shadow) + struct folio *folio, swp_entry_t entry, void *shadow, + bool swapout) { } diff --git a/mm/swap_state.c b/mm/swap_state.c index f3961fdd857dc..cb574030b814f 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 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 f11491ee9ed5c..17ab01693ae8d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -735,8 +735,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 *); -- 2.53.0