From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5D3D939AD34 for ; Thu, 23 Jul 2026 04:58:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784782702; cv=none; b=WX5qxMZy6Zt98cm/l+3lCE+sJOeSHrFvoSqPz38accBsu0fZodzc/Tds2NFh8PyL2rA3cGeIH0ejRrAOyAlcyj8EB8iYRhnrHzsrng8kRjPeQTwj6KAibK9ioL5Sp/HM45Pudc69dxFUpTKIvyIFmCybqRtVqmA3ILHMrJVwsZQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784782702; c=relaxed/simple; bh=4SIdt8gcZYgmAjPe1iTh2g2VN+Fc4FTcz5r0cjppUaU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=nVzVANXAUaNFIxOyLDzuFpu1Pqg3heb5+r2TcOme6uNN5i2805qi40FYhSYRVKVYXGTaWv+PTP72uIbPUTgtkyFp8ulr28DnioVS0tDlrPRmet577AoAiDRE89b9EvIGtdMuJKhr6xynWt7RIjsUEllsUOzUI1X+ALVtPGAkSus= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=iKpDd6OM; arc=none smtp.client-ip=91.218.175.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="iKpDd6OM" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1784782691; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tFTqvoKbwMWTXDnYGsKcqBttpTGihYLNyhVUcDk1sMs=; b=iKpDd6OMt2Ad+zyPxrYsQASJgE94Gpi9OqU2Wzp2irDu8KbfmMKkwyX1FwDdqBYjwZ2mMK 65qfiTc2sYQEQ1O/U+f9ijSBssMYOzcrY1SjrQChaE7OQxnWfC9RagIDCFGJebJ5PW6VZF omyQRZser7Eyngef9o0vXHPwKFTAQnA= From: Ridong To: Andrew Morton , Johannes Weiner Cc: David Hildenbrand , Michal Hocko , Qi Zheng , Shakeel Butt , Lorenzo Stoakes , Kairui Song , Barry Song , Axel Rasmussen , Yuanchu Xie , Wei Xu , Zhongkun He , Muchun Song , Davidlohr Bueso , Roman Gushchin , linux-mm@kvack.org, linux-kernel@vger.kernel.org, Ridong Chen , Ridong Chen Subject: [PATCH v3 4/4] mm/mglru: fix anon-only reclaim evicting file pages when swappiness=max Date: Thu, 23 Jul 2026 12:57:18 +0800 Message-Id: <20260723045718.2052070-5-ridong.chen@linux.dev> In-Reply-To: <20260723045718.2052070-1-ridong.chen@linux.dev> References: <20260723045718.2052070-1-ridong.chen@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT From: Ridong Chen The previous patch fixed this issue for the traditional LRU. The same problem exists in MGLRU [1]: when swappiness=max (SWAPPINESS_ANON_ONLY) is set, reclaim is expected to evict anonymous pages exclusively, but file pages can still be reclaimed when anonymous pages cannot be reclaimed (e.g. no swap and no demotion target). With SWAPPINESS_ANON_ONLY, get_type_to_scan() always returns LRU_GEN_ANON and for_each_evictable_type() only iterates the anon type. But if get_nr_to_scan() does not bail out, evict_folios() still runs and isolate_folios() falls back to scanning file pages in the !scanned case: shrink_one try_to_shrink_lruvec get_swappiness // returns SWAPPINESS_ANON_ONLY for swappiness=max get_nr_to_scan evict_folios isolate_folios // falls back to file type when !scanned This wrongly evicts file pages, violating the anon-only semantics. Fix it the same way as the traditional LRU: keep returning SWAPPINESS_ANON_ONLY in get_swappiness(), and return 0 from get_nr_to_scan() when SWAPPINESS_ANON_ONLY is set but anon pages cannot be reclaimed. This protects file pages from being reclaimed, and as a side effect avoids the useless scan work. The test result: Before fix: # cat /sys/kernel/mm/lru_gen/enabled 0x0007 # cat memory.stat anon 204800 file 67108864 ... pgsteal_proactive 0 pgscan_proactive 0 # echo "64M swappiness=max" > memory.reclaim # cat memory.stat anon 208896 file 0 ... pgsteal_proactive 16384 pgscan_proactive 16384 After fix: # cat memory.stat anon 188416 file 67215360 kernel 1970176 ... pgsteal_proactive 0 pgscan_proactive 0 # echo "64M swappiness=max" > memory.reclaim -bash: echo: write error: Resource temporarily unavailable # cat memory.stat anon 204800 file 67215360 ... pgsteal_proactive 0 pgscan_proactive 0 [1] https://sashiko.dev/#/patchset/20260717113300.214717-1-ridong.chen@linux.dev Fixes: 68a1436bde00 ("mm: add swappiness=max arg to memory.reclaim for only anon reclaim") Acked-by: Qi Zheng Signed-off-by: Ridong Chen --- mm/vmscan.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 859655fcf60d..20cb93fd3da8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2708,6 +2708,10 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) { struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); + int swappiness = sc_swappiness(sc, memcg); + + if (swappiness == SWAPPINESS_ANON_ONLY) + return swappiness; if (!sc->may_swap) return 0; @@ -2716,7 +2720,7 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) return 0; - return sc_swappiness(sc, memcg); + return swappiness; } static int get_nr_gens(struct lruvec *lruvec, int type) @@ -4921,6 +4925,19 @@ static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, struct mem_cgroup *memcg, int swappiness) { unsigned long nr_to_scan, evictable; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + /* + * Proactive reclaim initiated by userspace for anonymous memory only. + * SWAPPINESS_ANON_ONLY is set only on the proactive reclaim path, so + * warn if it shows up elsewhere. When anon cannot be reclaimed (e.g. + * no swap), return 0 instead of falling through and evicting file + * pages, which would violate the anon-only semantics. + */ + if (swappiness == SWAPPINESS_ANON_ONLY && + !can_reclaim_anon_pages(memcg, pgdat->node_id, sc)) { + WARN_ON_ONCE(!sc->proactive); + return 0; + } evictable = lruvec_evictable_size(lruvec, swappiness); -- 2.34.1