genirq: Prevent irq storm on migration
Thomas Gleixner [Fri, 28 Jan 2011 07:47:15 +0000 (08:47 +0100)]
move_native_irq() masks and unmasks the interrupt line
unconditionally, but the interrupt line might be masked due to a
threaded oneshot handler in progress. Unmasking the line in that case
can lead to interrupt storms. Observed on PREEMPT_RT.

Originally-from: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@kernel.org

kernel/irq/migration.c

index 1d25419..441fd62 100644 (file)
@@ -56,6 +56,7 @@ void move_masked_irq(int irq)
 void move_native_irq(int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       bool masked;
 
        if (likely(!(desc->status & IRQ_MOVE_PENDING)))
                return;
@@ -63,8 +64,15 @@ void move_native_irq(int irq)
        if (unlikely(desc->status & IRQ_DISABLED))
                return;
 
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
+       /*
+        * Be careful vs. already masked interrupts. If this is a
+        * threaded interrupt with ONESHOT set, we can end up with an
+        * interrupt storm.
+        */
+       masked = desc->status & IRQ_MASKED;
+       if (!masked)
+               desc->irq_data.chip->irq_mask(&desc->irq_data);
        move_masked_irq(irq);
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+       if (!masked)
+               desc->irq_data.chip->irq_unmask(&desc->irq_data);
 }
-