[patch 4/6] x86: force irq complete move during cpu offline

From: Suresh Siddha
Date: Mon Oct 26 2009 - 18:03:53 EST


When a cpu goes offline, fixup_irqs() try to move irq's currently
destined to the offline cpu to a new cpu. But this attempt will fail
if the irq is recently moved to this cpu and the irq still hasn't
arrived at this cpu (for non intr-remapping platforms this is when we free the
vector allocation at the previous destination) that is about to go offline.

This will endup with the interrupt subsystem still pointing the irq to
the offline cpu, causing that irq to not work any more.

Fix this by forcing the irq to complete its move (its been a long time
we moved the irq to this cpu which we are offlining now) and then
move this irq to a new cpu before this cpu goes offline.

Signed-off-by: Suresh Siddha <suresh.b.siddha@xxxxxxxxx>
Signed-off-by: Gary Hade <garyhade@xxxxxxxxxx>
Cc: Eric W. Biederman <ebiederm@xxxxxxxxxxxx>
---
arch/x86/include/asm/irq.h | 1 +
arch/x86/kernel/apic/io_apic.c | 18 +++++++++++++++---
arch/x86/kernel/irq.c | 7 +++++++
3 files changed, 23 insertions(+), 3 deletions(-)

Index: tip/arch/x86/kernel/apic/io_apic.c
===================================================================
--- tip.orig/arch/x86/kernel/apic/io_apic.c
+++ tip/arch/x86/kernel/apic/io_apic.c
@@ -2450,21 +2450,33 @@ unlock:
irq_exit();
}

-static void irq_complete_move(struct irq_desc **descp)
+static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
{
struct irq_desc *desc = *descp;
struct irq_cfg *cfg = desc->chip_data;
- unsigned vector, me;
+ unsigned me;

if (likely(!cfg->move_in_progress))
return;

- vector = ~get_irq_regs()->orig_ax;
me = smp_processor_id();

if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
send_cleanup_vector(cfg);
}
+
+static void irq_complete_move(struct irq_desc **descp)
+{
+ __irq_complete_move(descp, ~get_irq_regs()->orig_ax);
+}
+
+void irq_force_complete_move(int irq)
+{
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_cfg *cfg = desc->chip_data;
+
+ __irq_complete_move(&desc, cfg->vector);
+}
#else
static inline void irq_complete_move(struct irq_desc **descp) {}
#endif
Index: tip/arch/x86/kernel/irq.c
===================================================================
--- tip.orig/arch/x86/kernel/irq.c
+++ tip/arch/x86/kernel/irq.c
@@ -303,6 +303,13 @@ void fixup_irqs(void)
continue;
}

+ /*
+ * Complete the irq move. This cpu is going down and for
+ * non intr-remapping case, we can't wait till this interrupt
+ * arrives at this cpu before completing the irq move.
+ */
+ irq_force_complete_move(irq);
+
if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
break_affinity = 1;
affinity = cpu_all_mask;
Index: tip/arch/x86/include/asm/irq.h
===================================================================
--- tip.orig/arch/x86/include/asm/irq.h
+++ tip/arch/x86/include/asm/irq.h
@@ -34,6 +34,7 @@ static inline int irq_canonicalize(int i
#ifdef CONFIG_HOTPLUG_CPU
#include <linux/cpumask.h>
extern void fixup_irqs(void);
+extern void irq_force_complete_move(int);
#endif

extern void (*x86_platform_ipi_callback)(void);


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/