diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2011-01-28 02:47:15 -0500 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2011-02-02 16:15:08 -0500 |
| commit | f1a06390d013244e721372b3f9b66e39b6429c71 (patch) | |
| tree | 8ffce4d07e61d3533d17a2b2f947aefcebde211c | |
| parent | afe8a887550f7cc24eb16449670b93f6b43c32d8 (diff) | |
genirq: Prevent irq storm on migration
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
| -rw-r--r-- | kernel/irq/migration.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index 1d2541940480..441fd629ff04 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c | |||
| @@ -56,6 +56,7 @@ void move_masked_irq(int irq) | |||
| 56 | void move_native_irq(int irq) | 56 | void move_native_irq(int irq) |
| 57 | { | 57 | { |
| 58 | struct irq_desc *desc = irq_to_desc(irq); | 58 | struct irq_desc *desc = irq_to_desc(irq); |
| 59 | bool masked; | ||
| 59 | 60 | ||
| 60 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) | 61 | if (likely(!(desc->status & IRQ_MOVE_PENDING))) |
| 61 | return; | 62 | return; |
| @@ -63,8 +64,15 @@ void move_native_irq(int irq) | |||
| 63 | if (unlikely(desc->status & IRQ_DISABLED)) | 64 | if (unlikely(desc->status & IRQ_DISABLED)) |
| 64 | return; | 65 | return; |
| 65 | 66 | ||
| 66 | desc->irq_data.chip->irq_mask(&desc->irq_data); | 67 | /* |
| 68 | * Be careful vs. already masked interrupts. If this is a | ||
| 69 | * threaded interrupt with ONESHOT set, we can end up with an | ||
| 70 | * interrupt storm. | ||
| 71 | */ | ||
| 72 | masked = desc->status & IRQ_MASKED; | ||
| 73 | if (!masked) | ||
| 74 | desc->irq_data.chip->irq_mask(&desc->irq_data); | ||
| 67 | move_masked_irq(irq); | 75 | move_masked_irq(irq); |
| 68 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | 76 | if (!masked) |
| 77 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | ||
| 69 | } | 78 | } |
| 70 | |||
