Re: [PATCH] ratelimit: Fix data race on ->burst in ___ratelimit()

From: Paul E. McKenney

Date: Wed Nov 04 2026 - 12:59:31 EST


On Tue, Nov 03, 2026 at 04:29:54AM -0800, Breno Leitao wrote:
> I am seeing the following race on my debug kernels:
>
> BUG: KCSAN: data-race in ___ratelimit / do_proc_int_conv
>
> write (marked) to 0xffffffff83084544 of 4 bytes by task 186 on cpu 3:
> do_proc_int_conv+0x94/0xa0
> proc_vec+0x48a/0x8d0
> proc_dointvec+0x16/0x20
> proc_sys_call_handler+0x263/0x3b0
> proc_sys_write+0x13/0x20
> vfs_write+0x559/0x610
> __x64_sys_pwrite64+0xce/0x110
>
> read to 0xffffffff83084544 of 4 bytes by task 185 on cpu 1:
> ___ratelimit+0x137/0x3b0
> __printk_ratelimit+0x18/0x20
>
> value changed: 0x00000001 -> 0x00000000
>
> This could be reproduced by flipping kernel.printk_ratelimit_burst
> between 0 and 1 while a kthread calls __printk_ratelimit() in a loop
> makes KCSAN report:
>
> ___ratelimit() reads ->interval and ->burst once, with READ_ONCE(),
> because sysctl writes like the one above change them without taking
> rs->lock. Commit 6bae8ceb90ba ("ratelimit: Fix data-races in
> ___ratelimit().") added those snapshots.
>
> Refill rs_n_left from the snapshot instead, which is also the value
> the function has already checked to be positive.
>
> Fixes: cf8cfa8a9978 ("ratelimit: Reduce ___ratelimit() false-positive rate limiting")
> Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>

Because we have acquired a lock between times, this might get an old
version, but that can happen anyway and gets fixed on the next call.

Reviewed-by: Paul E. McKenney <paulmck@xxxxxxxxxx>

> ---
> lib/ratelimit.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/lib/ratelimit.c b/lib/ratelimit.c
> index e2d65d3b1c3545..d24864f12d871e 100644
> --- a/lib/ratelimit.c
> +++ b/lib/ratelimit.c
> @@ -67,7 +67,7 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
> if (!(rs->flags & RATELIMIT_INITIALIZED)) {
> rs->begin = jiffies;
> rs->flags |= RATELIMIT_INITIALIZED;
> - atomic_set(&rs->rs_n_left, rs->burst);
> + atomic_set(&rs->rs_n_left, burst);
> }
>
> if (time_is_before_jiffies(rs->begin + interval)) {
> @@ -77,7 +77,7 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
> * Reset rs_n_left ASAP to reduce false positives
> * in parallel calls, see above.
> */
> - atomic_set(&rs->rs_n_left, rs->burst);
> + atomic_set(&rs->rs_n_left, burst);
> rs->begin = jiffies;
>
> if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
>
> ---
> base-commit: 2637bdec0535a2044cd830eba9a79363651d9043
> base-tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
> change-id: 20261103-ratelimit_race-041f9bf78da1
>
> Best regards,
> --
> Breno Leitao <leitao@xxxxxxxxxx>
>