powerpc/perf: Fix deadlock caused by calling printk() in PMU exception
authorMichael Ellerman <michael@ellerman.id.au>
Wed, 5 Jun 2013 17:58:20 +0000 (17:58 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sun, 9 Jun 2013 22:36:32 +0000 (08:36 +1000)
In commit bc09c21 "Fix finding overflowed PMC in interrupt" we added
a printk() to the PMU exception handler. Unfortunately that is not safe.

The problem is that the PMU exception may run even when interrupts are
soft disabled, aka NMI context. We do this so that we can profile parts
of the kernel that have interrupts soft-disabled.

But by calling printk() from the exception handler, we can potentially
deadlock in the printk code on logbuf_lock, eg:

  [c00000038ba575c0c000000000081928 .vprintk_emit+0xa8/0x540
  [c00000038ba576a0c0000000007bcde8 .printk+0x48/0x58
  [c00000038ba57710c000000000076504 .perf_event_interrupt+0x2d4/0x490
  [c00000038ba57810c00000000001f6f8 .performance_monitor_exception+0x48/0x60
  [c00000038ba57880c0000000000032cc performance_monitor_common+0x14c/0x180
  --- Exception: f01 (Performance Monitor) at c0000000007b25d4 ._raw_spin_lock_irq
  +0x64/0xc0
  [c00000038ba57bf0c00000000007ed90 .devkmsg_read+0xd0/0x5a0
  [c00000038ba57d00c0000000001c2934 .vfs_read+0xc4/0x1e0
  [c00000038ba57d90c0000000001c2cd8 .SyS_read+0x58/0xd0
  [c00000038ba57e30c000000000009d54 syscall_exit+0x0/0x98
  --- Exception: c01 (System Call) at 00001fffffbf6f7c
  SP (3ffff6d4de10) is in userspace

Fix it by making sure we only call printk() when we are not in NMI
context.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Cc: <stable@vger.kernel.org> # 3.9
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/perf/core-book3s.c

index 845c867444e6ff27bffc1a203790bce5543c5e12..29c6482890c88c89f8fbb159d5561b591b47c09f 100644 (file)
@@ -1758,7 +1758,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
                        }
                }
        }
-       if ((!found) && printk_ratelimit())
+       if (!found && !nmi && printk_ratelimit())
                printk(KERN_WARNING "Can't find PMC that caused IRQ\n");
 
        /*