Skip to content

Commit cf4fc66

Browse files
Joel Fernandespaulmckrcu
authored andcommitted
smp: Document preemption and stop_machine() mutual exclusion
Recently while revising RCU's cpu online checks, there was some discussion around how IPIs synchronize with hotplug. Add comments explaining how preemption disable creates mutual exclusion with CPU hotplug's stop_machine mechanism. The key insight is that stop_machine() atomically updates CPU masks and flushes IPIs with interrupts disabled, and cannot proceed while any CPU (including the IPI sender) has preemption disabled. [ Apply peterz feedback. ] Cc: Andrea Righi <[email protected]> Cc: Paul E. McKenney <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: Peter Zijlstra (Intel) <[email protected]> Cc: [email protected] Acked-by: Paul E. McKenney <[email protected]> Co-developed-by: Frederic Weisbecker <[email protected]> Signed-off-by: Joel Fernandes <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent fc6f89d commit cf4fc66

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

kernel/smp.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ int smpcfd_dead_cpu(unsigned int cpu)
8686
int smpcfd_dying_cpu(unsigned int cpu)
8787
{
8888
/*
89-
* The IPIs for the smp-call-function callbacks queued by other
90-
* CPUs might arrive late, either due to hardware latencies or
91-
* because this CPU disabled interrupts (inside stop-machine)
92-
* before the IPIs were sent. So flush out any pending callbacks
93-
* explicitly (without waiting for the IPIs to arrive), to
94-
* ensure that the outgoing CPU doesn't go offline with work
95-
* still pending.
89+
* The IPIs for the smp-call-function callbacks queued by other CPUs
90+
* might arrive late, either due to hardware latencies or because this
91+
* CPU disabled interrupts (inside stop-machine) before the IPIs were
92+
* sent. So flush out any pending callbacks explicitly (without waiting
93+
* for the IPIs to arrive), to ensure that the outgoing CPU doesn't go
94+
* offline with work still pending.
95+
*
96+
* This runs with interrupts disabled inside the stopper task invoked by
97+
* stop_machine(), ensuring mutually exclusive CPU offlining and IPI flush.
9698
*/
9799
__flush_smp_call_function_queue(false);
98100
irq_work_run();
@@ -418,6 +420,10 @@ void __smp_call_single_queue(int cpu, struct llist_node *node)
418420
*/
419421
static int generic_exec_single(int cpu, call_single_data_t *csd)
420422
{
423+
/*
424+
* Preemption already disabled here so stopper cannot run on this CPU,
425+
* ensuring mutually exclusive CPU offlining and last IPI flush.
426+
*/
421427
if (cpu == smp_processor_id()) {
422428
smp_call_func_t func = csd->func;
423429
void *info = csd->info;
@@ -638,8 +644,10 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
638644
int err;
639645

640646
/*
641-
* prevent preemption and reschedule on another processor,
642-
* as well as CPU removal
647+
* Prevent preemption and reschedule on another CPU, as well as CPU
648+
* removal. This prevents stopper from running on this CPU, thus
649+
* providing mutual exclusion of the below cpu_online() check and
650+
* IPI sending ensuring IPI are not missed by CPU going offline.
643651
*/
644652
this_cpu = get_cpu();
645653

0 commit comments

Comments
 (0)