]>
Commit | Line | Data |
---|---|---|
931f3697 GKH |
1 | From foo@baz Tue Oct 28 11:19:22 CST 2014 |
2 | From: "David S. Miller" <davem@davemloft.net> | |
3 | Date: Mon, 11 Aug 2014 15:38:46 -0700 | |
4 | Subject: sparc64: Fix pcr_ops initialization and usage bugs. | |
5 | ||
6 | From: "David S. Miller" <davem@davemloft.net> | |
7 | ||
8 | [ Upstream commit 8bccf5b313180faefce38e0d1140f76e0f327d28 ] | |
9 | ||
10 | Christopher reports that perf_event_print_debug() can crash in uniprocessor | |
11 | builds. The crash is due to pcr_ops being NULL. | |
12 | ||
13 | This happens because pcr_arch_init() is only invoked by smp_cpus_done() which | |
14 | only executes in SMP builds. | |
15 | ||
16 | init_hw_perf_events() is closely intertwined with pcr_ops being setup properly, | |
17 | therefore: | |
18 | ||
19 | 1) Call pcr_arch_init() early on from init_hw_perf_events(), instead of | |
20 | from smp_cpus_done(). | |
21 | ||
22 | 2) Do not hook up a PMU type if pcr_ops is NULL after pcr_arch_init(). | |
23 | ||
24 | 3) Move init_hw_perf_events to a later initcall so that it we will be | |
25 | sure to invoke pcr_arch_init() after all cpus are brought up. | |
26 | ||
27 | Finally, guard the one naked sequence of pcr_ops dereferences in | |
28 | __global_pmu_self() with an appropriate NULL check. | |
29 | ||
30 | Reported-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net> | |
31 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
32 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
33 | --- | |
34 | arch/sparc/kernel/perf_event.c | 7 +++++-- | |
35 | arch/sparc/kernel/process_64.c | 3 +++ | |
36 | arch/sparc/kernel/smp_64.c | 1 - | |
37 | 3 files changed, 8 insertions(+), 3 deletions(-) | |
38 | ||
39 | --- a/arch/sparc/kernel/perf_event.c | |
40 | +++ b/arch/sparc/kernel/perf_event.c | |
41 | @@ -1671,9 +1671,12 @@ static bool __init supported_pmu(void) | |
42 | ||
43 | static int __init init_hw_perf_events(void) | |
44 | { | |
45 | + int err; | |
46 | + | |
47 | pr_info("Performance events: "); | |
48 | ||
49 | - if (!supported_pmu()) { | |
50 | + err = pcr_arch_init(); | |
51 | + if (err || !supported_pmu()) { | |
52 | pr_cont("No support for PMU type '%s'\n", sparc_pmu_type); | |
53 | return 0; | |
54 | } | |
55 | @@ -1685,7 +1688,7 @@ static int __init init_hw_perf_events(vo | |
56 | ||
57 | return 0; | |
58 | } | |
59 | -early_initcall(init_hw_perf_events); | |
60 | +pure_initcall(init_hw_perf_events); | |
61 | ||
62 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | |
63 | struct pt_regs *regs) | |
64 | --- a/arch/sparc/kernel/process_64.c | |
65 | +++ b/arch/sparc/kernel/process_64.c | |
66 | @@ -312,6 +312,9 @@ static void __global_pmu_self(int this_c | |
67 | struct global_pmu_snapshot *pp; | |
68 | int i, num; | |
69 | ||
70 | + if (!pcr_ops) | |
71 | + return; | |
72 | + | |
73 | pp = &global_cpu_snapshot[this_cpu].pmu; | |
74 | ||
75 | num = 1; | |
76 | --- a/arch/sparc/kernel/smp_64.c | |
77 | +++ b/arch/sparc/kernel/smp_64.c | |
78 | @@ -1383,7 +1383,6 @@ void __cpu_die(unsigned int cpu) | |
79 | ||
80 | void __init smp_cpus_done(unsigned int max_cpus) | |
81 | { | |
82 | - pcr_arch_init(); | |
83 | } | |
84 | ||
85 | void smp_send_reschedule(int cpu) |