Having following commands running concurently: # perf record -e ftrace:function -a -o krava.data sleep 10 # perf record -e ftrace:function --filter 'ip == SyS_read' ls
will endup in the latter one failing on the filter rules and store all functions (in perf.data) as instructed by the first record instead of just SyS_read records. The reason is that we don't check the ftrace_ops that triggered the event with event's ftrace_ops. Hence once running together the event from latter perf will get all the data of the event from the first one. Fixing this by having separate handler for ftrace:function event that actualy checks ftrace_ops against event. Signed-off-by: Jiri Olsa <[email protected]> --- include/linux/perf_event.h | 2 ++ kernel/events/core.c | 26 ++++++++++++++++++++++++++ kernel/trace/trace_event_perf.c | 3 +-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f9828a48f16a..be1ad1ef47f3 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1010,6 +1010,8 @@ extern void perf_tp_event(u64 addr, u64 count, void *record, struct hlist_head *head, int rctx, struct task_struct *task); extern void perf_bp_event(struct perf_event *event, void *data); +void perf_ftrace_ops_event(struct ftrace_ops *ops, void *record, int entry_size, + struct pt_regs *regs, struct hlist_head *head, int rctx); #ifndef perf_misc_flags # define perf_misc_flags(regs) \ diff --git a/kernel/events/core.c b/kernel/events/core.c index 5854fcf7f05a..1ec33bebd39a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -44,6 +44,7 @@ #include <linux/compat.h> #include <linux/bpf.h> #include <linux/filter.h> +#include <linux/ftrace.h> #include "internal.h" @@ -6950,6 +6951,31 @@ static int perf_tp_event_match(struct perf_event *event, return 1; } +#ifdef CONFIG_FUNCTION_TRACER +void perf_ftrace_ops_event(struct ftrace_ops *ops, void *record, int entry_size, + struct pt_regs *regs, struct hlist_head *head, int rctx) +{ + struct perf_sample_data data; + struct perf_event *event; + + struct perf_raw_record raw = { + .size = entry_size, + .data = record, + }; + + perf_sample_data_init(&data, 0, 0); + data.raw = &raw; + + hlist_for_each_entry_rcu(event, head, hlist_entry) { + if ((&event->ftrace_ops == ops) && + (perf_tp_event_match(event, &data, regs))) + perf_swevent_event(event, 1, &data, regs); + } + + perf_swevent_put_recursion_context(rctx); +} +#endif + void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, struct pt_regs *regs, struct hlist_head *head, int rctx, struct task_struct *task) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index cc9f7a9319be..fa1f12ef3ba3 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -324,8 +324,7 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, entry->ip = ip; entry->parent_ip = parent_ip; - perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, - 1, ®s, head, NULL); + perf_ftrace_ops_event(ops, entry, ENTRY_SIZE, ®s, head, rctx); #undef ENTRY_SIZE } -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

