diff options
author | David S. Miller <davem@davemloft.net> | 2014-08-11 18:38:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-11 23:45:12 -0400 |
commit | 8bccf5b313180faefce38e0d1140f76e0f327d28 (patch) | |
tree | ed8d8f8c5696526f1ecf6fccd94680fe166427f4 /arch/sparc/kernel | |
parent | 58556104e9cd0107a7a8d2692cf04ef31669f6e4 (diff) |
sparc64: Fix pcr_ops initialization and usage bugs.
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>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/perf_event.c | 7 | ||||
-rw-r--r-- | arch/sparc/kernel/process_64.c | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/smp_64.c | 1 |
3 files changed, 8 insertions, 3 deletions
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 8efd33753ad3..d35c490a91cb 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
@@ -1671,9 +1671,12 @@ static bool __init supported_pmu(void) | |||
1671 | 1671 | ||
1672 | static int __init init_hw_perf_events(void) | 1672 | static int __init init_hw_perf_events(void) |
1673 | { | 1673 | { |
1674 | int err; | ||
1675 | |||
1674 | pr_info("Performance events: "); | 1676 | pr_info("Performance events: "); |
1675 | 1677 | ||
1676 | if (!supported_pmu()) { | 1678 | err = pcr_arch_init(); |
1679 | if (err || !supported_pmu()) { | ||
1677 | pr_cont("No support for PMU type '%s'\n", sparc_pmu_type); | 1680 | pr_cont("No support for PMU type '%s'\n", sparc_pmu_type); |
1678 | return 0; | 1681 | return 0; |
1679 | } | 1682 | } |
@@ -1685,7 +1688,7 @@ static int __init init_hw_perf_events(void) | |||
1685 | 1688 | ||
1686 | return 0; | 1689 | return 0; |
1687 | } | 1690 | } |
1688 | early_initcall(init_hw_perf_events); | 1691 | pure_initcall(init_hw_perf_events); |
1689 | 1692 | ||
1690 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | 1693 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
1691 | struct pt_regs *regs) | 1694 | struct pt_regs *regs) |
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 027e09986194..0be7bf978cb1 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c | |||
@@ -312,6 +312,9 @@ static void __global_pmu_self(int this_cpu) | |||
312 | struct global_pmu_snapshot *pp; | 312 | struct global_pmu_snapshot *pp; |
313 | int i, num; | 313 | int i, num; |
314 | 314 | ||
315 | if (!pcr_ops) | ||
316 | return; | ||
317 | |||
315 | pp = &global_cpu_snapshot[this_cpu].pmu; | 318 | pp = &global_cpu_snapshot[this_cpu].pmu; |
316 | 319 | ||
317 | num = 1; | 320 | num = 1; |
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 41aa2478f3ca..f7ba87543e5f 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -1383,7 +1383,6 @@ void __cpu_die(unsigned int cpu) | |||
1383 | 1383 | ||
1384 | void __init smp_cpus_done(unsigned int max_cpus) | 1384 | void __init smp_cpus_done(unsigned int max_cpus) |
1385 | { | 1385 | { |
1386 | pcr_arch_init(); | ||
1387 | } | 1386 | } |
1388 | 1387 | ||
1389 | void smp_send_reschedule(int cpu) | 1388 | void smp_send_reschedule(int cpu) |