From: Ashok Raj Need to hold call_lock when setting cpu_online_map for a new cpu. __smp_call_function() reads num_cpus_online() to find out how many consumers to wait. These counts are done at different times, and unless we keep writes off cpu_online_map gaurded, these counts could be different. Worst case a new cpu would also participate, this basically keeps the new cpu off currently ongoing smp_call_functions(). Signed-off-by: Ashok Raj Signed-off-by: Andrew Morton --- arch/x86_64/kernel/smp.c | 10 ++++++++++ arch/x86_64/kernel/smpboot.c | 12 ++++++++++++ include/asm-x86_64/smp.h | 2 ++ 3 files changed, 24 insertions(+) diff -puN arch/x86_64/kernel/smpboot.c~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix arch/x86_64/kernel/smpboot.c --- 25/arch/x86_64/kernel/smpboot.c~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix Tue Jun 7 15:38:42 2005 +++ 25-akpm/arch/x86_64/kernel/smpboot.c Tue Jun 7 15:38:42 2005 @@ -508,9 +508,21 @@ void __cpuinit start_secondary(void) set_cpu_sibling_map(smp_processor_id()); /* + * We need to hold call_lock, so there is no inconsistency + * between the time smp_call_function() determines number of + * IPI receipients, and the time when the determination is made + * for which cpus receive the IPI in genapic_flat.c. Holding this + * lock helps us to not include this cpu in a currently in progress + * smp_call_function(). + */ + lock_ipi_call_lock(); + + /* * Allow the master to continue. */ cpu_set(smp_processor_id(), cpu_online_map); + unlock_ipi_call_lock(); + mb(); /* Wait for TSC sync to not schedule things before. diff -puN arch/x86_64/kernel/smp.c~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix arch/x86_64/kernel/smp.c --- 25/arch/x86_64/kernel/smp.c~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix Tue Jun 7 15:38:42 2005 +++ 25-akpm/arch/x86_64/kernel/smp.c Tue Jun 7 15:38:42 2005 @@ -283,6 +283,16 @@ struct call_data_struct { static struct call_data_struct * call_data; +void lock_ipi_call_lock(void) +{ + spin_lock_irq(&call_lock); +} + +void unlock_ipi_call_lock(void) +{ + spin_unlock_irq(&call_lock); +} + /* * this function sends a 'generic call function' IPI to all other CPUs * in the system. diff -puN include/asm-x86_64/smp.h~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix include/asm-x86_64/smp.h --- 25/include/asm-x86_64/smp.h~x86_64-dont-use-broadcast-shortcut-to-make-it-cpu-hotplug-safe-fix Tue Jun 7 15:38:42 2005 +++ 25-akpm/include/asm-x86_64/smp.h Tue Jun 7 15:38:42 2005 @@ -43,6 +43,8 @@ extern cpumask_t cpu_callout_map; extern void smp_alloc_memory(void); extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; +extern void lock_ipi_call_lock(void); +extern void unlock_ipi_call_lock(void); extern int smp_num_siblings; extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); _