summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/kmemleak.c51
1 files changed, 38 insertions, 13 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index e196f53f9b46..16b72cead07d 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1697,6 +1697,42 @@ unlock_put:
}
/*
+ * Scan all task kernel stacks, rescheduling between tasks. Each task is looked
+ * up and pinned within its own RCU read-side section, so no lock is held across
+ * the scan and the walk cannot trip the soft lockup watchdog.
+ */
+static void kmemleak_scan_task_stacks(void)
+{
+ struct pid *pid;
+ int nr = 1;
+
+ do {
+ struct task_struct *p = NULL;
+
+ rcu_read_lock();
+ pid = find_ge_pid(nr, &init_pid_ns);
+ if (pid) {
+ nr = pid_nr(pid) + 1;
+ p = pid_task(pid, PIDTYPE_PID);
+ if (p)
+ get_task_struct(p);
+ }
+ rcu_read_unlock();
+
+ if (p) {
+ void *stack = try_get_task_stack(p);
+
+ if (stack) {
+ scan_block(stack, stack + THREAD_SIZE, NULL);
+ put_task_stack(p);
+ }
+ put_task_struct(p);
+ }
+ cond_resched();
+ } while (pid && !scan_should_stop());
+}
+
+/*
* Print one leak inline. The hex dump is gated on OBJECT_ALLOCATED so it
* does not touch user memory that was freed concurrently; the rest of the
* report (backtrace, comm, pid) is always emitted since the kmemleak_object
@@ -1885,19 +1921,8 @@ static void kmemleak_scan(void)
/*
* Scanning the task stacks (may introduce false negatives).
*/
- if (kmemleak_stack_scan) {
- struct task_struct *p, *g;
-
- rcu_read_lock();
- for_each_process_thread(g, p) {
- void *stack = try_get_task_stack(p);
- if (stack) {
- scan_block(stack, stack + THREAD_SIZE, NULL);
- put_task_stack(p);
- }
- }
- rcu_read_unlock();
- }
+ if (kmemleak_stack_scan)
+ kmemleak_scan_task_stacks();
/*
* Scan the objects already referenced from the sections scanned