diff options
-rw-r--r-- | arch/x86/include/asm/trace/irq_vectors.h | 11 | ||||
-rw-r--r-- | include/linux/ftrace_event.h | 16 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 4 | ||||
-rw-r--r-- | include/trace/ftrace.h | 7 | ||||
-rw-r--r-- | kernel/events/core.c | 8 | ||||
-rw-r--r-- | kernel/trace/trace_event_perf.c | 8 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 25 | ||||
-rw-r--r-- | tools/perf/util/header.c | 6 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 11 |
9 files changed, 76 insertions, 20 deletions
diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h index 2874df24e7a4..4cab890007a7 100644 --- a/arch/x86/include/asm/trace/irq_vectors.h +++ b/arch/x86/include/asm/trace/irq_vectors.h | |||
@@ -72,6 +72,17 @@ DEFINE_IRQ_VECTOR_EVENT(x86_platform_ipi); | |||
72 | DEFINE_IRQ_VECTOR_EVENT(irq_work); | 72 | DEFINE_IRQ_VECTOR_EVENT(irq_work); |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * We must dis-allow sampling irq_work_exit() because perf event sampling | ||
76 | * itself can cause irq_work, which would lead to an infinite loop; | ||
77 | * | ||
78 | * 1) irq_work_exit happens | ||
79 | * 2) generates perf sample | ||
80 | * 3) generates irq_work | ||
81 | * 4) goto 1 | ||
82 | */ | ||
83 | TRACE_EVENT_PERF_PERM(irq_work_exit, is_sampling_event(p_event) ? -EPERM : 0); | ||
84 | |||
85 | /* | ||
75 | * call_function - called when entering/exiting a call function interrupt | 86 | * call_function - called when entering/exiting a call function interrupt |
76 | * vector handler | 87 | * vector handler |
77 | */ | 88 | */ |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 9abbe630c456..8c9b7a1c4138 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -248,6 +248,9 @@ struct ftrace_event_call { | |||
248 | #ifdef CONFIG_PERF_EVENTS | 248 | #ifdef CONFIG_PERF_EVENTS |
249 | int perf_refcount; | 249 | int perf_refcount; |
250 | struct hlist_head __percpu *perf_events; | 250 | struct hlist_head __percpu *perf_events; |
251 | |||
252 | int (*perf_perm)(struct ftrace_event_call *, | ||
253 | struct perf_event *); | ||
251 | #endif | 254 | #endif |
252 | }; | 255 | }; |
253 | 256 | ||
@@ -317,6 +320,19 @@ struct ftrace_event_file { | |||
317 | } \ | 320 | } \ |
318 | early_initcall(trace_init_flags_##name); | 321 | early_initcall(trace_init_flags_##name); |
319 | 322 | ||
323 | #define __TRACE_EVENT_PERF_PERM(name, expr...) \ | ||
324 | static int perf_perm_##name(struct ftrace_event_call *tp_event, \ | ||
325 | struct perf_event *p_event) \ | ||
326 | { \ | ||
327 | return ({ expr; }); \ | ||
328 | } \ | ||
329 | static int __init trace_init_perf_perm_##name(void) \ | ||
330 | { \ | ||
331 | event_##name.perf_perm = &perf_perm_##name; \ | ||
332 | return 0; \ | ||
333 | } \ | ||
334 | early_initcall(trace_init_perf_perm_##name); | ||
335 | |||
320 | #define PERF_MAX_TRACE_SIZE 2048 | 336 | #define PERF_MAX_TRACE_SIZE 2048 |
321 | 337 | ||
322 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ | 338 | #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index ebeab360d851..f16dc0a40049 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -267,6 +267,8 @@ static inline void tracepoint_synchronize_unregister(void) | |||
267 | 267 | ||
268 | #define TRACE_EVENT_FLAGS(event, flag) | 268 | #define TRACE_EVENT_FLAGS(event, flag) |
269 | 269 | ||
270 | #define TRACE_EVENT_PERF_PERM(event, expr...) | ||
271 | |||
270 | #endif /* DECLARE_TRACE */ | 272 | #endif /* DECLARE_TRACE */ |
271 | 273 | ||
272 | #ifndef TRACE_EVENT | 274 | #ifndef TRACE_EVENT |
@@ -399,4 +401,6 @@ static inline void tracepoint_synchronize_unregister(void) | |||
399 | 401 | ||
400 | #define TRACE_EVENT_FLAGS(event, flag) | 402 | #define TRACE_EVENT_FLAGS(event, flag) |
401 | 403 | ||
404 | #define TRACE_EVENT_PERF_PERM(event, expr...) | ||
405 | |||
402 | #endif /* ifdef TRACE_EVENT (see note above) */ | 406 | #endif /* ifdef TRACE_EVENT (see note above) */ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index d17a35c6537e..5c38606613d8 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -90,6 +90,10 @@ | |||
90 | #define TRACE_EVENT_FLAGS(name, value) \ | 90 | #define TRACE_EVENT_FLAGS(name, value) \ |
91 | __TRACE_EVENT_FLAGS(name, value) | 91 | __TRACE_EVENT_FLAGS(name, value) |
92 | 92 | ||
93 | #undef TRACE_EVENT_PERF_PERM | ||
94 | #define TRACE_EVENT_PERF_PERM(name, expr...) \ | ||
95 | __TRACE_EVENT_PERF_PERM(name, expr) | ||
96 | |||
93 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 97 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
94 | 98 | ||
95 | 99 | ||
@@ -140,6 +144,9 @@ | |||
140 | #undef TRACE_EVENT_FLAGS | 144 | #undef TRACE_EVENT_FLAGS |
141 | #define TRACE_EVENT_FLAGS(event, flag) | 145 | #define TRACE_EVENT_FLAGS(event, flag) |
142 | 146 | ||
147 | #undef TRACE_EVENT_PERF_PERM | ||
148 | #define TRACE_EVENT_PERF_PERM(event, expr...) | ||
149 | |||
143 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 150 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
144 | 151 | ||
145 | /* | 152 | /* |
diff --git a/kernel/events/core.c b/kernel/events/core.c index d724e7757cd1..72348dc192c1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -5680,11 +5680,6 @@ static void swevent_hlist_put(struct perf_event *event) | |||
5680 | { | 5680 | { |
5681 | int cpu; | 5681 | int cpu; |
5682 | 5682 | ||
5683 | if (event->cpu != -1) { | ||
5684 | swevent_hlist_put_cpu(event, event->cpu); | ||
5685 | return; | ||
5686 | } | ||
5687 | |||
5688 | for_each_possible_cpu(cpu) | 5683 | for_each_possible_cpu(cpu) |
5689 | swevent_hlist_put_cpu(event, cpu); | 5684 | swevent_hlist_put_cpu(event, cpu); |
5690 | } | 5685 | } |
@@ -5718,9 +5713,6 @@ static int swevent_hlist_get(struct perf_event *event) | |||
5718 | int err; | 5713 | int err; |
5719 | int cpu, failed_cpu; | 5714 | int cpu, failed_cpu; |
5720 | 5715 | ||
5721 | if (event->cpu != -1) | ||
5722 | return swevent_hlist_get_cpu(event, event->cpu); | ||
5723 | |||
5724 | get_online_cpus(); | 5716 | get_online_cpus(); |
5725 | for_each_possible_cpu(cpu) { | 5717 | for_each_possible_cpu(cpu) { |
5726 | err = swevent_hlist_get_cpu(event, cpu); | 5718 | err = swevent_hlist_get_cpu(event, cpu); |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 78e27e3b52ac..e854f420e033 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -24,6 +24,12 @@ static int total_ref_count; | |||
24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, | 24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, |
25 | struct perf_event *p_event) | 25 | struct perf_event *p_event) |
26 | { | 26 | { |
27 | if (tp_event->perf_perm) { | ||
28 | int ret = tp_event->perf_perm(tp_event, p_event); | ||
29 | if (ret) | ||
30 | return ret; | ||
31 | } | ||
32 | |||
27 | /* The ftrace function trace is allowed only for root. */ | 33 | /* The ftrace function trace is allowed only for root. */ |
28 | if (ftrace_event_is_function(tp_event) && | 34 | if (ftrace_event_is_function(tp_event) && |
29 | perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) | 35 | perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) |
@@ -173,7 +179,7 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event, | |||
173 | int perf_trace_init(struct perf_event *p_event) | 179 | int perf_trace_init(struct perf_event *p_event) |
174 | { | 180 | { |
175 | struct ftrace_event_call *tp_event; | 181 | struct ftrace_event_call *tp_event; |
176 | int event_id = p_event->attr.config; | 182 | u64 event_id = p_event->attr.config; |
177 | int ret = -EINVAL; | 183 | int ret = -EINVAL; |
178 | 184 | ||
179 | mutex_lock(&event_mutex); | 185 | mutex_lock(&event_mutex); |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 0362d575de7d..217c82ee3665 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -1606,6 +1606,24 @@ process_arg(struct event_format *event, struct print_arg *arg, char **tok) | |||
1606 | static enum event_type | 1606 | static enum event_type |
1607 | process_op(struct event_format *event, struct print_arg *arg, char **tok); | 1607 | process_op(struct event_format *event, struct print_arg *arg, char **tok); |
1608 | 1608 | ||
1609 | /* | ||
1610 | * For __print_symbolic() and __print_flags, we need to completely | ||
1611 | * evaluate the first argument, which defines what to print next. | ||
1612 | */ | ||
1613 | static enum event_type | ||
1614 | process_field_arg(struct event_format *event, struct print_arg *arg, char **tok) | ||
1615 | { | ||
1616 | enum event_type type; | ||
1617 | |||
1618 | type = process_arg(event, arg, tok); | ||
1619 | |||
1620 | while (type == EVENT_OP) { | ||
1621 | type = process_op(event, arg, tok); | ||
1622 | } | ||
1623 | |||
1624 | return type; | ||
1625 | } | ||
1626 | |||
1609 | static enum event_type | 1627 | static enum event_type |
1610 | process_cond(struct event_format *event, struct print_arg *top, char **tok) | 1628 | process_cond(struct event_format *event, struct print_arg *top, char **tok) |
1611 | { | 1629 | { |
@@ -2371,7 +2389,7 @@ process_flags(struct event_format *event, struct print_arg *arg, char **tok) | |||
2371 | goto out_free; | 2389 | goto out_free; |
2372 | } | 2390 | } |
2373 | 2391 | ||
2374 | type = process_arg(event, field, &token); | 2392 | type = process_field_arg(event, field, &token); |
2375 | 2393 | ||
2376 | /* Handle operations in the first argument */ | 2394 | /* Handle operations in the first argument */ |
2377 | while (type == EVENT_OP) | 2395 | while (type == EVENT_OP) |
@@ -2424,7 +2442,8 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok) | |||
2424 | goto out_free; | 2442 | goto out_free; |
2425 | } | 2443 | } |
2426 | 2444 | ||
2427 | type = process_arg(event, field, &token); | 2445 | type = process_field_arg(event, field, &token); |
2446 | |||
2428 | if (test_type_token(type, token, EVENT_DELIM, ",")) | 2447 | if (test_type_token(type, token, EVENT_DELIM, ",")) |
2429 | goto out_free_field; | 2448 | goto out_free_field; |
2430 | 2449 | ||
@@ -3446,7 +3465,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg | |||
3446 | * is in the bottom half of the 32 bit field. | 3465 | * is in the bottom half of the 32 bit field. |
3447 | */ | 3466 | */ |
3448 | offset &= 0xffff; | 3467 | offset &= 0xffff; |
3449 | val = (unsigned long long)(data + offset); | 3468 | val = (unsigned long long)((unsigned long)data + offset); |
3450 | break; | 3469 | break; |
3451 | default: /* not sure what to do there */ | 3470 | default: /* not sure what to do there */ |
3452 | return 0; | 3471 | return 0; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 369c03648f88..1cd035708931 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2078,8 +2078,10 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2078 | if (evsel->idx == (int) desc[i].leader_idx) { | 2078 | if (evsel->idx == (int) desc[i].leader_idx) { |
2079 | evsel->leader = evsel; | 2079 | evsel->leader = evsel; |
2080 | /* {anon_group} is a dummy name */ | 2080 | /* {anon_group} is a dummy name */ |
2081 | if (strcmp(desc[i].name, "{anon_group}")) | 2081 | if (strcmp(desc[i].name, "{anon_group}")) { |
2082 | evsel->group_name = desc[i].name; | 2082 | evsel->group_name = desc[i].name; |
2083 | desc[i].name = NULL; | ||
2084 | } | ||
2083 | evsel->nr_members = desc[i].nr_members; | 2085 | evsel->nr_members = desc[i].nr_members; |
2084 | 2086 | ||
2085 | if (i >= nr_groups || nr > 0) { | 2087 | if (i >= nr_groups || nr > 0) { |
@@ -2105,7 +2107,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2105 | 2107 | ||
2106 | ret = 0; | 2108 | ret = 0; |
2107 | out_free: | 2109 | out_free: |
2108 | while ((int) --i >= 0) | 2110 | for (i = 0; i < nr_groups; i++) |
2109 | free(desc[i].name); | 2111 | free(desc[i].name); |
2110 | free(desc); | 2112 | free(desc); |
2111 | 2113 | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index cd8e2f592719..49eaf1d7d89d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -70,14 +70,13 @@ int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) | |||
70 | /* Override latest entry if it had no specific time coverage */ | 70 | /* Override latest entry if it had no specific time coverage */ |
71 | if (!curr->start) { | 71 | if (!curr->start) { |
72 | comm__override(curr, str, timestamp); | 72 | comm__override(curr, str, timestamp); |
73 | return 0; | 73 | } else { |
74 | new = comm__new(str, timestamp); | ||
75 | if (!new) | ||
76 | return -ENOMEM; | ||
77 | list_add(&new->list, &thread->comm_list); | ||
74 | } | 78 | } |
75 | 79 | ||
76 | new = comm__new(str, timestamp); | ||
77 | if (!new) | ||
78 | return -ENOMEM; | ||
79 | |||
80 | list_add(&new->list, &thread->comm_list); | ||
81 | thread->comm_set = true; | 80 | thread->comm_set = true; |
82 | 81 | ||
83 | return 0; | 82 | return 0; |