From: "Kiryl Shutsemau (Meta)" __folio_unqueue_deferred_split() and __folio_freeze_and_split_unmapped() both clear PG_partially_mapped and take the folio out of MTHP_STAT_NR_ANON_PARTIALLY_MAPPED with the same five lines. Move the block into folio_reset_partially_mapped() and call it from both places. The helper asserts what both callers rely on: the folio is frozen, so deferred_split_folio() cannot set the flag again under it, and the folio is already off the deferred split queue. The list check sits behind the flag test because order-1 folios have no _deferred_list. folio_order() is safe to use at this point in the split process: it still shows the pre-split order. Suggested-by: David Hildenbrand (Arm) Assisted-by: Claude-Code:claude-fable-5-1 Signed-off-by: Kiryl Shutsemau (Meta) --- mm/huge_memory.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index dd66c6ad5af1..23ef22c2b5db 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3972,6 +3972,24 @@ static unsigned int folio_cache_ref_count(const struct folio *folio) return folio_nr_pages(folio); } +static void folio_reset_partially_mapped(struct folio *folio) +{ + VM_WARN_ON_FOLIO(folio_ref_count(folio), folio); + + if (!folio_test_partially_mapped(folio)) + return; + + /* + * Order-1 folios have no _deferred_list. The flag is only ever set + * on folios that do, so the list can be checked after the flag. + */ + VM_WARN_ON_FOLIO(!list_empty(&folio->_deferred_list), folio); + + folio_clear_partially_mapped(folio); + mod_mthp_stat(folio_order(folio), + MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1); +} + static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int new_order, struct page *split_at, struct xa_state *xas, struct address_space *mapping, bool do_lru, @@ -3980,7 +3998,6 @@ static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int n { struct folio *end_folio = folio_next(folio); struct folio *new_folio, *next; - int old_order = folio_order(folio); int ret = 0; VM_WARN_ON_ONCE(!mapping && end); @@ -3998,11 +4015,7 @@ static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int n * leaves PG_partially_mapped set. * Clear it here: the flag does not survive the split. */ - if (folio_test_partially_mapped(folio)) { - folio_clear_partially_mapped(folio); - mod_mthp_stat(old_order, - MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1); - } + folio_reset_partially_mapped(folio); if (mapping) { int nr = folio_nr_pages(folio); @@ -4516,11 +4529,7 @@ bool __folio_unqueue_deferred_split(struct folio *folio) memcg = folio_memcg(folio); lru = list_lru_lock_irqsave(&deferred_split_lru, nid, &memcg, &flags); if (__list_lru_del(&deferred_split_lru, lru, &folio->_deferred_list, nid)) { - if (folio_test_partially_mapped(folio)) { - folio_clear_partially_mapped(folio); - mod_mthp_stat(folio_order(folio), - MTHP_STAT_NR_ANON_PARTIALLY_MAPPED, -1); - } + folio_reset_partially_mapped(folio); unqueued = true; } list_lru_unlock_irqrestore(lru, &flags); base-commit: e3fc12b08aadde9cec7b3799ac0e0c9a1aa245c4 -- 2.54.0