Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cpu: Make atomic hotplug callbacks run with interrupts disabled on UP

On SMP systems the CPU hotplug callbacks in the "starting" range are
invoked while the CPU is brought up and interrupts are still
disabled. Callbacks which are added later are invoked via the
hotplug-thread on the target CPU and interrupts are explicitly disabled.

In the UP case callbacks which are added later are invoked directly without
the thread indirection. This is in principle okay since there is just one
CPU but those callbacks are invoked with interrupt disabled code. That's
incorrect as those callbacks assume interrupt disabled context.

Disable interrupts before invoking the callbacks on UP if the state is
atomic and interrupts are expected to be disabled. The "save" part is
required because this is also invoked early in the boot process while
interrupts are disabled and must not be enabled prematurely.

Fixes: 06ddd17521bf1 ("sched/smp: Always define is_percpu_thread() and scheduler_ipi()")
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://patch.msgid.link/20251127144723.ev9DuXXR@linutronix.de

authored by

Sebastian Andrzej Siewior and committed by
Thomas Gleixner
c9429191 cb015814

+16 -9
+16 -9
kernel/cpu.c
··· 249 249 return ret; 250 250 } 251 251 252 + /* 253 + * The former STARTING/DYING states, ran with IRQs disabled and must not fail. 254 + */ 255 + static bool cpuhp_is_atomic_state(enum cpuhp_state state) 256 + { 257 + return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; 258 + } 259 + 252 260 #ifdef CONFIG_SMP 253 261 static bool cpuhp_is_ap_state(enum cpuhp_state state) 254 262 { ··· 277 269 { 278 270 struct completion *done = bringup ? &st->done_up : &st->done_down; 279 271 complete(done); 280 - } 281 - 282 - /* 283 - * The former STARTING/DYING states, ran with IRQs disabled and must not fail. 284 - */ 285 - static bool cpuhp_is_atomic_state(enum cpuhp_state state) 286 - { 287 - return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; 288 272 } 289 273 290 274 /* Synchronization state management */ ··· 2364 2364 else 2365 2365 ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 2366 2366 #else 2367 - ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 2367 + if (cpuhp_is_atomic_state(state)) { 2368 + guard(irqsave)(); 2369 + ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 2370 + /* STARTING/DYING must not fail! */ 2371 + WARN_ON_ONCE(ret); 2372 + } else { 2373 + ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); 2374 + } 2368 2375 #endif 2369 2376 BUG_ON(ret && !bringup); 2370 2377 return ret;