From 5f753a48f64f2b91f55d38b9f20cc83e3ed94ffa Mon Sep 17 00:00:00 2001 From: Kaihao Bai Date: Thu, 16 Apr 2026 11:45:44 +0800 Subject: [PATCH] anolis: mm: exclude dirty pages from min_cache_kbytes protection ANBZ: #33265 min_cache_kbytes is intended to protect hot code segments and shared libraries from reclaim, which are typically clean file pages. However, the current implementation counts both clean and dirty file pages toward the watermark, causing dirty pages to incorrectly consume the reserved quota and leaving hot clean file pages vulnerable to eviction. Only account clean file pages against the min_cache_kbytes watermark, excluding dirty pages which are handled independently via the writeback path. Signed-off-by: Kaihao Bai --- mm/vmscan.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 85151e7b4b7d..2447fe5fa372 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -927,6 +927,11 @@ static enum folio_references folio_check_references(struct folio *folio, /* rmap lock contention: rotate */ if (referenced_ptes == -1) return FOLIOREF_KEEP; + /* + * Activate file-backed executable folios if min_cache_kbytes is enabled. + */ + if ((vm_flags & VM_EXEC) && folio_is_file_lru(folio) && sc->file_is_reserved) + return FOLIOREF_ACTIVATE; if (lru_gen_enabled()) { if (!referenced_ptes) @@ -2413,8 +2418,13 @@ static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) * given watermark. */ min_cache_kbytes = READ_ONCE(sysctl_min_cache_kbytes); - if (min_cache_kbytes) + if (min_cache_kbytes && !sc->file_is_reserved) { + unsigned long f_dirty; + + f_dirty = node_page_state(pgdat, NR_FILE_DIRTY); + file = (file > f_dirty) ? file - f_dirty : 0; sc->file_is_reserved = file <= pgdat->min_cache_pages; + } } } @@ -2621,9 +2631,6 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc, BUG(); } - if (sc->file_is_reserved && file) - scan = 0; - nr[lru] = scan; } } @@ -4816,11 +4823,6 @@ static int isolate_folios(unsigned long nr_to_scan, struct lruvec *lruvec, int type_scan; int tier = get_tier_idx(lruvec, type); - if (sc->file_is_reserved && (type == LRU_GEN_FILE)) { - type = !type; - continue; - } - type_scan = scan_folios(nr_to_scan, lruvec, sc, type, tier, list, isolated); scanned += type_scan; @@ -6477,14 +6479,15 @@ static void snapshot_refaults(struct mem_cgroup *target_memcg, pg_data_t *pgdat) static bool memcg_can_shrink(struct scan_control *sc) { struct mem_cgroup *memcg = sc->target_mem_cgroup; - unsigned long file; + unsigned long file, f_dirty; if (cgroup_reclaim(sc) && memcg->min_cache_pages) { file = memcg_page_state(memcg, NR_ACTIVE_FILE) + memcg_page_state(memcg, NR_INACTIVE_FILE); + f_dirty = memcg_page_state(memcg, NR_FILE_DIRTY); + file = (file > f_dirty) ? file - f_dirty : 0; + sc->file_is_reserved = file < memcg->min_cache_pages; - if (sc->file_is_reserved && !mem_cgroup_swappiness(memcg)) - return false; } return true; -- Gitee