mm/kmemleak: report RCU-tasks quiescent states during the scan
Subsystems (3)
PATCH 1/1 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_scanand, 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_freeThen 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").
--- mm/kmemleak.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
mm/kmemleak.c +7 -7
@@ -1586,7 +1586,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 ;
@@ -1623,7 +1623,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 ;
@@ -1645,7 +1645,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 {
@@ -1673,7 +1673,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 ())
@@ -1708,7 +1708,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);
@@ -1753,7 +1753,7 @@ static void kmemleak_scan_task_stacks(void) }put_task_struct (p); } -cond_resched (); +cond_resched_tasks_rcu_qs (); }while (pid && !stop); }
@@ -1935,7 +1935,7 @@ static int __kmemleak_scan(bool full)struct page *page =pfn_to_online_page (pfn);if (!(pfn &63 )) -cond_resched (); +cond_resched_tasks_rcu_qs ();if (!page)continue ;
---
base-commit: 0718283ab28bc3907e10b61a6b4be6fefa1cbb2f
change-id: 20260720-kmemleak_rcu_task-6d3ea111b947
Best regards,
Signature · 1 line
Breno Leitao <[email protected]>
[email protected]
AI reviewThank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Incomplete fix: Tasks RCU stalls persist in __kmemleak_do_cleanup() and __kmemleak_scan().
- [High] Unbounded RCU critical section in kmemleak_clear() stalls Normal RCU.
--
--- Patch [1]: [PATCH] mm/kmemleak: report RCU-tasks quiescent states during the scan --- commit 558fef0ac4a016de42546b6d38536df76b835edb
Author: Breno Leitao <[email protected]>
mm/kmemleak: report RCU-tasks quiescent states during the scan
This patch replaces cond_resched() with cond_resched_tasks_rcu_qs() at various reschedule points during the kmemleak scan. This aims to report Tasks RCU quiescent states and prevent Tasks RCU stalls and hung tasks, since cond_resched() by itself is not a Tasks RCU quiescent state.
Quoted 4 lines
mm/kmemleak.c +0
-0
[ ... ]
mm/kmemleak.c static void kmemleak_cond_resched(struct kmemleak_object *object) · line 1714
Quoted 9 lines
mm/kmemleak.c +1
-1@@ -1708,7 +1708,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);
[Severity: High]
This is a pre-existing issue, but modifying kmemleak_cond_resched() here might not fully resolve the Tasks RCU stall.
kmemleak_cond_resched() is only called in __kmemleak_scan() when need_resched() is true:
if (need_resched()) kmemleak_cond_resched(object);
Since Tasks RCU does not actively set the need_resched flag on running tasks (unlike normal RCU, which uses inter-processor interrupts during a stall), need_resched() could remain false on an otherwise idle system.
Does this mean the Tasks RCU quiescent state update is never reached, bypassing this new logic and leaving the stall bug intact?
[ ... ]
[Severity: High]
Additionally, this is a pre-existing issue, but does __kmemleak_do_cleanup() need a similar fix?
It still uses the bare cond_resched() in its loop:
mm/kmemleak.c:__kmemleak_do_cleanup() {
list_for_each_entry_safe(object, tmp, &object_list, object_list) {
...
/* Call cond_resched() once per 64 iterations to avoid soft lockup */
if (!(++cnt & 0x3f))
cond_resched();
}
}Will this cause Tasks RCU grace periods to stall during cleanup work, just like they were stalling during the scan?
[Severity: High]
This is another pre-existing issue, but can the unyielding loop in kmemleak_clear() stall normal RCU?
When a privileged user writes 'clear' to /sys/kernel/debug/kmemleak, it invokes kmemleak_clear(), which iterates over the entire object_list:
mm/kmemleak.c:kmemleak_clear() {
rcu_read_lock();
list_for_each_entry_rcu(object, &object_list, object_list) {
raw_spin_lock_irq(&object->lock);
...
raw_spin_unlock_irq(&object->lock);
}
rcu_read_unlock();
}Since this loop runs fully inside an RCU read-side critical section with no yielding mechanisms whatsoever, could iterating millions of objects uninterrupted exceed the 21-second RCU stall timeout and trigger normal RCU stall warnings?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Quoted 24 lines · Breno Leitao
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen I've learned that
cond_resched()is not an RCU-tasks quiescent state, so, we need to use stronger primitives.
Quoted 7 lines
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: Haveosnoise_main()add a quiescent state for task rcu").Signed-off-by Breno Leitao <[email protected]>
Quoted 80 lines
--- mm/kmemleak.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)mm/kmemleak.c +7
-8@@ -1586,7 +1586,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 ;@@ -1623,7 +1623,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 ;@@ -1645,7 +1645,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 {@@ -1673,7 +1673,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 ())@@ -1708,7 +1708,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);@@ -1753,7 +1753,7 @@ static void kmemleak_scan_task_stacks(void) }put_task_struct (p); } -cond_resched (); +cond_resched_tasks_rcu_qs (); }while (pid && !stop); }@@ -1935,7 +1935,7 @@ static int __kmemleak_scan(bool full)struct page *page =pfn_to_online_page (pfn);if (!(pfn &63 )) -cond_resched (); +cond_resched_tasks_rcu_qs ();if (!page)continue ; ---base-commit:
0718283ab28bc3907e10b61a6b4be6fefa1cbb2f
change-id: 20260720-kmemleak_rcu_task-6d3ea111b947Best regards,
Signature · 1 line
Breno Leitao <[email protected]>
Andrew Morton
maintainerQuoted 21 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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
Quoted 8 lines
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: Haveosnoise_main()add a quiescent state for task rcu").
I'll add
.
.
Quoted 29 lines · Andrew Morton
Quoted 27 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen 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.
Quoted 7 lines
Quoted 2 lines
Inspired by commit
b96285e10aad("tracing: Haveosnoise_main()add a quiescent state for task rcu").I'll add
Fixes c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")Cc <[email protected]>
Thanks to all three of you!
This adds fewer than ten calls to cond_resched_tasks_rcu_qs(), but still more than doubles the number of such calls outside of the RCU subsystem.
Which is most likely just fine, and in any case absolutely should not get in the way of Breno's patch, which after all solves a real problem in the here and now.
Nevertheless, on the off-chance that over the next few months or years we start playing cond_resched_tasks_rcu_qs() whack-a-mole, I figured it would be good to get a head start on writing up alternatives. An initial draft may be found here:
https://docs.google.com/document/d/1s3fn29SCTYVw9jak4iraNIVQR59Wk5C6_I-_eu-MfQA/edit?usp=sharing
TL;DR: Should we get into a rousing game of whack-a-mole, alternatives include continuing as we are, making the existing calls to cond_resched() in turn call cond_resched_tasks_rcu_qs(), decoupling mutex-induced hung-task warnings from synchronize_rcu_tasks(), and various not-so-practical alternatives to RCU Tasks for trampoline synchronization.
Thoughts? Especially thoughts on other schemes?
Thanx, Paul
Hello Paul,
Quoted 54 lines · Paul E. McKenney
Quoted 29 lines · Andrew Morton
Quoted 27 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen 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.Quoted 7 lines
Quoted 2 lines
Inspired by commit
b96285e10aad("tracing: Haveosnoise_main()add a quiescent state for task rcu").I'll add
Fixes c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")Cc <[email protected]>Thanks to all three of you!
This adds fewer than ten calls to
cond_resched_tasks_rcu_qs(), but still more than doubles the number of such calls outside of the RCU subsystem.Which is most likely just fine, and in any case absolutely should not get in the way of Breno's patch, which after all solves a real problem in the here and now.
Nevertheless, on the off-chance that over the next few months or years we start playing
cond_resched_tasks_rcu_qs()whack-a-mole, I figured it would be good to get a head start on writing up alternatives. An initial draft may be found here:https://docs.google.com/document/d/1s3fn29SCTYVw9jak4iraNIVQR59Wk5C6_I-_eu-MfQA/edit?usp=sharing
Quoted 7 lines
TL;DR: Should we get into a rousing game of whack-a-mole, alternatives include continuing as we are, making the existing calls to
cond_resched()in turn callcond_resched_tasks_rcu_qs(), decoupling mutex-induced hung-task warnings fromsynchronize_rcu_tasks(), and various not-so-practical alternatives to RCU Tasks for trampoline synchronization.Thoughts? Especially thoughts on other schemes?
While debugging this issue, I was surprised to discover that cond_resched() doesn't provide RCU-tasks quiescent states. That led me to cond_resched_tasks_rcu_qs(), which is the stronger primitive needed for long-running kernel threads like kmemleak_scan(). Is this the common case for cond_resched()? I got the impression that kmemleak is the extreme side, but, I have no data on this.
Worth noting that commit 7dadeaa6e851e7 ("sched: Further restrict the preemption modes") continues to narrow PREEMPT_NONE, so the future of cond_resched() itself may be uncertain, no?
Quoted 63 lines · Breno Leitao
Hello Paul,
Quoted 60 lines · Paul E. McKenney
Quoted 29 lines · Andrew Morton
Quoted 27 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen 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.Quoted 7 lines
Quoted 2 lines
Inspired by commit
b96285e10aad("tracing: Haveosnoise_main()add a quiescent state for task rcu").I'll add
Fixes c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")Cc <[email protected]>Thanks to all three of you!
This adds fewer than ten calls to
cond_resched_tasks_rcu_qs(), but still more than doubles the number of such calls outside of the RCU subsystem.Which is most likely just fine, and in any case absolutely should not get in the way of Breno's patch, which after all solves a real problem in the here and now.
Nevertheless, on the off-chance that over the next few months or years we start playing
cond_resched_tasks_rcu_qs()whack-a-mole, I figured it would be good to get a head start on writing up alternatives. An initial draft may be found here:https://docs.google.com/document/d/1s3fn29SCTYVw9jak4iraNIVQR59Wk5C6_I-_eu-MfQA/edit?usp=sharing
TL;DR: Should we get into a rousing game of whack-a-mole, alternatives include continuing as we are, making the existing calls to
cond_resched()in turn callcond_resched_tasks_rcu_qs(), decoupling mutex-induced hung-task warnings fromsynchronize_rcu_tasks(), and various not-so-practical alternatives to RCU Tasks for trampoline synchronization.
Quoted 8 lines
Quoted 1 line
Thoughts? Especially thoughts on other schemes?
While debugging this issue, I was surprised to discover that
cond_resched()doesn't provide RCU-tasks quiescent states. That led me tocond_resched_tasks_rcu_qs(), which is the stronger primitive needed for long-running kernel threads likekmemleak_scan(). Is this the common case forcond_resched()? I got the impression that kmemleak is the extreme side, but, I have no data on this.
And that discovery did in fact lead you correctly, and hence my giving you a Reviewed-by.
Quoted 3 lines
Worth noting that commit
7dadeaa6e851e7("sched: Further restrict the preemption modes") continues to narrowPREEMPT_NONE, so the future ofcond_resched()itself may be uncertain, no?
Especially given that one of the explicitly stated goals of lazy preemption was in fact to eliminate cond_resched(). ;-)
Getting back to your point about kmemleak possibly being extreme, as far as I know, none of us have data on how many conversions of cond_resched() to cond_resched_tasks_rcu_qs() will be required, or, for that matter, how many additions of cond_resched_tasks_rcu_qs() above and beyond current cond_resched() instances will be required.
There were concerns raised off-list, so I figured that it was time to lay out what we do know, hence the above gdoc. I very much hope that we don't need many more calls to cond_resched_tasks_rcu_qs(), and thus that the time I spent writing that turns out to be wasted time. But better safe than sorry!
Thanx, Paul
Quoted 80 lines · Paul E. McKenney
Quoted 63 lines · Breno Leitao
Hello Paul,
Quoted 60 lines · Paul E. McKenney
Quoted 29 lines · Andrew Morton
Quoted 27 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen 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.Quoted 7 lines
Quoted 2 lines
Inspired by commit
b96285e10aad("tracing: Haveosnoise_main()add a quiescent state for task rcu").I'll add
Fixes c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")Cc <[email protected]>G
Thanks to all three of you!This adds fewer than ten calls to
cond_resched_tasks_rcu_qs(), but still more than doubles the number of such calls outside of the RCU subsystem.Which is most likely just fine, and in any case absolutely should not get in the way of Breno's patch, which after all solves a real problem in the here and now.
Nevertheless, on the off-chance that over the next few months or years we start playing
cond_resched_tasks_rcu_qs()whack-a-mole, I figured it would be good to get a head start on writing up alternatives. An initial draft may be found here:https://docs.google.com/document/d/1s3fn29SCTYVw9jak4iraNIVQR59Wk5C6_I-_eu-MfQA/edit?usp=sharing
TL;DR: Should we get into a rousing game of whack-a-mole, alternatives include continuing as we are, making the existing calls to
cond_resched()in turn callcond_resched_tasks_rcu_qs(), decoupling mutex-induced hung-task warnings fromsynchronize_rcu_tasks(), and various not-so-practical alternatives to RCU Tasks for trampoline synchronization.Quoted 8 lines
Quoted 1 line
Thoughts? Especially thoughts on other schemes?
While debugging this issue, I was surprised to discover that
cond_resched()doesn't provide RCU-tasks quiescent states. That led me tocond_resched_tasks_rcu_qs(), which is the stronger primitive needed for long-running kernel threads likekmemleak_scan(). Is this the common case forcond_resched()? I got the impression that kmemleak is the extreme side, but, I have no data on this.And that discovery did in fact lead you correctly, and hence my giving you a Reviewed-by.
Quoted 3 lines
Worth noting that commit
7dadeaa6e851e7("sched: Further restrict the preemption modes") continues to narrowPREEMPT_NONE, so the future ofcond_resched()itself may be uncertain, no?
Quoted 8 lines
Especially given that one of the explicitly stated goals of lazy preemption was in fact to eliminate
cond_resched(). ;-)Getting back to your point about kmemleak possibly being extreme, as far as I know, none of us have data on how many conversions of
cond_resched()tocond_resched_tasks_rcu_qs()will be required, or, for that matter, how many additions ofcond_resched_tasks_rcu_qs()above and beyond currentcond_resched()instances will be required.
I've searched for "rcu_tasks detected stalls on tasks" on Meta's fleet "dmesg depot" and I was suprised to see we have many of them, in which seems to be on hypervisor workloads (running VMs).
Quoted 5 lines
There were concerns raised off-list, so I figured that it was time to lay out what we do know, hence the above gdoc. I very much hope that we don't need many more calls to
cond_resched_tasks_rcu_qs(), and thus that the time I spent writing that turns out to be wasted time. But better safe than sorry!
The document was not a waste of time. it helped people like me to understand what the issue is, and what are the decisions we have ahead of us.
Back to what is the best decision/design, I honestly don't have an opinion, but I am happy to get more data about Meta production servers to help with the decision.
Quoted 90 lines · Breno Leitao
Quoted 80 lines · Paul E. McKenney
Quoted 63 lines · Breno Leitao
Hello Paul,
Quoted 60 lines · Paul E. McKenney
Quoted 29 lines · Andrew Morton
Quoted 27 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen 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.Quoted 7 lines
Quoted 2 lines
Inspired by commit
b96285e10aad("tracing: Haveosnoise_main()add a quiescent state for task rcu").I'll add
Fixes c4b28963fd79 ("mm/kmemleak: rely on rcu for task stack scanning")Cc <[email protected]>G
Thanks to all three of you!This adds fewer than ten calls to
cond_resched_tasks_rcu_qs(), but still more than doubles the number of such calls outside of the RCU subsystem.Which is most likely just fine, and in any case absolutely should not get in the way of Breno's patch, which after all solves a real problem in the here and now.
Nevertheless, on the off-chance that over the next few months or years we start playing
cond_resched_tasks_rcu_qs()whack-a-mole, I figured it would be good to get a head start on writing up alternatives. An initial draft may be found here:https://docs.google.com/document/d/1s3fn29SCTYVw9jak4iraNIVQR59Wk5C6_I-_eu-MfQA/edit?usp=sharing
TL;DR: Should we get into a rousing game of whack-a-mole, alternatives include continuing as we are, making the existing calls to
cond_resched()in turn callcond_resched_tasks_rcu_qs(), decoupling mutex-induced hung-task warnings fromsynchronize_rcu_tasks(), and various not-so-practical alternatives to RCU Tasks for trampoline synchronization.Quoted 8 lines
Quoted 1 line
Thoughts? Especially thoughts on other schemes?
While debugging this issue, I was surprised to discover that
cond_resched()doesn't provide RCU-tasks quiescent states. That led me tocond_resched_tasks_rcu_qs(), which is the stronger primitive needed for long-running kernel threads likekmemleak_scan(). Is this the common case forcond_resched()? I got the impression that kmemleak is the extreme side, but, I have no data on this.And that discovery did in fact lead you correctly, and hence my giving you a Reviewed-by.
Quoted 3 lines
Worth noting that commit
7dadeaa6e851e7("sched: Further restrict the preemption modes") continues to narrowPREEMPT_NONE, so the future ofcond_resched()itself may be uncertain, no?Quoted 8 lines
Especially given that one of the explicitly stated goals of lazy preemption was in fact to eliminate
cond_resched(). ;-)Getting back to your point about kmemleak possibly being extreme, as far as I know, none of us have data on how many conversions of
cond_resched()tocond_resched_tasks_rcu_qs()will be required, or, for that matter, how many additions ofcond_resched_tasks_rcu_qs()above and beyond currentcond_resched()instances will be required.
Quoted 3 lines
I've searched for "
rcu_tasksdetected stalls on tasks" on Meta's fleet "dmesg depot" and I was suprised to see we have many of them, in which seems to be on hypervisor workloads (running VMs).
Good to know! There have been experiments in the past with hinting to the hypervisor that a given vCPU could really use some CPU time, but the result has usually instead been a more targeted fix.
Quoted 6 lines
Quoted 5 lines
There were concerns raised off-list, so I figured that it was time to lay out what we do know, hence the above gdoc. I very much hope that we don't need many more calls to
cond_resched_tasks_rcu_qs(), and thus that the time I spent writing that turns out to be wasted time. But better safe than sorry!
Quoted 7 lines
The document was not a waste of time. it helped people like me to understand what the issue is, and what are the decisions we have ahead of us.
Back to what is the best decision/design, I honestly don't have an opinion, but I am happy to get more data about Meta production servers to help with the decision.
Looking forward to seeing what you come up with!
Thanx, Paul
Quoted 9 lines
Quoted 7 lines
The document was not a waste of time. it helped people like me to understand what the issue is, and what are the decisions we have ahead of us.
Back to what is the best decision/design, I honestly don't have an opinion, but I am happy to get more data about Meta production servers to help with the decision.
Looking forward to seeing what you come up with!
I found 3 different cases on Meta fleet, where rcu task stalls show up:
1) kmemleak -> This patch solves it
2) KVM / kcompactd
* Holdout: kcompactd0 (pid 1216), state:R, nvcsw frozen at 716336/716336 across three reports 10 min apart (stuck ≥20 min in one compaction pass)
* This is coming from: migrate_pages ->
kvm_mmu_notifier_invalidate_range_start -> tdp_mmu_next_root -> tdp_mmu_zap_leafs
3) Nvidia driver
* stuck in nv_procfs_read_lock_params
Given we can't do much about 3) and 1) is now closed, I will spend some time geting more data and possible a fix for 2.
Quoted 18 lines · Breno Leitao
Quoted 9 lines
Quoted 7 lines
The document was not a waste of time. it helped people like me to understand what the issue is, and what are the decisions we have ahead of us.
Back to what is the best decision/design, I honestly don't have an opinion, but I am happy to get more data about Meta production servers to help with the decision.
Looking forward to seeing what you come up with!
I found 3 different cases on Meta fleet, where rcu task stalls show up:
1) kmemleak -> This patch solves it
2) KVM / kcompactd
* Holdout: kcompactd0 (pid 1216), state:R, nvcsw frozen at 716336/716336 across three reports 10 min apart (stuck ≥20 min in one compaction pass)
* This is coming from:migrate_pages->
Quoted 8 lines
kvm_mmu_notifier_invalidate_range_start -> tdp_mmu_next_root -> tdp_mmu_zap_leafs3) Nvidia driver
* stuck innv_procfs_read_lock_paramsGiven we can't do much about 3) and 1) is now closed, I will spend some time geting more data and possible a fix for 2.
Quick update about item number 2), I've investigated and found that migrate_pages_batch() unmaps each folio before moving it, and every unmap runs the mmu_notifier invalidate callbacks. On KVM hosts try_to_migrate() ends up in kvm_mmu_notifier_invalidate_range_start() -> tdp_mmu_zap_leafs(), which is expensive. Patch at:
Quoted 1 line · Breno Leitao
I found 3 different cases on Meta fleet, where rcu task stalls show up:
...
Quoted 2 lines
3) Nvidia driver
* stuck innv_procfs_read_lock_params
I've investigated this issue. The nvidia driver contains the following locking pattern:
static inline int nv_down_read_interruptible(struct rw_semaphore *lock)
{
while (!down_read_trylock(lock))
{
if (signal_pending(current))
return -EINTR;
cond_resched();
}
return 0;
}The lock is never acquired, and cond_resched() provides insufficient scheduling relief.
This triggers a more severe issue with ftrace, which holds ftrace_lock across RCU synchronization:
mutex_lock(&ftrace_lock);
ftrace_shutdown(struct ftrace_ops *ops, int command) {
synchronize_rcu_tasks_rude();
synchronize_rcu_tasks();
}
mutex_unlock(&ftrace_lock);Since nv_down_read_interruptible() spins indefinitely, ftrace_lock now becomes completely wedged.
I suppose we want two things:
1) change cond_resched() with cond_resched_tasks_rcu_qs()
2) Avoiding holding the ftrace lock while calling synchronize_rcu_tasks()? It can take up to 10 minutes on a healthy system to be releasd, right?
--breno
Quoted 38 lines · Breno Leitao
Quoted 1 line · Breno Leitao
I found 3 different cases on Meta fleet, where rcu task stalls show up:
...
Quoted 2 lines
3) Nvidia driver
* stuck innv_procfs_read_lock_paramsI've investigated this issue. The nvidia driver contains the following locking pattern:
static inline int nv_down_read_interruptible(struct rw_semaphore *lock) { while (!down_read_trylock(lock)) { if (signal_pending(current)) return -EINTR; cond_resched(); } return 0; }The lock is never acquired, and
cond_resched()provides insufficient scheduling relief.This triggers a more severe issue with ftrace, which holds
ftrace_lockacross RCU synchronization:mutex_lock(&ftrace_lock); ftrace_shutdown(struct ftrace_ops *ops, int command) { synchronize_rcu_tasks_rude(); synchronize_rcu_tasks(); } mutex_unlock(&ftrace_lock);Since
nv_down_read_interruptible()spins indefinitely,ftrace_locknow becomes completely wedged.
Quoted 6 lines
I suppose we want two things:
1) change
cond_resched()withcond_resched_tasks_rcu_qs()
2) Avoiding holding the ftrace lock while callingsynchronize_rcu_tasks()? It can take up to 10 minutes on a healthy system to be releasd, right?
I do very much like both of those options. ;-)
If #2 is impossible, would it make sense to have a mutex_lock_idle() or similar in order to sanctify the lock synchronize_rcu_tasks() latencies?
Thanx, Paul
Quoted 11 lines · Paul E. McKenney
Quoted 6 lines
I suppose we want two things:
1) change
cond_resched()withcond_resched_tasks_rcu_qs()
2) Avoiding holding the ftrace lock while callingsynchronize_rcu_tasks()? It can take up to 10 minutes on a healthy system to be releasd, right?I do very much like both of those options. ;-)
If #2 is impossible, would it make sense to have a
mutex_lock_idle()or similar in order to sanctify the locksynchronize_rcu_tasks()latencies?
How would mutex_lock_idle() differ from a regular mutex_lock() when sanctifying synchronize_rcu_tasks() latencies?
Quoted 8 lines · Breno Leitao
Quoted 7 lines · Paul E. McKenney
Quoted 6 lines
I suppose we want two things:
1) change
cond_resched()withcond_resched_tasks_rcu_qs()
2) Avoiding holding the ftrace lock while callingsynchronize_rcu_tasks()? It can take up to 10 minutes on a healthy system to be releasd, right?
Quoted 7 lines
Quoted 4 lines
I do very much like both of those options. ;-)
If #2 is impossible, would it make sense to have a
mutex_lock_idle()or similar in order to sanctify the locksynchronize_rcu_tasks()latencies?How would
mutex_lock_idle()differ from a regularmutex_lock()when sanctifyingsynchronize_rcu_tasks()latencies?
It would sleep at TASK_IDLE instead of TASK_UNINTERRUPTIBLE, as shown below. This would cause it to be ignored for hung-task purposes.
For a similar example, RCU uses swait_event_idle_exclusive() instead of swait_event_exclusive() to avoid its grace-period kthread getting a hung-task warning when the system doesn't need a grace period for more than two minutes.
Yes, I did learn about this the hard way. Why do you ask? ;-)
The downside is that if some bug somewhere else under one of these mutexes caused a too-long sleep, that too-long sleep would be silently ignored. As always, choose wisely!
Thanx, Paul
------------------------------------------------------------------------
static noinline void __sched__mutex_lock_slowpath_idle(struct mutex *lock)
__acquires(lock)
{
__mutex_lock(lock, TASK_IDLE, 0, NULL, _RET_IP_);
__acquire(lock);
}Quoted 8 lines · Breno Leitao
I found 3 different cases on Meta fleet, where rcu task stalls show up:
1) kmemleak -> This patch solves it
2) KVM / kcompactd
* Holdout: kcompactd0 (pid 1216), state:R, nvcsw frozen at 716336/716336 across three reports 10 min apart (stuck ≥20 min in one compaction pass)
* This is coming from:migrate_pages->
Quoted 5 lines
kvm_mmu_notifier_invalidate_range_start -> tdp_mmu_next_root -> tdp_mmu_zap_leafs3) Nvidia driver
* stuck innv_procfs_read_lock_params
I've found an additional one:
4) While shrinking in reclaim:
INFO: rcu_tasks detected stalls on tasks: 0000000088620d09: .. nvcsw: 6735/6735 holdout: 1 idle_cpu: -1/8 task:GlobalCPUThread state:R running task pid:2552016 tgid:2524552 Call Trace: shrink_lruvec mem_cgroup_iter shrink_node
I've proposing promoting cond_resched() to cond_resched_tasks_rcu_qs():
https://lore.kernel.org/all/[email protected]/
Quoted 21 lines · On Mon, 20 Jul 2026 06:23:45 -0700 Breno Leitao <[email protected]> wrote:
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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
Quoted 8 lines
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: Haveosnoise_main()add a quiescent state for task rcu").
Makes sense to me.
Quoted 2 lines
Signed-off-by Breno Leitao <[email protected]>
Thanks,
SJ
[...]
Quoted 24 lines · Breno Leitao
kmemleak_scan()can run for ages on large debug kernels. It was causing some soft-lockups which I got fixed with commit3175fcfec8b16baeb("mm/kmemleak: avoid soft lockup when scanning task stacks") with our belovedcond_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_scanand, worse, blocks the callers waiting on that grace period. Here a BPF
struct_opsmap free, which waits viasynchronize_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_freeThen I've learned that
cond_resched()is not an RCU-tasks quiescent state, so, we need to use stronger primitives.
Quoted 7 lines
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: Haveosnoise_main()add a quiescent state for task rcu").Signed-off-by Breno Leitao <[email protected]>
In case Andrew still need a tag: