Commit 1082687e authored by Thomas Gleixner's avatar Thomas Gleixner

genirq: Plug race in report_bad_irq()

We cannot walk the action chain unlocked. Even if IRQ_INPROGRESS is
set an action can be removed and we follow a null pointer. It's safe
to take the lock there, because the code which removes the action will
call synchronize_irq() which waits unlocked for IRQ_INPROGRESS going
away.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 2b879eaf
...@@ -139,15 +139,13 @@ static void poll_spurious_irqs(unsigned long dummy) ...@@ -139,15 +139,13 @@ static void poll_spurious_irqs(unsigned long dummy)
* *
* (The other 100-of-100,000 interrupts may have been a correctly * (The other 100-of-100,000 interrupts may have been a correctly
* functioning device sharing an IRQ with the failing one) * functioning device sharing an IRQ with the failing one)
*
* Called under desc->lock
*/ */
static void static void
__report_bad_irq(unsigned int irq, struct irq_desc *desc, __report_bad_irq(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret) irqreturn_t action_ret)
{ {
struct irqaction *action; struct irqaction *action;
unsigned long flags;
if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
printk(KERN_ERR "irq event %d: bogus return value %x\n", printk(KERN_ERR "irq event %d: bogus return value %x\n",
...@@ -159,6 +157,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc, ...@@ -159,6 +157,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
dump_stack(); dump_stack();
printk(KERN_ERR "handlers:\n"); printk(KERN_ERR "handlers:\n");
/*
* We need to take desc->lock here. note_interrupt() is called
* w/o desc->lock held, but IRQ_PROGRESS set. We might race
* with something else removing an action. It's ok to take
* desc->lock here. See synchronize_irq().
*/
raw_spin_lock_irqsave(&desc->lock, flags);
action = desc->action; action = desc->action;
while (action) { while (action) {
printk(KERN_ERR "[<%p>]", action->handler); printk(KERN_ERR "[<%p>]", action->handler);
...@@ -167,6 +172,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc, ...@@ -167,6 +172,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
printk("\n"); printk("\n");
action = action->next; action = action->next;
} }
raw_spin_unlock_irqrestore(&desc->lock, flags);
} }
static void static void
......
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