Every anonymous PMD-sized folio is put on the deferred split queue when it is first mapped, so that the shrinker can find it under memory pressure and split it if it turns out to be mostly zero-filled. With the default khugepaged/max_ptes_none this is wasted work. The default is HPAGE_PMD_NR - 1, which tells thp_underused() that any number of zero-filled pages is tolerable, which means the shrinker will never split any of these folios for being underused. They take the list_lru lock at fault time, inflate the object count the shrinker reports, and are then walked and dropped when they're first scanned. Skip the queuing for folios that thp_can_be_underused() says can never qualify. At the default khugepaged/max_ptes_none that is all of them, and once the knob is lowered only folios with more pages than it are queued. This matters for a subsequent patch that adds anonymous mTHP folios to the deferred split list, as it prevents small mTHP orders from taking the list_lru lock on every anonymous fault. Please note that the queue has always been best-effort. A folio that was queued before khugepaged/max_ptes_none is lowered gets dropped from the queue by the first scan that finds it's not underused, so changing the sysctl has never retroactively applied to folios that were already scanned. Requeueing eligible folios when the sysctl changes will be addressed in a separate patch. Suggested-by: Johannes Weiner Signed-off-by: Joanne Koong --- mm/huge_memory.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c6ca2a541128..e3349f2314cb 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -4573,8 +4573,18 @@ void deferred_split_folio(struct folio *folio, bool partially_mapped) if (folio_order(folio) <= 1) return; - if (!partially_mapped && !split_underused_thp) - return; + if (!partially_mapped) { + if (!split_underused_thp) + return; + /* + * Nothing will ever split this folio for being underused, so + * keep it off the queue entirely rather than paying for the + * list_lru lock here and a shrinker scan later. + */ + if (!thp_can_be_underused(folio_nr_pages(folio), + khugepaged_max_ptes_none)) + return; + } /* * Exclude swapcache: originally to avoid a corrupt deferred split -- 2.52.0