aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/smpboot.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2015-07-05 13:12:32 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-07-07 05:54:04 -0400
commit5a3f75e3f02836518ce49536e9c460ca8e1fa290 (patch)
treed789e3eea0d8e334c6b702e415450ea75b5d4e1a /arch/x86/kernel/smpboot.c
parent827a82ff399523a954253dfea401af748640f0f4 (diff)
x86/irq: Plug irq vector hotplug race
Jin debugged a nasty cpu hotplug race which results in leaking a irq vector on the newly hotplugged cpu. cpu N cpu M native_cpu_up device_shutdown do_boot_cpu free_msi_irqs start_secondary arch_teardown_msi_irqs smp_callin default_teardown_msi_irqs setup_vector_irq arch_teardown_msi_irq __setup_vector_irq native_teardown_msi_irq lock(vector_lock) destroy_irq install vectors unlock(vector_lock) lock(vector_lock) ---> __clear_irq_vector unlock(vector_lock) lock(vector_lock) set_cpu_online unlock(vector_lock) This leaves the irq vector(s) which are torn down on CPU M stale in the vector array of CPU N, because CPU M does not see CPU N online yet. There is a similar issue with concurrent newly setup interrupts. The alloc/free protection of irq descriptors does not prevent the above race, because it merily prevents interrupt descriptors from going away or changing concurrently. Prevent this by moving the call to setup_vector_irq() into the vector_lock held region which protects set_cpu_online(): cpu N cpu M native_cpu_up device_shutdown do_boot_cpu free_msi_irqs start_secondary arch_teardown_msi_irqs smp_callin default_teardown_msi_irqs lock(vector_lock) arch_teardown_msi_irq setup_vector_irq() __setup_vector_irq native_teardown_msi_irq install vectors destroy_irq set_cpu_online unlock(vector_lock) lock(vector_lock) __clear_irq_vector unlock(vector_lock) So cpu M either sees the cpu N online before clearing the vector or cpu N installs the vectors after cpu M has cleared it. Reported-by: xiao jin <jin.xiao@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Joerg Roedel <jroedel@suse.de> Cc: Borislav Petkov <bp@suse.de> Cc: Yanmin Zhang <yanmin_zhang@linux.intel.com> Link: http://lkml.kernel.org/r/20150705171102.141898931@linutronix.de
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r--arch/x86/kernel/smpboot.c13
1 files changed, 5 insertions, 8 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 0bd8c1d507b3..d3010aa79daf 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -171,11 +171,6 @@ static void smp_callin(void)
171 apic_ap_setup(); 171 apic_ap_setup();
172 172
173 /* 173 /*
174 * Need to setup vector mappings before we enable interrupts.
175 */
176 setup_vector_irq(smp_processor_id());
177
178 /*
179 * Save our processor parameters. Note: this information 174 * Save our processor parameters. Note: this information
180 * is needed for clock calibration. 175 * is needed for clock calibration.
181 */ 176 */
@@ -239,11 +234,13 @@ static void notrace start_secondary(void *unused)
239 check_tsc_sync_target(); 234 check_tsc_sync_target();
240 235
241 /* 236 /*
242 * We need to hold vector_lock so there the set of online cpus 237 * Lock vector_lock and initialize the vectors on this cpu
243 * does not change while we are assigning vectors to cpus. Holding 238 * before setting the cpu online. We must set it online with
244 * this lock ensures we don't half assign or remove an irq from a cpu. 239 * vector_lock held to prevent a concurrent setup/teardown
240 * from seeing a half valid vector space.
245 */ 241 */
246 lock_vector_lock(); 242 lock_vector_lock();
243 setup_vector_irq(smp_processor_id());
247 set_cpu_online(smp_processor_id(), true); 244 set_cpu_online(smp_processor_id(), true);
248 unlock_vector_lock(); 245 unlock_vector_lock();
249 cpu_set_state_online(smp_processor_id()); 246 cpu_set_state_online(smp_processor_id());