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

Longlong Xia posted 1 patch 1 month ago
kernel/rcu/tree_nocb.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
[PATCH v2] rcu: fix shrink budget underflow in lazy_rcu_shrink_scan
Posted by Longlong Xia 1 month ago
From: Longlong Xia <xialonglong@kylinos.cn>

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@kylinos.cn>
---
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@163.com/
---
 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
Re: [PATCH v2] rcu: fix shrink budget underflow in lazy_rcu_shrink_scan
Posted by Paul E. McKenney 1 month ago
On Wed, Aug 26, 2026 at 04:21:50PM +0800, Longlong Xia wrote:
> From: Longlong Xia <xialonglong@kylinos.cn>
> 
> 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@kylinos.cn>

OK, I should have read ahead.

This one looks even more plausible, and quite a bit simpler.  I have
replaced your v1 with this patch.

Frederic, thoughts?

							Thanx, Paul

> ---
> 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@163.com/
> ---
>  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
>