Skip to content

Commit

Permalink
ARM: irq migration: ensure migration is handled safely
Browse files Browse the repository at this point in the history
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: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Feb 23, 2011
1 parent 1dbfa18 commit 6179124
Showing 1 changed file with 31 additions and 19 deletions.
50 changes: 31 additions & 19 deletions arch/arm/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,21 @@ int __init arch_probe_nr_irqs(void)

#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);
desc->irq_data.chip->irq_set_affinity(&desc->irq_data,
cpumask_of(cpu), true);
raw_spin_unlock_irq(&desc->lock);
if (cpu >= nr_cpu_ids) {
cpu = cpumask_any(cpu_online_mask);
ret = true;
}

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;
}

/*
Expand All @@ -198,25 +205,30 @@ void migrate_irqs(void)
{
unsigned int i, cpu = smp_processor_id();
struct irq_desc *desc;
unsigned long flags;

local_irq_save(flags);

for_each_irq_desc(i, desc) {
struct irq_data *d = &desc->irq_data;
bool affinity_broken = false;

if (d->node == cpu) {
unsigned int newcpu = cpumask_any_and(d->affinity,
cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
if (printk_ratelimit())
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
i, cpu);
raw_spin_lock(&desc->lock);
do {
if (desc->action == NULL)
break;

cpumask_setall(d->affinity);
newcpu = cpumask_any_and(d->affinity,
cpu_online_mask);
}
if (d->node != cpu)
break;

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 */

0 comments on commit 6179124

Please sign in to comment.