[PATCH v3 2/3] mm/kmemleak: stop the task stack scan early when interrupted
From: Breno Leitao
Date: Mon Jun 15 2026 - 13:54:22 EST
scan_block() already checks scan_should_stop() for every pointer and
bails out of the current block, but the task stack walk cannot tell and
keeps issuing a separate scan_should_stop() between every task.
Return that status from scan_block() and use it as the task stack loop
condition, so the walk stops as soon as a scan is interrupted.
Suggested-by: Catalin Marinas <catalin.marinas@xxxxxxx>
Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
mm/kmemleak.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index a7786b6bc174e..916af7cecb3b4 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1524,22 +1524,25 @@ static int scan_should_stop(void)
/*
* Scan a memory block (exclusive range) for valid pointers and add those
- * found to the gray list.
+ * found to the gray list. Return non-zero if the scan was interrupted.
*/
-static void scan_block(void *_start, void *_end,
- struct kmemleak_object *scanned)
+static int scan_block(void *_start, void *_end,
+ struct kmemleak_object *scanned)
{
unsigned long *ptr;
unsigned long *start = PTR_ALIGN(_start, BYTES_PER_POINTER);
unsigned long *end = _end - (BYTES_PER_POINTER - 1);
unsigned long flags;
+ int stop = 0;
raw_spin_lock_irqsave(&kmemleak_lock, flags);
for (ptr = start; ptr < end; ptr++) {
unsigned long pointer;
- if (scan_should_stop())
+ if (scan_should_stop()) {
+ stop = 1;
break;
+ }
kasan_disable_current();
pointer = *(unsigned long *)kasan_reset_tag((void *)ptr);
@@ -1549,6 +1552,8 @@ static void scan_block(void *_start, void *_end,
pointer_update_refs(scanned, pointer, OBJECT_PERCPU);
}
raw_spin_unlock_irqrestore(&kmemleak_lock, flags);
+
+ return stop;
}
/*
@@ -1704,6 +1709,7 @@ static void kmemleak_scan_task_stacks(void)
{
struct pid *pid;
int nr = 1;
+ int stop = 0;
do {
struct task_struct *p = NULL;
@@ -1722,13 +1728,13 @@ static void kmemleak_scan_task_stacks(void)
void *stack = try_get_task_stack(p);
if (stack) {
- scan_block(stack, stack + THREAD_SIZE, NULL);
+ stop = scan_block(stack, stack + THREAD_SIZE, NULL);
put_task_stack(p);
}
put_task_struct(p);
}
cond_resched();
- } while (pid && !scan_should_stop());
+ } while (pid && !stop);
}
/*
--
2.53.0-Meta