Skip to content

Commit 9029a5e

Browse files
author
Ingo Molnar
committed
perf_counter: x86: Protect against infinite loops in intel_pmu_handle_irq()
intel_pmu_handle_irq() can lock up in an infinite loop if the hardware does not allow the acking of irqs. Alas, this happened in testing so make this robust and emit a warning if it happens in the future. Also, clean up the IRQ handlers a bit. [ Impact: improve perfcounter irq/nmi handling robustness ] Acked-by: Peter Zijlstra <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Corey Ashford <[email protected]> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <[email protected]>
1 parent 1c80f4b commit 9029a5e

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

arch/x86/kernel/cpu/perf_counter.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -722,9 +722,13 @@ static void intel_pmu_save_and_restart(struct perf_counter *counter)
722722
*/
723723
static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
724724
{
725-
int bit, cpu = smp_processor_id();
725+
struct cpu_hw_counters *cpuc;
726+
struct cpu_hw_counters;
727+
int bit, cpu, loops;
726728
u64 ack, status;
727-
struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
729+
730+
cpu = smp_processor_id();
731+
cpuc = &per_cpu(cpu_hw_counters, cpu);
728732

729733
perf_disable();
730734
status = intel_pmu_get_status();
@@ -733,7 +737,13 @@ static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
733737
return 0;
734738
}
735739

740+
loops = 0;
736741
again:
742+
if (++loops > 100) {
743+
WARN_ONCE(1, "perfcounters: irq loop stuck!\n");
744+
return 1;
745+
}
746+
737747
inc_irq_stat(apic_perf_irqs);
738748
ack = status;
739749
for_each_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) {
@@ -765,13 +775,14 @@ static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
765775

766776
static int amd_pmu_handle_irq(struct pt_regs *regs, int nmi)
767777
{
768-
int cpu = smp_processor_id();
769-
struct cpu_hw_counters *cpuc = &per_cpu(cpu_hw_counters, cpu);
770-
u64 val;
771-
int handled = 0;
778+
int cpu, idx, throttle = 0, handled = 0;
779+
struct cpu_hw_counters *cpuc;
772780
struct perf_counter *counter;
773781
struct hw_perf_counter *hwc;
774-
int idx, throttle = 0;
782+
u64 val;
783+
784+
cpu = smp_processor_id();
785+
cpuc = &per_cpu(cpu_hw_counters, cpu);
775786

776787
if (++cpuc->interrupts == PERFMON_MAX_INTERRUPTS) {
777788
throttle = 1;

0 commit comments

Comments
 (0)