* [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
@ 2026-08-03 12:30 Chen Jinghuang
2026-08-04 5:09 ` K Prateek Nayak
0 siblings, 1 reply; 5+ messages in thread
From: Chen Jinghuang @ 2026-08-03 12:30 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Paolo Bonzini
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, linux-kernel
While fuzzing with syzkaller, a concurrent 1/0 write race to
/proc/sys/kernel/numa_balancing was found that trips a jump_label
WARN_ON_ONCE().
Concurrent writes of 1/0 to /proc/sys/kernel/numa_balancing enable/disable
the same static key. Enable sets key->enabled to -1 while holding the
lock, restoring it to 1 only after jump_label_update(); disable checks
enabled before taking the lock. Under concurrency, disable reads -1 and
trips WARN_ON_ONCE().
Timeline:
write 1 → enable write 0 → disable
│ │
├─ static_key_enable_cpuslocked() ├─ static_key_disable_cpuslocked()
│ jump_label_lock() │ atomic_read(enabled) ← before lock
│ atomic_set(enabled, -1) ◄───────┼── reads -1
│ jump_label_update() │ WARN_ON_ONCE(enabled!=0)
│ atomic_set_release(enabled,1) │ return ← disable skipped
│ jump_label_unlock() │
Serialize the enable/disable switch at the convergence point in
set_numabalancing_state() with a mutex, so the transient -1 in
key->enabled never leaks to a concurrent disable and this WARN_ON_ONCE
no longer trips.
This follows existing kernel practice, e.g. timer_key_mutex guarding
timers_update_migration() (kernel/time/timer.c) and perf_sched_mutex
guarding static_branch_enable() (kernel/events/core.c).
Fixes: 1dbb6704de91 ("jump_label: Fix concurrent static_key_enable/disable()")
Reported-by: Zhang zhaotian <zhangzhaotian@h-partners.com>
Signed-off-by: Chen Jinghuang <chenjinghuang2@huawei.com>
---
kernel/sched/core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 96226707c2f6..61fb0d7966e4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4629,13 +4629,17 @@ static void __set_numabalancing_state(bool enabled)
static_branch_disable(&sched_numa_balancing);
}
+static DEFINE_MUTEX(numabalancing_mutex);
+
void set_numabalancing_state(bool enabled)
{
+ mutex_lock(&numabalancing_mutex);
if (enabled)
sysctl_numa_balancing_mode = NUMA_BALANCING_NORMAL;
else
sysctl_numa_balancing_mode = NUMA_BALANCING_DISABLED;
__set_numabalancing_state(enabled);
+ mutex_unlock(&numabalancing_mutex);
}
#ifdef CONFIG_PROC_SYSCTL
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
2026-08-03 12:30 [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key Chen Jinghuang
@ 2026-08-04 5:09 ` K Prateek Nayak
2026-08-04 8:35 ` chenjinghuang
0 siblings, 1 reply; 5+ messages in thread
From: K Prateek Nayak @ 2026-08-04 5:09 UTC (permalink / raw)
To: Chen Jinghuang, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Paolo Bonzini
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, linux-kernel
Hell Chen,
On 8/3/2026 6:00 PM, Chen Jinghuang wrote:
> +static DEFINE_MUTEX(numabalancing_mutex);
> +
> void set_numabalancing_state(bool enabled)
> {
> + mutex_lock(&numabalancing_mutex);
> if (enabled)
> sysctl_numa_balancing_mode = NUMA_BALANCING_NORMAL;
> else
> sysctl_numa_balancing_mode = NUMA_BALANCING_DISABLED;
> __set_numabalancing_state(enabled);
> + mutex_unlock(&numabalancing_mutex);
> }
Doesn't sysctl_numa_balancing() directly call __set_numabalancing_state()
and this bit is only used by check_numabalancing_enable() on the mm side
during early init?
I think you should move this serialization into sysctl_numa_balancing()
because nothing can race during early init and we only need this for sysfs
writes.
--
Thanks and Regards,
Prateek
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
2026-08-04 5:09 ` K Prateek Nayak
@ 2026-08-04 8:35 ` chenjinghuang
2026-08-04 8:44 ` K Prateek Nayak
0 siblings, 1 reply; 5+ messages in thread
From: chenjinghuang @ 2026-08-04 8:35 UTC (permalink / raw)
To: K Prateek Nayak, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Paolo Bonzini
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, linux-kernel
On 8/4/2026 1:09 PM, K Prateek Nayak wrote:
> Hell Chen,
>
> On 8/3/2026 6:00 PM, Chen Jinghuang wrote:
>> +static DEFINE_MUTEX(numabalancing_mutex);
>> +
>> void set_numabalancing_state(bool enabled)
>> {
>> + mutex_lock(&numabalancing_mutex);
>> if (enabled)
>> sysctl_numa_balancing_mode = NUMA_BALANCING_NORMAL;
>> else
>> sysctl_numa_balancing_mode = NUMA_BALANCING_DISABLED;
>> __set_numabalancing_state(enabled);
>> + mutex_unlock(&numabalancing_mutex);
>> }
>
> Doesn't sysctl_numa_balancing() directly call __set_numabalancing_state()
> and this bit is only used by check_numabalancing_enable() on the mm side
> during early init?
>
> I think you should move this serialization into sysctl_numa_balancing()
> because nothing can race during early init and we only need this for sysfs
> writes.
>
You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
and drop it from the early-init path. No one races during init, so the lock is only
needed for sysfs writes:
+static DEFINE_MUTEX(numabalancing_mutex);
+
static int sysctl_numa_balancing(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
@@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
if (err < 0)
return err;
if (write) {
+ mutex_lock(&numabalancing_mutex);
if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
(state & NUMA_BALANCING_MEMORY_TIERING))
reset_memory_tiering();
sysctl_numa_balancing_mode = state;
__set_numabalancing_state(state);
+ mutex_unlock(&numabalancing_mutex);
}
return err;
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
2026-08-04 8:35 ` chenjinghuang
@ 2026-08-04 8:44 ` K Prateek Nayak
2026-08-04 8:52 ` chenjinghuang
0 siblings, 1 reply; 5+ messages in thread
From: K Prateek Nayak @ 2026-08-04 8:44 UTC (permalink / raw)
To: chenjinghuang, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Paolo Bonzini
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, linux-kernel
Hello Chen,
On 8/4/2026 2:05 PM, chenjinghuang wrote:
> You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
> and drop it from the early-init path. No one races during init, so the lock is only
> needed for sysfs writes:
>
> +static DEFINE_MUTEX(numabalancing_mutex);
> +
> static int sysctl_numa_balancing(const struct ctl_table *table, int write,
> void *buffer, size_t *lenp, loff_t *ppos)
> {
> @@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
> if (err < 0)
> return err;
> if (write) {
> + mutex_lock(&numabalancing_mutex);
nit. You can just use a:
guard(mutex)(&numabalancing_mutex);
> if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
> (state & NUMA_BALANCING_MEMORY_TIERING))
> reset_memory_tiering();
> sysctl_numa_balancing_mode = state;
> __set_numabalancing_state(state);
> + mutex_unlock(&numabalancing_mutex);
... and save on the need to explicitly call unlock here.
> }
> return err;
> }
--
Thanks and Regards,
Prateek
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key
2026-08-04 8:44 ` K Prateek Nayak
@ 2026-08-04 8:52 ` chenjinghuang
0 siblings, 0 replies; 5+ messages in thread
From: chenjinghuang @ 2026-08-04 8:52 UTC (permalink / raw)
To: K Prateek Nayak, Ingo Molnar, Peter Zijlstra, Juri Lelli,
Vincent Guittot, Paolo Bonzini
Cc: Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, linux-kernel
On 8/4/2026 4:44 PM, K Prateek Nayak wrote:
> Hello Chen,
>
> On 8/4/2026 2:05 PM, chenjinghuang wrote:
>> You're right - my mistake, I'll move numabalancing_mutex into sysctl_numa_balancing()
>> and drop it from the early-init path. No one races during init, so the lock is only
>> needed for sysfs writes:
>>
>> +static DEFINE_MUTEX(numabalancing_mutex);
>> +
>> static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>> void *buffer, size_t *lenp, loff_t *ppos)
>> {
>> @@ -4666,11 +4668,13 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
>> if (err < 0)
>> return err;
>> if (write) {
>> + mutex_lock(&numabalancing_mutex);
>
> nit. You can just use a:
>
> guard(mutex)(&numabalancing_mutex);
>
>> if (!(sysctl_numa_balancing_mode & NUMA_BALANCING_MEMORY_TIERING) &&
>> (state & NUMA_BALANCING_MEMORY_TIERING))
>> reset_memory_tiering();
>> sysctl_numa_balancing_mode = state;
>> __set_numabalancing_state(state);
>> + mutex_unlock(&numabalancing_mutex);
>
> ... and save on the need to explicitly call unlock here.
>
>> }
>> return err;
>> }
>
Thanks Prateek, I'll update the patch accordingly.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-04 8:52 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-03 12:30 [PATCH] sched/numa: Prevent race on sysctl_numa_balancing static key Chen Jinghuang
2026-08-04 5:09 ` K Prateek Nayak
2026-08-04 8:35 ` chenjinghuang
2026-08-04 8:44 ` K Prateek Nayak
2026-08-04 8:52 ` chenjinghuang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®