From: Ashok Raj <ashok.raj@intel.com>

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 <ashok.raj@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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);
_