Commit e7f7dcadf97accf7a3f0fca58c8d3b4ffb563808

Authored by David S. Miller
Committed by Greg Kroah-Hartman
1 parent 4eed408a0b

sparc64: Fix pcr_ops initialization and usage bugs.

[ Upstream commit 8bccf5b313180faefce38e0d1140f76e0f327d28 ]

Christopher reports that perf_event_print_debug() can crash in uniprocessor
builds.  The crash is due to pcr_ops being NULL.

This happens because pcr_arch_init() is only invoked by smp_cpus_done() which
only executes in SMP builds.

init_hw_perf_events() is closely intertwined with pcr_ops being setup properly,
therefore:

1) Call pcr_arch_init() early on from init_hw_perf_events(), instead of
   from smp_cpus_done().

2) Do not hook up a PMU type if pcr_ops is NULL after pcr_arch_init().

3) Move init_hw_perf_events to a later initcall so that it we will be
   sure to invoke pcr_arch_init() after all cpus are brought up.

Finally, guard the one naked sequence of pcr_ops dereferences in
__global_pmu_self() with an appropriate NULL check.

Reported-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 3 changed files with 8 additions and 3 deletions Side-by-side Diff

arch/sparc/kernel/perf_event.c
... ... @@ -1671,9 +1671,12 @@
1671 1671  
1672 1672 static int __init init_hw_perf_events(void)
1673 1673 {
  1674 + int err;
  1675 +
1674 1676 pr_info("Performance events: ");
1675 1677  
1676   - if (!supported_pmu()) {
  1678 + err = pcr_arch_init();
  1679 + if (err || !supported_pmu()) {
1677 1680 pr_cont("No support for PMU type '%s'\n", sparc_pmu_type);
1678 1681 return 0;
1679 1682 }
... ... @@ -1685,7 +1688,7 @@
1685 1688  
1686 1689 return 0;
1687 1690 }
1688   -early_initcall(init_hw_perf_events);
  1691 +pure_initcall(init_hw_perf_events);
1689 1692  
1690 1693 void perf_callchain_kernel(struct perf_callchain_entry *entry,
1691 1694 struct pt_regs *regs)
arch/sparc/kernel/process_64.c
... ... @@ -312,6 +312,9 @@
312 312 struct global_pmu_snapshot *pp;
313 313 int i, num;
314 314  
  315 + if (!pcr_ops)
  316 + return;
  317 +
315 318 pp = &global_cpu_snapshot[this_cpu].pmu;
316 319  
317 320 num = 1;
arch/sparc/kernel/smp_64.c
... ... @@ -1383,7 +1383,6 @@
1383 1383  
1384 1384 void __init smp_cpus_done(unsigned int max_cpus)
1385 1385 {
1386   - pcr_arch_init();
1387 1386 }
1388 1387  
1389 1388 void smp_send_reschedule(int cpu)