diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /kernel/trace/trace_event_perf.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'kernel/trace/trace_event_perf.c')
-rw-r--r-- | kernel/trace/trace_event_perf.c | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 31cc4cb0dbf2..19a359d5e6d5 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <linux/kprobes.h> | 9 | #include <linux/kprobes.h> |
10 | #include "trace.h" | 10 | #include "trace.h" |
11 | 11 | ||
12 | static char *perf_trace_buf[4]; | 12 | static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS]; |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * Force it to be aligned to unsigned long to avoid misaligned accesses | 15 | * Force it to be aligned to unsigned long to avoid misaligned accesses |
@@ -21,17 +21,46 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) | |||
21 | /* Count the events in use (per event id, not per instance) */ | 21 | /* Count the events in use (per event id, not per instance) */ |
22 | static int total_ref_count; | 22 | static int total_ref_count; |
23 | 23 | ||
24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, | ||
25 | struct perf_event *p_event) | ||
26 | { | ||
27 | /* No tracing, just counting, so no obvious leak */ | ||
28 | if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) | ||
29 | return 0; | ||
30 | |||
31 | /* Some events are ok to be traced by non-root users... */ | ||
32 | if (p_event->attach_state == PERF_ATTACH_TASK) { | ||
33 | if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY) | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * ...otherwise raw tracepoint data can be a severe data leak, | ||
39 | * only allow root to have these. | ||
40 | */ | ||
41 | if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) | ||
42 | return -EPERM; | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
24 | static int perf_trace_event_init(struct ftrace_event_call *tp_event, | 47 | static int perf_trace_event_init(struct ftrace_event_call *tp_event, |
25 | struct perf_event *p_event) | 48 | struct perf_event *p_event) |
26 | { | 49 | { |
27 | struct hlist_head *list; | 50 | struct hlist_head __percpu *list; |
28 | int ret = -ENOMEM; | 51 | int ret; |
29 | int cpu; | 52 | int cpu; |
30 | 53 | ||
54 | ret = perf_trace_event_perm(tp_event, p_event); | ||
55 | if (ret) | ||
56 | return ret; | ||
57 | |||
31 | p_event->tp_event = tp_event; | 58 | p_event->tp_event = tp_event; |
32 | if (tp_event->perf_refcount++ > 0) | 59 | if (tp_event->perf_refcount++ > 0) |
33 | return 0; | 60 | return 0; |
34 | 61 | ||
62 | ret = -ENOMEM; | ||
63 | |||
35 | list = alloc_percpu(struct hlist_head); | 64 | list = alloc_percpu(struct hlist_head); |
36 | if (!list) | 65 | if (!list) |
37 | goto fail; | 66 | goto fail; |
@@ -42,11 +71,11 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event, | |||
42 | tp_event->perf_events = list; | 71 | tp_event->perf_events = list; |
43 | 72 | ||
44 | if (!total_ref_count) { | 73 | if (!total_ref_count) { |
45 | char *buf; | 74 | char __percpu *buf; |
46 | int i; | 75 | int i; |
47 | 76 | ||
48 | for (i = 0; i < 4; i++) { | 77 | for (i = 0; i < PERF_NR_CONTEXTS; i++) { |
49 | buf = (char *)alloc_percpu(perf_trace_t); | 78 | buf = (char __percpu *)alloc_percpu(perf_trace_t); |
50 | if (!buf) | 79 | if (!buf) |
51 | goto fail; | 80 | goto fail; |
52 | 81 | ||
@@ -65,7 +94,7 @@ fail: | |||
65 | if (!total_ref_count) { | 94 | if (!total_ref_count) { |
66 | int i; | 95 | int i; |
67 | 96 | ||
68 | for (i = 0; i < 4; i++) { | 97 | for (i = 0; i < PERF_NR_CONTEXTS; i++) { |
69 | free_percpu(perf_trace_buf[i]); | 98 | free_percpu(perf_trace_buf[i]); |
70 | perf_trace_buf[i] = NULL; | 99 | perf_trace_buf[i] = NULL; |
71 | } | 100 | } |
@@ -101,22 +130,26 @@ int perf_trace_init(struct perf_event *p_event) | |||
101 | return ret; | 130 | return ret; |
102 | } | 131 | } |
103 | 132 | ||
104 | int perf_trace_enable(struct perf_event *p_event) | 133 | int perf_trace_add(struct perf_event *p_event, int flags) |
105 | { | 134 | { |
106 | struct ftrace_event_call *tp_event = p_event->tp_event; | 135 | struct ftrace_event_call *tp_event = p_event->tp_event; |
136 | struct hlist_head __percpu *pcpu_list; | ||
107 | struct hlist_head *list; | 137 | struct hlist_head *list; |
108 | 138 | ||
109 | list = tp_event->perf_events; | 139 | pcpu_list = tp_event->perf_events; |
110 | if (WARN_ON_ONCE(!list)) | 140 | if (WARN_ON_ONCE(!pcpu_list)) |
111 | return -EINVAL; | 141 | return -EINVAL; |
112 | 142 | ||
113 | list = this_cpu_ptr(list); | 143 | if (!(flags & PERF_EF_START)) |
144 | p_event->hw.state = PERF_HES_STOPPED; | ||
145 | |||
146 | list = this_cpu_ptr(pcpu_list); | ||
114 | hlist_add_head_rcu(&p_event->hlist_entry, list); | 147 | hlist_add_head_rcu(&p_event->hlist_entry, list); |
115 | 148 | ||
116 | return 0; | 149 | return 0; |
117 | } | 150 | } |
118 | 151 | ||
119 | void perf_trace_disable(struct perf_event *p_event) | 152 | void perf_trace_del(struct perf_event *p_event, int flags) |
120 | { | 153 | { |
121 | hlist_del_rcu(&p_event->hlist_entry); | 154 | hlist_del_rcu(&p_event->hlist_entry); |
122 | } | 155 | } |
@@ -142,7 +175,7 @@ void perf_trace_destroy(struct perf_event *p_event) | |||
142 | tp_event->perf_events = NULL; | 175 | tp_event->perf_events = NULL; |
143 | 176 | ||
144 | if (!--total_ref_count) { | 177 | if (!--total_ref_count) { |
145 | for (i = 0; i < 4; i++) { | 178 | for (i = 0; i < PERF_NR_CONTEXTS; i++) { |
146 | free_percpu(perf_trace_buf[i]); | 179 | free_percpu(perf_trace_buf[i]); |
147 | perf_trace_buf[i] = NULL; | 180 | perf_trace_buf[i] = NULL; |
148 | } | 181 | } |