Skip to content

Commit

Permalink
Fix crash with irqpoll due to the IRQF_IRQPOLL flag testing
Browse files Browse the repository at this point in the history
With irqpoll enabled, trying to test the IRQF_IRQPOLL flag in the
actions would cause a NULL pointer dereference if no action was
installed (for example, the driver might have been unloaded with
interrupts still pending).

So be a bit more careful about testing the flag by making sure to test
for that case.

(The actual _change_ is trivial, the patch is more than a one-liner
because I rewrote the testing to also be much more readable.

Original (discarded) bugfix by Bernhard Walle.

Cc: Bernhard Walle <[email protected]>
Tested-by: Vivek Goyal <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Linus Torvalds committed May 24, 2007
1 parent db2668f commit 92ea772
Showing 1 changed file with 37 additions and 9 deletions.
46 changes: 37 additions & 9 deletions kernel/irq/spurious.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,39 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
}
}

static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
{
struct irqaction *action;

if (!irqfixup)
return 0;

/* We didn't actually handle the IRQ - see if it was misrouted? */
if (action_ret == IRQ_NONE)
return 1;

/*
* But for 'irqfixup == 2' we also do it for handled interrupts if
* they are marked as IRQF_IRQPOLL (or for irq zero, which is the
* traditional PC timer interrupt.. Legacy)
*/
if (irqfixup < 2)
return 0;

if (!irq)
return 1;

/*
* Since we don't get the descriptor lock, "action" can
* change under us. We don't really care, but we don't
* want to follow a NULL pointer. So tell the compiler to
* just load it once by using a barrier.
*/
action = desc->action;
barrier();
return action && (action->flags & IRQF_IRQPOLL);
}

void note_interrupt(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret)
{
Expand All @@ -144,15 +177,10 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
report_bad_irq(irq, desc, action_ret);
}

if (unlikely(irqfixup)) {
/* Don't punish working computers */
if ((irqfixup == 2 && ((irq == 0) ||
(desc->action->flags & IRQF_IRQPOLL))) ||
action_ret == IRQ_NONE) {
int ok = misrouted_irq(irq);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
}
if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
int ok = misrouted_irq(irq);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
}

desc->irq_count++;
Expand Down

0 comments on commit 92ea772

Please sign in to comment.