aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-02-05 09:23:08 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-05 09:24:14 -0500
commit82aa9a1829199233f9bdaf26e2ee271114f4701e (patch)
tree638cccf1b1708bdce1cc45d54408c0907f051128 /arch/x86/oprofile
parent5b75af0a02fcf3b8899f38ff6f22164c5d8e2fdd (diff)
perfcounters: fix "perf counters kills oprofile" bug, v2
Impact: fix kernel crash Both oprofile and perfcounters register an NMI die handler, but only one can handle the NMI. Conveniently, oprofile unregisters it's notifier when not actively in use, so setting it's notifier priority higher than perfcounter's allows oprofile to borrow the NMI for the duration of it's run. Tested/works both as module and built-in. While testing, I found that if kerneltop was generating NMIs at very high frequency, the kernel may panic when oprofile registered it's handler. This turned out to be because oprofile registers it's handler before reset_value has been allocated, so if an NMI comes in while it's still setting up, kabOom. Rather than try more invasive changes, I followed the lead of other places in op_model_ppro.c, and simply returned in that highly unlikely event. (debug warnings attached) Signed-off-by: Mike Galbraith <efault@gmx.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/oprofile')
-rw-r--r--arch/x86/oprofile/op_model_ppro.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/arch/x86/oprofile/op_model_ppro.c b/arch/x86/oprofile/op_model_ppro.c
index 07c914555a5e..85eb6268374f 100644
--- a/arch/x86/oprofile/op_model_ppro.c
+++ b/arch/x86/oprofile/op_model_ppro.c
@@ -126,6 +126,13 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
126 u64 val; 126 u64 val;
127 int i; 127 int i;
128 128
129 /*
130 * This can happen if perf counters are in use when
131 * we steal the die notifier NMI.
132 */
133 if (unlikely(!reset_value))
134 goto out;
135
129 for (i = 0 ; i < num_counters; ++i) { 136 for (i = 0 ; i < num_counters; ++i) {
130 if (!reset_value[i]) 137 if (!reset_value[i])
131 continue; 138 continue;
@@ -136,6 +143,7 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
136 } 143 }
137 } 144 }
138 145
146out:
139 /* Only P6 based Pentium M need to re-unmask the apic vector but it 147 /* Only P6 based Pentium M need to re-unmask the apic vector but it
140 * doesn't hurt other P6 variant */ 148 * doesn't hurt other P6 variant */
141 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 149 apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);