Commit 61791244 authored by Russell King's avatar Russell King

ARM: irq migration: ensure migration is handled safely

Ensure appropriate locks are taken to ensure that IRQ migration off
the current CPU is race-free.  We may have a concurrent set_affinity
via procfs running on another CPU in parallel with the IRQ migration,
resulting in unpredictable results.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 1dbfa187
...@@ -179,14 +179,21 @@ int __init arch_probe_nr_irqs(void) ...@@ -179,14 +179,21 @@ int __init arch_probe_nr_irqs(void)
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) static bool migrate_one_irq(struct irq_data *d)
{ {
pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->irq_data.node, cpu); unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask);
bool ret = false;
raw_spin_lock_irq(&desc->lock); if (cpu >= nr_cpu_ids) {
desc->irq_data.chip->irq_set_affinity(&desc->irq_data, cpu = cpumask_any(cpu_online_mask);
cpumask_of(cpu), true); ret = true;
raw_spin_unlock_irq(&desc->lock); }
pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu);
d->chip->irq_set_affinity(d, cpumask_of(cpu), true);
return ret;
} }
/* /*
...@@ -198,25 +205,30 @@ void migrate_irqs(void) ...@@ -198,25 +205,30 @@ void migrate_irqs(void)
{ {
unsigned int i, cpu = smp_processor_id(); unsigned int i, cpu = smp_processor_id();
struct irq_desc *desc; struct irq_desc *desc;
unsigned long flags;
local_irq_save(flags);
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
struct irq_data *d = &desc->irq_data; struct irq_data *d = &desc->irq_data;
bool affinity_broken = false;
if (d->node == cpu) { raw_spin_lock(&desc->lock);
unsigned int newcpu = cpumask_any_and(d->affinity, do {
cpu_online_mask); if (desc->action == NULL)
if (newcpu >= nr_cpu_ids) { break;
if (printk_ratelimit())
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
i, cpu);
cpumask_setall(d->affinity); if (d->node != cpu)
newcpu = cpumask_any_and(d->affinity, break;
cpu_online_mask);
}
route_irq(desc, i, newcpu); affinity_broken = migrate_one_irq(d);
} } while (0);
raw_spin_unlock(&desc->lock);
if (affinity_broken && printk_ratelimit())
pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu);
} }
local_irq_restore(flags);
} }
#endif /* CONFIG_HOTPLUG_CPU */ #endif /* CONFIG_HOTPLUG_CPU */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment