From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out30-112.freemail.mail.aliyun.com (out30-112.freemail.mail.aliyun.com [115.124.30.112]) (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 D7B212571B8 for ; Wed, 19 Aug 2026 02:15:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.112 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787105719; cv=none; b=NqzfJN1YgOOv+z6lNLJVXG4/qdZEdmTfUxwLYdwjw5i2EqC8Gnb2Dffc/iWr6lCmLqZRajv5ScLoGT+7ctunn3+NSR5DaDcjD0S7w0iRpXoYJXnz15IgPla97dUxz/YqxksYbqh4O+V76uW4/FelImqDwoOVm3Me1Ym+/RobJx0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787105719; c=relaxed/simple; bh=TUFlNwdVtf/2cKKUfwuI4OdKKT/VRVBp2QMLCS2beC8=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=cvW7VZfLuxpyw9g/ye5t37cr20d0qqH2NoR5WuQQ1kHWtwMUwluBdtyjW+kuWS2EJjXXuWpMsfSgyXB0vtC7vE5kvjWuJO38rDvUM+2uExz5tfV5eeoKB6zEii91kZyqF2zmh/9oMXvHtuIO8+F/+FisAf4JxOJHo7WuI7gYKz0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=FWcUsZv5; arc=none smtp.client-ip=115.124.30.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="FWcUsZv5" DKIM-Signature:v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1787105706; h=Message-ID:Date:MIME-Version:Subject:To:From:Content-Type; bh=02UHFtSIN6JDJ4bj3MePIt9/xxUXCOrrST878CoL+Xw=; b=FWcUsZv5mSW+zQfhgmkXo32mAubKm6+7iMwLPcxBMX0K79MHJH1IMX/sJtr3QTIXrikws8Q7UaWs4fGv2plM/1BAd7IeBphyW5Hl5JsfzaVXbp/zr1IKzVnXzk0YC1Rh2YLaKzo/adCTtO5BDO9UyLFWDJ/iihfL/efWM1c3m28= X-Alimail-AntiSpam:AC=PASS;BC=-1|-1;BR=01201311R941e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033045098064;MF=baolin.wang@linux.alibaba.com;NM=1;PH=DS;RN=16;SR=0;TI=SMTPD_---0X9F2Zqi_1787105704; Received: from 30.74.144.121(mailfrom:baolin.wang@linux.alibaba.com fp:SMTPD_---0X9F2Zqi_1787105704 cluster:ay36) by smtp.aliyun-inc.com; Wed, 19 Aug 2026 10:15:05 +0800 Message-ID: <39871dbf-25e3-4518-9942-a733dbb6acf5@linux.alibaba.com> Date: Wed, 19 Aug 2026 10:15:03 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH mm-unstable v3 2/2] mm/vmscan: apply too_many_isolated() throttling to MGLRU eviction To: Barry Song , Hui Zhu Cc: Andrew Morton , Kairui Song , Qi Zheng , Shakeel Butt , Axel Rasmussen , Yuanchu Xie , Wei Xu , Johannes Weiner , David Hildenbrand , Michal Hocko , Lorenzo Stoakes , linux-mm@kvack.org, linux-kernel@vger.kernel.org, Hui Zhu References: <4b4d4e3065e36f1b60dd69e8276cb92082f393a6.1787056208.git.zhuhui@kylinos.cn> From: Baolin Wang In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 8/19/26 6:06 AM, Barry Song wrote: > On Tue, Aug 18, 2026 at 8:49 PM Hui Zhu wrote: >> >> From: Hui Zhu >> >> The legacy path throttles direct reclaim in shrink_inactive_list() >> when too many isolated folios pile up, but MGLRU's evict_folios() >> isolates folios without this check, which can lead to unnecessary >> swapping, thrashing and OOM. >> >> With the NR_ISOLATED counters now updated in evict_folios(), extract >> the throttling loop from shrink_inactive_list() into >> throttle_is_throttled() and reuse it in evict_folios(). Since the >> type to isolate is unknown until isolation and isolate_folios() may >> fall back to the other type, check all evictable types with >> for_each_evictable_type() and throttle if any of them has too many >> isolated folios. >> > > I feel this is unlikely to work. MGLRU behaves quite differently from the > active/inactive LRU, and its `NR_INACTIVE_FILE` accounting is also very > different. > > With the active/inactive LRU, shrink_inactive_list() ensures that we > always have an inactive list with pages available for reclaim. With MGLRU, > however, a generation can legitimately point to an empty list, so this > assumption does not hold. > > try_to_inc_min_seq: > > /* see the comment on lru_gen_folio */ > if (swappiness && swappiness <= MAX_SWAPPINESS) { > unsigned long seq = lrugen->max_seq - MIN_NR_GENS; > > if (min_seq[LRU_GEN_ANON] > seq && min_seq[LRU_GEN_FILE] < seq) > min_seq[LRU_GEN_ANON] = seq; > else if (min_seq[LRU_GEN_FILE] > seq && > min_seq[LRU_GEN_ANON] < seq) > min_seq[LRU_GEN_FILE] = seq; > } > > At that point, we have no inactive pages for the type, so the > throttle will take effect when the following condition is true: > > too_many = isolated > inactive; > > With MGLRU, however, we can still fall back to the other type even > when there are no inactive pages for the current type. Yes, that's a valid concern. So I think we can check the isolation of both types for MGLRU to avoid this case: static bool check_need_throttle() { bool need_throttle = true; for_each_evictable_type(i, swappiness) { if (!too_many_isolated(pgdat, i, sc)) need_throttle = false; } return need_throttle; } In evict_folios(): ...... while (unlikely(check_need_throttle())) { if (stalled) return 0; /* wait a bit for the reclaimer. */ stalled = true; reclaim_throttle(pgdat, VMSCAN_THROTTLE_ISOLATED); /* We are about to die and free our memory. Return now. */ if (fatal_signal_pending(current)) return SWAP_CLUSTER_MAX; } > BTW, if we are hitting isolated > inactive with MGLRU, it probably > means the generations are quite imbalanced—we are running out of > reclaimable generations. In that case, we may actually want > reclamation to proceed with aging instead. The typical 'isolated > inactive' case is that we've tried our best with aging, but cold pages production can't keep up with isolation speed, especially under concurrent reclaim from multiple processes. In this case, I think throttling is reasonable. >> If a fatal signal is pending, fake reclaim progress the same way the >> legacy path does, so the dying task exits reclaim quickly instead of >> being held in the throttle. >> >> Signed-off-by: Hui Zhu >> --- >> mm/vmscan.c | 71 ++++++++++++++++++++++++++++++++++++++++++++--------- >> 1 file changed, 59 insertions(+), 12 deletions(-) >> >> diff --git a/mm/vmscan.c b/mm/vmscan.c >> index 98226bb021f3..6fe8824430ac 100644 >> --- a/mm/vmscan.c >> +++ b/mm/vmscan.c >> @@ -1819,7 +1819,7 @@ bool folio_isolate_lru(struct folio *folio) >> * the LRU list will go small and be scanned faster than necessary, leading to >> * unnecessary swapping, thrashing and OOM. >> */ >> -static bool too_many_isolated(struct pglist_data *pgdat, int file, >> +static bool too_many_isolated(struct pglist_data *pgdat, bool file, >> struct scan_control *sc) >> { >> unsigned long inactive, isolated; >> @@ -1856,6 +1856,37 @@ static bool too_many_isolated(struct pglist_data *pgdat, int file, >> return too_many; >> } >> >> +/* >> + * Throttle reclaim if too many isolated folios are piling up. If this makes >> + * no progress, the caller is probably looping on unevictable folios, so give >> + * up. Returns true to tell the caller to stop reclaiming, and sets @fatal >> + * if the task received a fatal signal while waiting, so that the caller can >> + * bail out faster. >> + */ >> +static bool throttle_is_throttled(struct pglist_data *pgdat, bool file, >> + struct scan_control *sc, bool *fatal) >> +{ >> + bool stalled = false; >> + >> + *fatal = false; > > TBH, I find the name quite weird :-) Yes, that is not what I meant. :) What I mean is to use a readable variable to return instead of 'true' or 'false': static bool throttle_isolated(struct pglist_data *pgdat, bool file, struct scan_control *sc, bool *fatal) { bool stalled = false; *fatal = false; while (unlikely(too_many_isolated(pgdat, file, sc))) { if (stalled) return stalled; /* wait a bit for the reclaimer. */ stalled = true; reclaim_throttle(pgdat, VMSCAN_THROTTLE_ISOLATED); /* We are about to die and free our memory. Return now. */ if (fatal_signal_pending(current)) { *fatal = true; return stalled; } } return stalled; }