[PATCH] Fix misrouted interrupts deadlocks
commitf72fa707604c015a6625e80f269506032d5430dc
authorPavel Emelianov <xemul@openvz.org>
Fri, 10 Nov 2006 20:27:56 +0000 (10 12:27 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 13 Nov 2006 15:40:43 +0000 (13 07:40 -0800)
treed7701d7a0e6fef020e78f690041486a052bc9bb3
parent0130b0b32ee53dc7add773fcea984f6a26ef1da3
[PATCH] Fix misrouted interrupts deadlocks

While testing kernel on machine with "irqpoll" option I've caught such a
lockup:

__do_IRQ()
   spin_lock(&desc->lock);
           desc->chip->ack(); /* IRQ is ACKed */
note_interrupt()
misrouted_irq()
handle_IRQ_event()
           if (...)
      local_irq_enable_in_hardirq();
/* interrupts are enabled from now */
...
__do_IRQ() /* same IRQ we've started from */
   spin_lock(&desc->lock); /* LOCKUP */

Looking at misrouted_irq() code I've found that a potential deadlock like
this can also take place:

1CPU:
__do_IRQ()
   spin_lock(&desc->lock); /* irq = A */
misrouted_irq()
   for (i = 1; i < NR_IRQS; i++) {
      spin_lock(&desc->lock); /* irq = B */
      if (desc->status & IRQ_INPROGRESS) {

2CPU:
__do_IRQ()
   spin_lock(&desc->lock); /* irq = B */
misrouted_irq()
   for (i = 1; i < NR_IRQS; i++) {
      spin_lock(&desc->lock); /* irq = A */
      if (desc->status & IRQ_INPROGRESS) {

As the second lock on both CPUs is taken before checking that this irq is
being handled in another processor this may cause a deadlock.  This issue
is only theoretical.

I propose the attached patch to fix booth problems: when trying to handle
misrouted IRQ active desc->lock may be unlocked.

Acked-by: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/irq/spurious.c