aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/trace/irq_vectors.h11
-rw-r--r--include/linux/ftrace_event.h16
-rw-r--r--include/linux/tracepoint.h4
-rw-r--r--include/trace/ftrace.h7
-rw-r--r--kernel/events/core.c8
-rw-r--r--kernel/trace/trace_event_perf.c8
-rw-r--r--tools/lib/traceevent/event-parse.c25
-rw-r--r--tools/perf/util/header.c6
-rw-r--r--tools/perf/util/thread.c11
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);
72DEFINE_IRQ_VECTOR_EVENT(irq_work); 72DEFINE_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 */
83TRACE_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;
24static int perf_trace_event_perm(struct ftrace_event_call *tp_event, 24static 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,
173int perf_trace_init(struct perf_event *p_event) 179int 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)
1606static enum event_type 1606static enum event_type
1607process_op(struct event_format *event, struct print_arg *arg, char **tok); 1607process_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 */
1613static enum event_type
1614process_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
1609static enum event_type 1627static enum event_type
1610process_cond(struct event_format *event, struct print_arg *top, char **tok) 1628process_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;
2107out_free: 2109out_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;