History

Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fix from Thomas Gleixner: "A single fix for a cpu hotplug race vs. interrupt descriptors: Prevent irq setup/teardown across the cpu starting/dying parts of cpu hotplug so that the starting/dying cpu has a stable view of the descriptor space. This has been an issue for all architectures in the cpu dying phase, where interrupts are migrated away from the dying cpu. In the starting phase its mostly a x86 issue vs the vector space update" * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: hotplug: Prevent alloc/free of irq descriptors during cpu up/down

Linus Torvalds committed 11 years ago

Commit c4bc6802 parents 59c3cb5 a8994183 files · +27 −6Browse files

Unified · Split

3 files
  1. include/linux/irqdesc.h +6 −1
  2. kernel/cpu.c +21 −1
  3. kernel/irq/internals.h +0 −4
include/linux/irqdesc.h+6−1
@@ -87,7 +87,12 @@ struct irq_desc { · 86 unmodified lines
8787 const char *name;
8888 } ____cacheline_internodealigned_in_smp;
8989
90−#ifndef CONFIG_SPARSE_IRQ
90+#ifdef CONFIG_SPARSE_IRQ
91+extern void irq_lock_sparse(void);
92+extern void irq_unlock_sparse(void);
93+#else
94+static inline void irq_lock_sparse(void) { }
95+static inline void irq_unlock_sparse(void) { }
9196 extern struct irq_desc irq_desc[NR_IRQS];
9297 #endif
9398
kernel/cpu.c+21−1
@@ -21,6 +21,7 @@ · 20 unmodified lines
2121 #include <linux/suspend.h>
2222 #include <linux/lockdep.h>
2323 #include <linux/tick.h>
24+#include <linux/irq.h>
2425 #include <trace/events/power.h>
2526
2627 #include "smpboot.h"
@@ -392,13 +393,19 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) · 365 unmodified lines
392393 smpboot_park_threads(cpu);
393394
394395 /*
395− * So now all preempt/rcu users must observe !cpu_active().
396+ * Prevent irq alloc/free while the dying cpu reorganizes the
397+ * interrupt affinities.
396398 */
399+ irq_lock_sparse();
397400
401+ /*
402+ * So now all preempt/rcu users must observe !cpu_active().
403+ */
398404 err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
399405 if (err) {
400406 /* CPU didn't die: tell everyone. Can't complain. */
401407 cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
408+ irq_unlock_sparse();
402409 goto out_release;
403410 }
404411 BUG_ON(cpu_online(cpu));
@@ -415,6 +422,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) · 10 unmodified lines
415422 smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
416423 per_cpu(cpu_dead_idle, cpu) = false;
417424
425+ /* Interrupts are moved away from the dying cpu, reenable alloc/free */
426+ irq_unlock_sparse();
427+
418428 hotplug_cpu__broadcast_tick_pull(cpu);
419429 /* This actually kills the CPU. */
420430 __cpu_die(cpu);
@@ -517,8 +527,18 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) · 96 unmodified lines
517527 goto out_notify;
518528 }
519529
530+ /*
531+ * Some architectures have to walk the irq descriptors to
532+ * setup the vector space for the cpu which comes online.
533+ * Prevent irq alloc/free across the bringup.
534+ */
535+ irq_lock_sparse();
536+
520537 /* Arch-specific enabling code. */
521538 ret = __cpu_up(cpu, idle);
539+
540+ irq_unlock_sparse();
541+
522542 if (ret != 0)
523543 goto out_notify;
524544 BUG_ON(!cpu_online(cpu));
kernel/irq/internals.h+0−4
@@ -76,12 +76,8 @@ extern void unmask_threaded_irq(struct irq_desc *desc); · 75 unmodified lines
7676
7777 #ifdef CONFIG_SPARSE_IRQ
7878 static inline void irq_mark_irq(unsigned int irq) { }
79−extern void irq_lock_sparse(void);
80−extern void irq_unlock_sparse(void);
8179 #else
8280 extern void irq_mark_irq(unsigned int irq);
83−static inline void irq_lock_sparse(void) { }
84−static inline void irq_unlock_sparse(void) { }
8581 #endif
8682
8783 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);