From cdf95d6b3387b99a9377046491a0a51bad93b5af Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Mon, 15 Jun 2026 10:49:08 -0700 Subject: [PATCH] mm/kmemleak: stop the per-cpu and struct page scans early too The per-cpu and struct page scan loops have no reschedule-stop check of their own: once a scan is interrupted they keep calling scan_block() for every remaining block, which scans nothing useful. Propagate scan_block()'s interrupted status through scan_large_block() and break both loops as soon as it is set. Link: https://lore.kernel.org/20260615-kmemleak-stack-resched-v3-3-acecd7d7fd92@debian.org Signed-off-by: Breno Leitao Suggested-by: Catalin Marinas Reviewed-by: Catalin Marinas Reviewed-by: Oleg Nesterov Cc: Davidlohr Bueso Cc: Lance Yang Cc: Qian Cai Cc: SeongJae Park Signed-off-by: Andrew Morton --- mm/kmemleak.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index bc79e293531b..ac2a44a1c4a5 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1559,18 +1559,22 @@ static int scan_block(void *_start, void *_end, /* * Scan a large memory block in MAX_SCAN_SIZE chunks to reduce the latency. + * Return non-zero if the scan was interrupted. */ #ifdef CONFIG_SMP -static void scan_large_block(void *start, void *end) +static int scan_large_block(void *start, void *end) { void *next; while (start < end) { next = min(start + MAX_SCAN_SIZE, end); - scan_block(start, next, NULL); + if (scan_block(start, next, NULL)) + return 1; start = next; cond_resched(); } + + return 0; } #endif @@ -1890,9 +1894,11 @@ static void kmemleak_scan(void) #ifdef CONFIG_SMP /* per-cpu sections scanning */ - for_each_possible_cpu(i) - scan_large_block(__per_cpu_start + per_cpu_offset(i), - __per_cpu_end + per_cpu_offset(i)); + for_each_possible_cpu(i) { + if (scan_large_block(__per_cpu_start + per_cpu_offset(i), + __per_cpu_end + per_cpu_offset(i))) + break; + } #endif /* @@ -1903,6 +1909,7 @@ static void kmemleak_scan(void) unsigned long start_pfn = zone->zone_start_pfn; unsigned long end_pfn = zone_end_pfn(zone); unsigned long pfn; + int stop = 0; for (pfn = start_pfn; pfn < end_pfn; pfn++) { struct page *page = pfn_to_online_page(pfn); @@ -1919,8 +1926,12 @@ static void kmemleak_scan(void) /* only scan if page is in use */ if (page_count(page) == 0) continue; - scan_block(page, page + 1, NULL); + stop = scan_block(page, page + 1, NULL); + if (stop) + break; } + if (stop) + break; } put_online_mems();