From nobody Mon Apr 6 15:29:00 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 023A73164AA for ; Thu, 2 Apr 2026 18:53:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775156022; cv=none; b=KSyVr/HQY3hxcI2M45R36f1AbQRpvEpTkpVHKaBKYGNf/A3X7/TuEnNFk8RTNSCpjjJHQD9NuOz9200uY9a+HaNWKMP6MvFlm6BF7CIcvA8wBxO4jjl+9pzjDQD/tJcQXcL6IjeyKUKA6Zd+bN/w+y+Qe4xl+X1f4ZLo1UP2DxE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775156022; c=relaxed/simple; bh=63nEWfwkNNkk9J++qrkxrJVSy188Dx52Qvrtm+1BaGs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mktSJ8S8CjN1WcRGyC8i0GeqCfEV8YUPXiloTXtAAkYLHJ9SxBAC8DvwMluvwLuszHHkzbZk4sHFrdy9nLF4SwxMAck13Fnumlaolsamqt9iLkmpUdnfOgO0ulN18ihnLrtaf0rbMOsLdGrI81rNW7Sw3HudUAlQndOtKuj823w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ASiGTN3V; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ASiGTN3V" Received: by smtp.kernel.org (Postfix) with ESMTPS id D6244C2BCB5; Thu, 2 Apr 2026 18:53:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775156021; bh=63nEWfwkNNkk9J++qrkxrJVSy188Dx52Qvrtm+1BaGs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ASiGTN3V5lLKskHiafX2Q0dnO62ymSFp7sdXqmcdYIkkHkHv+uw7tGvC5QDnUljO5 ktke/cSdCLHwUtMklH0OXxA12xD907BwJtEu1H2dp/qilvY7/Ghp9JWaHyQ8p5NGse 5JemgLRflD+d9u8qfHZ+iWuFheOKmsBeg5uziv/eQoo6oJWXNh2S2RxrlshBLFiQgy 2zAaAVTQmkD+emqmIFoxQdo+VM/yF2BU2Rwy38eeFj91QXa1WMD4jyUDnUeLeJ4Nnx nlEqnicDmX35zHsuUm3m4QQHyaY9iFhCsH4cscY/JiP+tjwg8mZ2FFrhsRuCMhvEQL L1Nj5Pz4/+pPw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8F16D6AAF9; Thu, 2 Apr 2026 18:53:41 +0000 (UTC) From: Kairui Song via B4 Relay Date: Fri, 03 Apr 2026 02:53:36 +0800 Subject: [PATCH v3 10/14] mm/mglru: simplify and improve dirty writeback handling Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260403-mglru-reclaim-v3-10-a285efd6ff91@tencent.com> References: <20260403-mglru-reclaim-v3-0-a285efd6ff91@tencent.com> In-Reply-To: <20260403-mglru-reclaim-v3-0-a285efd6ff91@tencent.com> To: linux-mm@kvack.org Cc: Andrew Morton , Axel Rasmussen , Yuanchu Xie , Wei Xu , Johannes Weiner , David Hildenbrand , Michal Hocko , Qi Zheng , Shakeel Butt , Lorenzo Stoakes , Barry Song , David Stevens , Chen Ridong , Leno Hou , Yafang Shao , Yu Zhao , Zicheng Wang , Kalesh Singh , Suren Baghdasaryan , Chris Li , Vernon Yang , linux-kernel@vger.kernel.org, Qi Zheng , Baolin Wang , Kairui Song X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=ed25519-sha256; t=1775156018; l=4353; i=kasong@tencent.com; s=kasong-sign-tencent; h=from:subject:message-id; bh=hVu3ISonYulOgbgDjpADHQN2QCCwFiXdmGgk/BQPxSU=; b=kkEuh+8AqhlfqE5nr5RrlNP81wjM+EdWclsP/JUJJxh32ldb9EaSVYEdYH+0la/BG+SZlGhMe fp6Kn8c2mXcAzxSGGt/ekc4X+n3yxuXsgAFprbRwFbWETApZovUH9ht X-Developer-Key: i=kasong@tencent.com; a=ed25519; pk=kCdoBuwrYph+KrkJnrr7Sm1pwwhGDdZKcKrqiK8Y1mI= X-Endpoint-Received: by B4 Relay for kasong@tencent.com/kasong-sign-tencent with auth_id=562 X-Original-From: Kairui Song Reply-To: kasong@tencent.com From: Kairui Song Right now the flusher wakeup mechanism for MGLRU is less responsive and unlikely to trigger compared to classical LRU. The classical LRU wakes the flusher if one batch of folios passed to shrink_folio_list is unevictable due to under writeback. MGLRU instead check and handle this after the whole reclaim loop is done. We previously even saw OOM problems due to passive flusher, which were fixed but still not perfect [1]. We have just unified the dirty folio counting and activation routine, now just move the dirty flush into the loop right after shrink_folio_list. This improves the performance a lot for workloads involving heavy writeback and prepares for throttling too. Test with YCSB workloadb showed a major performance improvement: Before this series: Throughput(ops/sec): 62485.02962831822 AverageLatency(us): 500.9746963330107 pgpgin 159347462 workingset_refault_file 34522071 After this commit: Throughput(ops/sec): 80857.08510208207 AverageLatency(us): 386.653262968934 pgpgin 112233121 workingset_refault_file 19516246 The performance is a lot better with significantly lower refault. We also observed similar or higher performance gain for other real-world workloads. We were concerned that the dirty flush could cause more wear for SSD: that should not be the problem here, since the wakeup condition is when the dirty folios have been pushed to the tail of LRU, which indicates that memory pressure is so high that writeback is blocking the workload already. Reviewed-by: Axel Rasmussen Link: https://lore.kernel.org/linux-mm/20241026115714.1437435-1-jingxiangze= ng.cas@gmail.com/ [1] Signed-off-by: Kairui Song --- mm/vmscan.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 2a36cf937061..bd2bf45826de 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -4724,8 +4724,6 @@ static int scan_folios(unsigned long nr_to_scan, stru= ct lruvec *lruvec, trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scanned, skipped, isolated, type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON); - if (type =3D=3D LRU_GEN_FILE) - sc->nr.file_taken +=3D isolated; =20 *isolatedp =3D isolated; return scanned; @@ -4833,12 +4831,27 @@ static int evict_folios(unsigned long nr_to_scan, s= truct lruvec *lruvec, return scanned; retry: reclaimed =3D shrink_folio_list(&list, pgdat, sc, &stat, false, memcg); - sc->nr.unqueued_dirty +=3D stat.nr_unqueued_dirty; sc->nr_reclaimed +=3D reclaimed; trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id, type_scanned, reclaimed, &stat, sc->priority, type ? LRU_INACTIVE_FILE : LRU_INACTIVE_ANON); =20 + /* + * If too many file cache in the coldest generation can't be evicted + * due to being dirty, wake up the flusher. + */ + if (stat.nr_unqueued_dirty =3D=3D isolated) { + wakeup_flusher_threads(WB_REASON_VMSCAN); + + /* + * For cgroupv1 dirty throttling is achieved by waking up + * the kernel flusher here and later waiting on folios + * which are in writeback to finish (see shrink_folio_list()). + */ + if (!writeback_throttling_sane(sc)) + reclaim_throttle(pgdat, VMSCAN_THROTTLE_WRITEBACK); + } + list_for_each_entry_safe_reverse(folio, next, &list, lru) { DEFINE_MIN_SEQ(lruvec); =20 @@ -4999,28 +5012,6 @@ static bool try_to_shrink_lruvec(struct lruvec *lruv= ec, struct scan_control *sc) cond_resched(); } =20 - /* - * If too many file cache in the coldest generation can't be evicted - * due to being dirty, wake up the flusher. - */ - if (sc->nr.unqueued_dirty && sc->nr.unqueued_dirty =3D=3D sc->nr.file_tak= en) { - struct pglist_data *pgdat =3D lruvec_pgdat(lruvec); - - wakeup_flusher_threads(WB_REASON_VMSCAN); - - /* - * For cgroupv1 dirty throttling is achieved by waking up - * the kernel flusher here and later waiting on folios - * which are in writeback to finish (see shrink_folio_list()). - * - * Flusher may not be able to issue writeback quickly - * enough for cgroupv1 writeback throttling to work - * on a large system. - */ - if (!writeback_throttling_sane(sc)) - reclaim_throttle(pgdat, VMSCAN_THROTTLE_WRITEBACK); - } - return need_rotate; } =20 --=20 2.53.0