[PATCH v2] rcu: fix shrink budget underflow in lazy_rcu_shrink_scan

From: Longlong Xia

Date: Wed Aug 26 2026 - 04:24:17 EST


From: Longlong Xia <xialonglong@xxxxxxxxxx>

The lazy RCU shrinker decremented sc->nr_to_scan (unsigned long)
and then tested the result with <= 0. When a single CPU's lazy
callback count exceeds the remaining budget, the subtraction wraps
to a large positive value and the <= 0 comparison, which is
equivalent to == 0 for an unsigned type, never fires again. The
scan loop then iterates through every nocb CPU instead of honouring
the reclaim budget.

Accumulate into count and stop once count >= nr_to_scan.

Fixes: c945b4da7a448 ("rcu: Shrinker for lazy rcu")
Assisted-by: Zcode:GLM-5.2
Signed-off-by: Longlong Xia <xialonglong@xxxxxxxxxx>
---
Changes in v2:
- Rework to accumulate into count directly and compare count >= nr_to_scan
instead of decrementing nr_to_scan, matching the kfree_rcu_shrink_scan()
fix reworked per Hao Li's suggestion.

Link: https://lore.kernel.org/all/20260824133142.2293426-1-xialonglong2025@xxxxxxx/
---
kernel/rcu/tree_nocb.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index 19bb42672baf..b6cfee4e5039 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -1332,9 +1332,8 @@ lazy_rcu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
rcu_nocb_try_flush_bypass(rdp, jiffies);
rcu_nocb_unlock_irqrestore(rdp, flags);
wake_nocb_gp(rdp);
- sc->nr_to_scan -= _count;
count += _count;
- if (sc->nr_to_scan <= 0)
+ if (count >= sc->nr_to_scan)
break;
}

--
2.43.0