All of lore.kernel.org
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] mm/kmemleak: report RCU-tasks quiescent states during the" failed to apply to 6.12-stable tree
@ 2026-09-03 10:47 gregkh
  2026-09-03 18:32 ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Sasha Levin
  0 siblings, 1 reply; 4+ messages in thread
From: gregkh @ 2026-09-03 10:47 UTC (permalink / raw)
  To: leitao, akpm, catalin.marinas, paulmck, puranjay, sj, stable; +Cc: stable


The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 3541a2b06ecd78ba333188df04368dcf97273d6a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090345-doorpost-concur-ba65@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'

Possible dependencies:



thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 3541a2b06ecd78ba333188df04368dcf97273d6a Mon Sep 17 00:00:00 2001
From: Breno Leitao <leitao@debian.org>
Date: Mon, 20 Jul 2026 06:23:45 -0700
Subject: [PATCH] mm/kmemleak: report RCU-tasks quiescent states during the
 scan

kmemleak_scan() can run for ages on large debug kernels. It was
causing some soft-lockups which I got fixed with commit
3175fcfec8b16baeb ("mm/kmemleak: avoid soft lockup when scanning task
stacks") with our beloved cond_resched().

I've got the fix above deployed in the Meta fleet, and now I am seeing:

  INFO: rcu_tasks detected stalls on tasks:
    task:kmemleak state:R ... nvcsw: 274/274 holdout: 1 idle_cpu: -1/3
     scan_block
     scan_gray_list
     kmemleak_scan

and, worse, blocks the callers waiting on that grace period.  Here a BPF
struct_ops map free, which waits via synchronize_rcu_mult(call_rcu,
call_rcu_tasks), is stuck long enough to also trip the hung task check:

  INFO: task kworker/...:bpf_map_free_deferred blocked for 122 seconds
     __wait_rcu_gp
     bpf_struct_ops_map_free

Then I've learned that cond_resched() is not an RCU-tasks quiescent
state, so, we need to use stronger primitives.

Use cond_resched_tasks_rcu_qs() at the scan reschedule points so the scan
reports an RCU-tasks quiescent state as it proceeds.

Inspired by commit b96285e10aad ("tracing: Have osnoise_main() add a
quiescent state for task rcu").

Link: https://lore.kernel.org/20260720-kmemleak_rcu_task-v1-1-5b460ade777d@debian.org
Fixes: c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: SJ Park <sj@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Breno Leitao <leitao@debian.org>
Cc: Puranjay Mohan <puranjay@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index e96e9efd19b0..0a6045c857d6 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1571,7 +1571,7 @@ static int scan_large_block(void *start, void *end)
 		if (scan_block(start, next, NULL))
 			return 1;
 		start = next;
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 	}
 
 	return 0;
@@ -1608,7 +1608,7 @@ static void scan_object(struct kmemleak_object *object)
 			scan_block(start, end, object);
 
 			raw_spin_unlock_irqrestore(&object->lock, flags);
-			cond_resched();
+			cond_resched_tasks_rcu_qs();
 			raw_spin_lock_irqsave(&object->lock, flags);
 			if (!(object->flags & OBJECT_ALLOCATED))
 				break;
@@ -1630,7 +1630,7 @@ static void scan_object(struct kmemleak_object *object)
 				break;
 
 			raw_spin_unlock_irqrestore(&object->lock, flags);
-			cond_resched();
+			cond_resched_tasks_rcu_qs();
 			raw_spin_lock_irqsave(&object->lock, flags);
 		} while (object->flags & OBJECT_ALLOCATED);
 	} else {
@@ -1658,7 +1658,7 @@ static void scan_gray_list(void)
 	 */
 	object = list_entry(gray_list.next, typeof(*object), gray_list);
 	while (&object->gray_list != &gray_list) {
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 
 		/* may add new objects to the list */
 		if (!scan_should_stop())
@@ -1693,7 +1693,7 @@ static void kmemleak_cond_resched(struct kmemleak_object *object)
 	raw_spin_unlock_irq(&kmemleak_lock);
 
 	rcu_read_unlock();
-	cond_resched();
+	cond_resched_tasks_rcu_qs();
 	rcu_read_lock();
 
 	raw_spin_lock_irq(&kmemleak_lock);
@@ -1738,7 +1738,7 @@ static void kmemleak_scan_task_stacks(void)
 			}
 			put_task_struct(p);
 		}
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 	} while (pid && !stop);
 }
 
@@ -1915,7 +1915,7 @@ static void kmemleak_scan(void)
 			struct page *page = pfn_to_online_page(pfn);
 
 			if (!(pfn & 63))
-				cond_resched();
+				cond_resched_tasks_rcu_qs();
 
 			if (!page)
 				continue;


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks
  2026-09-03 10:47 FAILED: patch "[PATCH] mm/kmemleak: report RCU-tasks quiescent states during the" failed to apply to 6.12-stable tree gregkh
@ 2026-09-03 18:32 ` Sasha Levin
  2026-09-03 18:32   ` [PATCH 6.12.y 2/2] mm/kmemleak: report RCU-tasks quiescent states during the scan Sasha Levin
  2026-09-17 11:22   ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Greg KH
  0 siblings, 2 replies; 4+ messages in thread
From: Sasha Levin @ 2026-09-03 18:32 UTC (permalink / raw)
  To: stable
  Cc: Breno Leitao, Catalin Marinas, Davidlohr Bueso, Lance Yang,
	Oleg Nesterov, Qian Cai, SeongJae Park, Andrew Morton,
	Sasha Levin

From: Breno Leitao <leitao@debian.org>

[ Upstream commit 5d10d4e19e6daa487f0cd0ea6cba472325de92f9 ]

Patch series "mm/kmemleak: avoid soft lockup when scanning task", v3.

kmemleak_scan() scans every task stack under one rcu_read_lock() with no
reschedule point, which can trip the soft lockup watchdog on hosts with
very many threads.

That prints the following message, depending on the workload+host
configuration:

      watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
       scan_block
       kmemleak_scan
       kmemleak_scan_thread
       kthread

Patch 1 walks the tasks with find_ge_pid() so the scan reschedules between
tasks

Patches 2-3 let the scan loops stop early once a scan is interrupted.

This patch (of 3):

kmemleak_scan() walks every thread and scans its kernel stack under a
single rcu_read_lock() with no reschedule point.  On a host with very many
threads -- amplified by KASAN/lockdep in debug builds -- this loop can hog
a CPU long enough to trip the soft lockup watchdog:

  watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
   scan_block
   kmemleak_scan
   kmemleak_scan_thread
   kthread

A cond_resched() cannot be added directly: the loop runs inside an RCU
read-side critical section.

Walk the tasks one PID at a time with find_ge_pid(), taking the RCU read
lock only to look up and pin each task.  The stack is then scanned with no
lock held, so cond_resched() runs between tasks and the scan stops early
on scan_should_stop().  This follows the next_tgid()/task_seq_get_next()
iteration pattern and keeps each RCU critical section short.

Link: https://lore.kernel.org/20260615-kmemleak-stack-resched-v3-0-acecd7d7fd92@debian.org
Link: https://lore.kernel.org/20260615-kmemleak-stack-resched-v3-1-acecd7d7fd92@debian.org
Fixes: c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Qian Cai <cai@lca.pw>
Cc: SeongJae Park <sj@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Stable-dep-of: 3541a2b06ecd ("mm/kmemleak: report RCU-tasks quiescent states during the scan")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 mm/kmemleak.c | 91 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 68 insertions(+), 23 deletions(-)

diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 4092f38d3fc84..0dcdddb3c33d8 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1499,22 +1499,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);
@@ -1524,22 +1527,28 @@ static void scan_block(void *_start, void *_end,
 		pointer_update_refs(scanned, pointer, OBJECT_PERCPU);
 	}
 	raw_spin_unlock_irqrestore(&kmemleak_lock, flags);
+
+	return stop;
 }
 
 /*
  * 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
 
@@ -1670,6 +1679,43 @@ static void kmemleak_cond_resched(struct kmemleak_object *object)
 	put_object(object);
 }
 
+/*
+ * 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;
+	int stop = 0;
+
+	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) {
+				stop = scan_block(stack, stack + THREAD_SIZE, NULL);
+				put_task_stack(p);
+			}
+			put_task_struct(p);
+		}
+		cond_resched();
+	} while (pid && !stop);
+}
+
 /*
  * Scan data sections and all the referenced memory blocks allocated via the
  * kernel's standard allocators. This function must be called with the
@@ -1681,6 +1727,7 @@ static void kmemleak_scan(void)
 	struct zone *zone;
 	int __maybe_unused i;
 	int new_leaks = 0;
+	int stop = 0;
 
 	jiffies_last_scan = jiffies;
 
@@ -1724,9 +1771,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)))
+			goto scan_gray;
+	}
 #endif
 
 	/*
@@ -1753,32 +1802,28 @@ 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();
+	if (stop)
+		goto scan_gray;
 
 	/*
 	 * 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
 	 * above.
 	 */
+scan_gray:
 	scan_gray_list();
 
 	/*
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 6.12.y 2/2] mm/kmemleak: report RCU-tasks quiescent states during the scan
  2026-09-03 18:32 ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Sasha Levin
@ 2026-09-03 18:32   ` Sasha Levin
  2026-09-17 11:22   ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Greg KH
  1 sibling, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-09-03 18:32 UTC (permalink / raw)
  To: stable
  Cc: Breno Leitao, Paul E. McKenney, SJ Park, Catalin Marinas,
	Puranjay Mohan, Andrew Morton, Sasha Levin

From: Breno Leitao <leitao@debian.org>

[ Upstream commit 3541a2b06ecd78ba333188df04368dcf97273d6a ]

kmemleak_scan() can run for ages on large debug kernels. It was
causing some soft-lockups which I got fixed with commit
3175fcfec8b16baeb ("mm/kmemleak: avoid soft lockup when scanning task
stacks") with our beloved cond_resched().

I've got the fix above deployed in the Meta fleet, and now I am seeing:

  INFO: rcu_tasks detected stalls on tasks:
    task:kmemleak state:R ... nvcsw: 274/274 holdout: 1 idle_cpu: -1/3
     scan_block
     scan_gray_list
     kmemleak_scan

and, worse, blocks the callers waiting on that grace period.  Here a BPF
struct_ops map free, which waits via synchronize_rcu_mult(call_rcu,
call_rcu_tasks), is stuck long enough to also trip the hung task check:

  INFO: task kworker/...:bpf_map_free_deferred blocked for 122 seconds
     __wait_rcu_gp
     bpf_struct_ops_map_free

Then I've learned that cond_resched() is not an RCU-tasks quiescent
state, so, we need to use stronger primitives.

Use cond_resched_tasks_rcu_qs() at the scan reschedule points so the scan
reports an RCU-tasks quiescent state as it proceeds.

Inspired by commit b96285e10aad ("tracing: Have osnoise_main() add a
quiescent state for task rcu").

Link: https://lore.kernel.org/20260720-kmemleak_rcu_task-v1-1-5b460ade777d@debian.org
Fixes: c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: SJ Park <sj@kernel.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Breno Leitao <leitao@debian.org>
Cc: Puranjay Mohan <puranjay@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 mm/kmemleak.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 0dcdddb3c33d8..1957bb7c670e7 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1545,7 +1545,7 @@ static int scan_large_block(void *start, void *end)
 		if (scan_block(start, next, NULL))
 			return 1;
 		start = next;
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 	}
 
 	return 0;
@@ -1582,7 +1582,7 @@ static void scan_object(struct kmemleak_object *object)
 			scan_block(start, end, object);
 
 			raw_spin_unlock_irqrestore(&object->lock, flags);
-			cond_resched();
+			cond_resched_tasks_rcu_qs();
 			raw_spin_lock_irqsave(&object->lock, flags);
 			if (!(object->flags & OBJECT_ALLOCATED))
 				break;
@@ -1604,7 +1604,7 @@ static void scan_object(struct kmemleak_object *object)
 				break;
 
 			raw_spin_unlock_irqrestore(&object->lock, flags);
-			cond_resched();
+			cond_resched_tasks_rcu_qs();
 			raw_spin_lock_irqsave(&object->lock, flags);
 		} while (object->flags & OBJECT_ALLOCATED);
 	} else {
@@ -1632,7 +1632,7 @@ static void scan_gray_list(void)
 	 */
 	object = list_entry(gray_list.next, typeof(*object), gray_list);
 	while (&object->gray_list != &gray_list) {
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 
 		/* may add new objects to the list */
 		if (!scan_should_stop())
@@ -1667,7 +1667,7 @@ static void kmemleak_cond_resched(struct kmemleak_object *object)
 	raw_spin_unlock_irq(&kmemleak_lock);
 
 	rcu_read_unlock();
-	cond_resched();
+	cond_resched_tasks_rcu_qs();
 	rcu_read_lock();
 
 	raw_spin_lock_irq(&kmemleak_lock);
@@ -1712,7 +1712,7 @@ static void kmemleak_scan_task_stacks(void)
 			}
 			put_task_struct(p);
 		}
-		cond_resched();
+		cond_resched_tasks_rcu_qs();
 	} while (pid && !stop);
 }
 
@@ -1791,7 +1791,7 @@ static void kmemleak_scan(void)
 			struct page *page = pfn_to_online_page(pfn);
 
 			if (!(pfn & 63))
-				cond_resched();
+				cond_resched_tasks_rcu_qs();
 
 			if (!page)
 				continue;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks
  2026-09-03 18:32 ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Sasha Levin
  2026-09-03 18:32   ` [PATCH 6.12.y 2/2] mm/kmemleak: report RCU-tasks quiescent states during the scan Sasha Levin
@ 2026-09-17 11:22   ` Greg KH
  1 sibling, 0 replies; 4+ messages in thread
From: Greg KH @ 2026-09-17 11:22 UTC (permalink / raw)
  To: Sasha Levin
  Cc: stable, Breno Leitao, Catalin Marinas, Davidlohr Bueso,
	Lance Yang, Oleg Nesterov, Qian Cai, SeongJae Park, Andrew Morton

On Thu, Sep 03, 2026 at 02:32:41PM -0400, Sasha Levin wrote:
> From: Breno Leitao <leitao@debian.org>
> 
> [ Upstream commit 5d10d4e19e6daa487f0cd0ea6cba472325de92f9 ]
> 
> Patch series "mm/kmemleak: avoid soft lockup when scanning task", v3.
> 
> kmemleak_scan() scans every task stack under one rcu_read_lock() with no
> reschedule point, which can trip the soft lockup watchdog on hosts with
> very many threads.
> 
> That prints the following message, depending on the workload+host
> configuration:
> 
>       watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
>        scan_block
>        kmemleak_scan
>        kmemleak_scan_thread
>        kthread
> 
> Patch 1 walks the tasks with find_ge_pid() so the scan reschedules between
> tasks
> 
> Patches 2-3 let the scan loops stop early once a scan is interrupted.
> 
> This patch (of 3):
> 
> kmemleak_scan() walks every thread and scans its kernel stack under a
> single rcu_read_lock() with no reschedule point.  On a host with very many
> threads -- amplified by KASAN/lockdep in debug builds -- this loop can hog
> a CPU long enough to trip the soft lockup watchdog:
> 
>   watchdog: BUG: soft lockup - CPU#35 stuck for 22s! [kmemleak:537]
>    scan_block
>    kmemleak_scan
>    kmemleak_scan_thread
>    kthread
> 
> A cond_resched() cannot be added directly: the loop runs inside an RCU
> read-side critical section.
> 
> Walk the tasks one PID at a time with find_ge_pid(), taking the RCU read
> lock only to look up and pin each task.  The stack is then scanned with no
> lock held, so cond_resched() runs between tasks and the scan stops early
> on scan_should_stop().  This follows the next_tgid()/task_seq_get_next()
> iteration pattern and keeps each RCU critical section short.
> 
> Link: https://lore.kernel.org/20260615-kmemleak-stack-resched-v3-0-acecd7d7fd92@debian.org
> Link: https://lore.kernel.org/20260615-kmemleak-stack-resched-v3-1-acecd7d7fd92@debian.org
> Fixes: c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")
> Signed-off-by: Breno Leitao <leitao@debian.org>
> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
> Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>
> Reviewed-by: Lance Yang <lance.yang@linux.dev>
> Reviewed-by: Oleg Nesterov <oleg@redhat.com>
> Cc: Qian Cai <cai@lca.pw>
> Cc: SeongJae Park <sj@kernel.org>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> Stable-dep-of: 3541a2b06ecd ("mm/kmemleak: report RCU-tasks quiescent states during the scan")
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
>  mm/kmemleak.c | 91 ++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 68 insertions(+), 23 deletions(-)
> 
> diff --git a/mm/kmemleak.c b/mm/kmemleak.c
> index 4092f38d3fc84..0dcdddb3c33d8 100644
> --- a/mm/kmemleak.c
> +++ b/mm/kmemleak.c
> @@ -1499,22 +1499,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);
> @@ -1524,22 +1527,28 @@ static void scan_block(void *_start, void *_end,
>  		pointer_update_refs(scanned, pointer, OBJECT_PERCPU);
>  	}
>  	raw_spin_unlock_irqrestore(&kmemleak_lock, flags);
> +
> +	return stop;
>  }
>  
>  /*
>   * 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
>  
> @@ -1670,6 +1679,43 @@ static void kmemleak_cond_resched(struct kmemleak_object *object)
>  	put_object(object);
>  }
>  
> +/*
> + * 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;
> +	int stop = 0;
> +
> +	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) {
> +				stop = scan_block(stack, stack + THREAD_SIZE, NULL);
> +				put_task_stack(p);
> +			}
> +			put_task_struct(p);
> +		}
> +		cond_resched();
> +	} while (pid && !stop);
> +}
> +
>  /*
>   * Scan data sections and all the referenced memory blocks allocated via the
>   * kernel's standard allocators. This function must be called with the
> @@ -1681,6 +1727,7 @@ static void kmemleak_scan(void)
>  	struct zone *zone;
>  	int __maybe_unused i;
>  	int new_leaks = 0;
> +	int stop = 0;
>  
>  	jiffies_last_scan = jiffies;
>  
> @@ -1724,9 +1771,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)))
> +			goto scan_gray;
> +	}
>  #endif
>  
>  	/*
> @@ -1753,32 +1802,28 @@ 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();
> +	if (stop)
> +		goto scan_gray;
>  
>  	/*
>  	 * 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
>  	 * above.
>  	 */
> +scan_gray:
>  	scan_gray_list();
>  
>  	/*
> -- 
> 2.53.0
> 
> 

Does not apply

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-17 11:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 10:47 FAILED: patch "[PATCH] mm/kmemleak: report RCU-tasks quiescent states during the" failed to apply to 6.12-stable tree gregkh
2026-09-03 18:32 ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Sasha Levin
2026-09-03 18:32   ` [PATCH 6.12.y 2/2] mm/kmemleak: report RCU-tasks quiescent states during the scan Sasha Levin
2026-09-17 11:22   ` [PATCH 6.12.y 1/2] mm/kmemleak: avoid soft lockup when scanning task stacks Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.