aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorJarek Poplawski <jarkao2@o2.pl>2007-08-31 02:56:34 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-31 04:42:23 -0400
commit59845b1ffd9121e5ef474ea5f27405fd7a83c85b (patch)
tree9f7c073327138b7c5bb0193229244dbdd5444113 /kernel/irq
parent2aeb3db17fc33443d21b11d7121c5627d55717c6 (diff)
request_irq: fix DEBUG_SHIRQ handling
Mariusz Kozlowski reported lockdep's warning: > ================================= > [ INFO: inconsistent lock state ] > 2.6.23-rc2-mm1 #7 > --------------------------------- > inconsistent {in-hardirq-W} -> {hardirq-on-W} usage. > ifconfig/5492 [HC0[0]:SC0[0]:HE1:SE1] takes: > (&tp->lock){+...}, at: [<de8706e0>] rtl8139_interrupt+0x27/0x46b [8139too] > {in-hardirq-W} state was registered at: > [<c0138eeb>] __lock_acquire+0x949/0x11ac > [<c01397e7>] lock_acquire+0x99/0xb2 > [<c0452ff3>] _spin_lock+0x35/0x42 > [<de8706e0>] rtl8139_interrupt+0x27/0x46b [8139too] > [<c0147a5d>] handle_IRQ_event+0x28/0x59 > [<c01493ca>] handle_level_irq+0xad/0x10b > [<c0105a13>] do_IRQ+0x93/0xd0 > [<c010441e>] common_interrupt+0x2e/0x34 ... > other info that might help us debug this: > 1 lock held by ifconfig/5492: > #0: (rtnl_mutex){--..}, at: [<c0451778>] mutex_lock+0x1c/0x1f > > stack backtrace: ... > [<c0452ff3>] _spin_lock+0x35/0x42 > [<de8706e0>] rtl8139_interrupt+0x27/0x46b [8139too] > [<c01480fd>] free_irq+0x11b/0x146 > [<de871d59>] rtl8139_close+0x8a/0x14a [8139too] > [<c03bde63>] dev_close+0x57/0x74 ... This shows that a driver's irq handler was running both in hard interrupt and process contexts with irqs enabled. The latter was done during free_irq() call and was possible only with CONFIG_DEBUG_SHIRQ enabled. This was fixed by another patch. But similar problem is possible with request_irq(): any locks taken from irq handler could be vulnerable - especially with soft interrupts. This patch fixes it by disabling local interrupts during handler's run. (It seems, disabling softirqs should be enough, but it needs more checking on possible races or other special cases). Reported-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Jarek Poplawski <jarkao2@o2.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/manage.c11
1 files changed, 4 insertions, 7 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 853aefbd184b..7230d914eaa2 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -547,14 +547,11 @@ int request_irq(unsigned int irq, irq_handler_t handler,
547 * We do this before actually registering it, to make sure that 547 * We do this before actually registering it, to make sure that
548 * a 'real' IRQ doesn't run in parallel with our fake 548 * a 'real' IRQ doesn't run in parallel with our fake
549 */ 549 */
550 if (irqflags & IRQF_DISABLED) { 550 unsigned long flags;
551 unsigned long flags;
552 551
553 local_irq_save(flags); 552 local_irq_save(flags);
554 handler(irq, dev_id); 553 handler(irq, dev_id);
555 local_irq_restore(flags); 554 local_irq_restore(flags);
556 } else
557 handler(irq, dev_id);
558 } 555 }
559#endif 556#endif
560 557