From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mta0.migadu.com (out-54.mta0.migadu.com [91.218.175.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D10E2DD5F6 for ; Thu, 20 Aug 2026 07:27:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.54 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787210829; cv=none; b=dMy2RmowNgojujTqbmlQN0VhEkFJ8C7sFrlLjL3ibPGP6xaZ5++KMZ1jTMAL4bJ9+PvDegXouypfTM8DLGFetqJDTHFRXHS+l70aXEDPmodme9c/FPQ2PL0JQGQRBlVhjv8uZRpFu/WPDi1L7x50j20qVzdNAfK9RkT4a54/oQo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787210829; c=relaxed/simple; bh=T3OdxQvA2mkiYGw37MprnKiKHzYt+s6q7FUUCqndvrI=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=dP1bdGQc/wkMS2h6JAf98wYVv+D3IjIMhJt1GjPuuS4TIoQvrBQ06L2eiVsbnvjn6530keVGFoFwrddAgkn1N36Eo9F1f0ql6g8BxW2DPoOoTp+BBNkUD3FxUtRT7cL8rzChwTgOoTybY3a99M52VqcQIgJ2gDob22PSWEWYj2s= 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=bA5LTkh0; arc=none smtp.client-ip=91.218.175.54 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="bA5LTkh0" X-Envelope-To: linux-kernel@vger.kernel.org DKIM-Signature: a=rsa-sha256; bh=T3OdxQvA2mkiYGw37MprnKiKHzYt+s6q7FUUCqndvrI=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1787210825; v=1; x=1787815625; b=bA5LTkh0J4EqhI25SNNg0dAx2Ho2Dg7Vy/RwhX+hSo1BeJcuTy8y4f0lmRg4dmaC2Hq8udOB shw4o19TlzRkE1tdPnWNsIo7cXp8KL2SFLU0yRiC/aMkL/Ow/9LusnLQgrG+N1V+3TIYXIWHFOP 5ctFeDRqlKCFgwdRKrovqBgg= X-Envelope-To: linux-kernel@vger.kernel.org Received: from mi-ThinkCentre-M760t.mioffice.cn (14.29.108.92) by smtp.migadu.com with ESMTPS id 5b40ec1e6038cfe3; Thu, 20 Aug 2026 07:27:05 +0000 X-Mizu-Trace-ID: 5b40ec1e6038cfe3 X-Migadu-Flow: FLOW_OUT From: Ridong Chen 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 , Steven Barrett , "Jan Alexander Steffens (heftig)" , Yu Zhao , Oleksandr Natalenko , linux-mm@kvack.org, linux-kernel@vger.kernel.org, Ridong Chen , Ridong Chen Subject: [PATCH] mm/mglru: preserve inactive placement when enabling MGLRU Date: Thu, 20 Aug 2026 15:26:41 +0800 Message-Id: <20260820072641.253591-1-ridong.chen@linux.dev> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Ridong Chen When the LRU is switched to MGLRU (echo y > /sys/kernel/mm/lru_gen/ enabled), fill_evictable() re-inserts every folio via lru_gen_add_folio(..., false). With reclaiming hardcoded to false, an inactive anonymous folio (no PG_active, not in the swapcache) takes the "gen = MIN_NR_GENS" branch in lru_gen_folio_seq() and is seeded at seq = max_seq - 1, which lru_gen_is_active() treats as active. Its inactive placement is lost and NR_INACTIVE_ANON is folded into NR_ACTIVE_ANON. Pass reclaiming=!active so a folio from an inactive list is seeded into an older generation. Folios from the active list carry PG_active and hit the first branch either way, so they are unchanged. reclaiming also selects the insertion end in lru_gen_add_folio(): list_add_tail() for inactive folios, list_add() for active ones. Both the legacy LRU and a MGLRU generation keep the hottest folios at the head and the coldest at the tail, and reclaim takes from the tail. To preserve that order the folio must be taken from the end matching the insertion end, so take inactive folios from the head and active folios from the tail; otherwise hot/cold would be reversed within the generation. Tested on x86_64, next-20260812, 2G VM + 1G swap, ~1.5G anon pushed onto the inactive list before enabling MGLRU: Active(anon) Inactive(anon) before switch (legacy) 2952 1548792 kB after `echo y`, unpatched 1552052 0 kB after `echo y`, patched 15144 1536636 kB Inactive file folios stay inactive either way (NR_INACTIVE_FILE is preserved). Fixes: 354ed5974429 ("mm: multi-gen LRU: kill switch") Suggested-by: Barry Song Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ridong Chen --- mm/vmscan.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 94fc4f25e99f..7be4cec9a838 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -5311,7 +5311,23 @@ static bool fill_evictable(struct lruvec *lruvec) while (!list_empty(head)) { bool success; - struct folio *folio = lru_to_folio(head); + struct folio *folio; + + /* + * Both the legacy LRU and a MGLRU generation keep the + * hottest folios at the head and the coldest at the + * tail, and reclaim takes from the tail. To preserve + * that order, the end we take from must match the end + * lru_gen_add_folio() inserts at: inactive folios use + * reclaiming=true (list_add_tail), so take from the + * head; active folios use reclaiming=false (list_add), + * so take from the tail. Taking from the wrong end + * would reverse hot/cold within the generation. + */ + if (active) + folio = lru_to_folio(head); + else + folio = list_first_entry(head, struct folio, lru); VM_WARN_ON_ONCE_FOLIO(folio_test_unevictable(folio), folio); VM_WARN_ON_ONCE_FOLIO(folio_test_active(folio) != active, folio); @@ -5319,7 +5335,16 @@ static bool fill_evictable(struct lruvec *lruvec) VM_WARN_ON_ONCE_FOLIO(folio_lru_gen(folio) != -1, folio); lruvec_del_folio(lruvec, folio); - success = lru_gen_add_folio(lruvec, folio, false); + /* + * With reclaiming=false, lru_gen_folio_seq() would seed + * an inactive folio near max_seq, which + * lru_gen_is_active() reports as active, so its inactive + * placement would be lost. Pass reclaiming=!active to + * seed it into the oldest generation instead. This + * reuses reclaiming beyond its folio_rotate_reclaimable() + * meaning; it also picks list_add_tail() above. + */ + success = lru_gen_add_folio(lruvec, folio, !active); VM_WARN_ON_ONCE(!success); if (!--remaining) -- 2.34.1