Commit 5500fa51199aee770ce53718853732600543619e

Authored by Jiri Olsa
Committed by Steven Rostedt
1 parent 02aa3162ed

ftrace, perf: Add filter support for function trace event

Adding support to filter function trace event via perf
interface. It is now possible to use filter interface
in the perf tool like:

  perf record -e ftrace:function --filter="(ip == mm_*)" ls

The filter syntax is restricted to the the 'ip' field only,
and following operators are accepted '==' '!=' '||', ending
up with the filter strings like:

  ip == f1[, ]f2 ... || ip != f3[, ]f4 ...

with comma ',' or space ' ' as a function separator. If the
space ' ' is used as a separator, the right side of the
assignment needs to be enclosed in double quotes '"', e.g.:

  perf record -e ftrace:function --filter '(ip == do_execve,sys_*,ext*)' ls
  perf record -e ftrace:function --filter '(ip == "do_execve,sys_*,ext*")' ls
  perf record -e ftrace:function --filter '(ip == "do_execve sys_* ext*")' ls

The '==' operator adds trace filter with same effect as would
be added via set_ftrace_filter file.

The '!=' operator adds trace filter with same effect as would
be added via set_ftrace_notrace file.

The right side of the '!=', '==' operators is list of functions
or regexp. to be added to filter separated by space.

The '||' operator is used for connecting multiple filter definitions
together. It is possible to have more than one '==' and '!='
operators within one filter string.

Link: http://lkml.kernel.org/r/1329317514-8131-8-git-send-email-jolsa@redhat.com

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Showing 5 changed files with 172 additions and 12 deletions Side-by-side Diff

include/linux/ftrace.h
... ... @@ -250,6 +250,7 @@
250 250 int len, int reset);
251 251 void ftrace_set_global_filter(unsigned char *buf, int len, int reset);
252 252 void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
  253 +void ftrace_free_filter(struct ftrace_ops *ops);
253 254  
254 255 int register_ftrace_command(struct ftrace_func_command *cmd);
255 256 int unregister_ftrace_command(struct ftrace_func_command *cmd);
... ... @@ -380,9 +381,6 @@
380 381 #else
381 382 static inline int skip_trace(unsigned long ip) { return 0; }
382 383 static inline int ftrace_force_update(void) { return 0; }
383   -static inline void ftrace_set_filter(unsigned char *buf, int len, int reset)
384   -{
385   -}
386 384 static inline void ftrace_disable_daemon(void) { }
387 385 static inline void ftrace_enable_daemon(void) { }
388 386 static inline void ftrace_release_mod(struct module *mod) {}
... ... @@ -406,6 +404,9 @@
406 404 */
407 405 #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
408 406 #define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
  407 +#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
  408 +#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
  409 +#define ftrace_free_filter(ops) do { } while (0)
409 410  
410 411 static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
411 412 size_t cnt, loff_t *ppos) { return -ENODEV; }
kernel/trace/ftrace.c
... ... @@ -1186,6 +1186,12 @@
1186 1186 call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu);
1187 1187 }
1188 1188  
  1189 +void ftrace_free_filter(struct ftrace_ops *ops)
  1190 +{
  1191 + free_ftrace_hash(ops->filter_hash);
  1192 + free_ftrace_hash(ops->notrace_hash);
  1193 +}
  1194 +
1189 1195 static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
1190 1196 {
1191 1197 struct ftrace_hash *hash;
kernel/trace/trace.h
... ... @@ -776,9 +776,7 @@
776 776 u64 val;
777 777 struct regex regex;
778 778 unsigned short *ops;
779   -#ifdef CONFIG_FTRACE_STARTUP_TEST
780 779 struct ftrace_event_field *field;
781   -#endif
782 780 int offset;
783 781 int not;
784 782 int op;
kernel/trace/trace_event_perf.c
... ... @@ -298,7 +298,9 @@
298 298 static int perf_ftrace_function_unregister(struct perf_event *event)
299 299 {
300 300 struct ftrace_ops *ops = &event->ftrace_ops;
301   - return unregister_ftrace_function(ops);
  301 + int ret = unregister_ftrace_function(ops);
  302 + ftrace_free_filter(ops);
  303 + return ret;
302 304 }
303 305  
304 306 static void perf_ftrace_function_enable(struct perf_event *event)
kernel/trace/trace_events_filter.c
... ... @@ -81,6 +81,7 @@
81 81 FILT_ERR_TOO_MANY_PREDS,
82 82 FILT_ERR_MISSING_FIELD,
83 83 FILT_ERR_INVALID_FILTER,
  84 + FILT_ERR_IP_FIELD_ONLY,
84 85 };
85 86  
86 87 static char *err_text[] = {
... ... @@ -96,6 +97,7 @@
96 97 "Too many terms in predicate expression",
97 98 "Missing field name and/or value",
98 99 "Meaningless filter expression",
  100 + "Only 'ip' field is supported for function trace",
99 101 };
100 102  
101 103 struct opstack_op {
... ... @@ -991,7 +993,12 @@
991 993 fn = filter_pred_strloc;
992 994 else
993 995 fn = filter_pred_pchar;
994   - } else if (!is_function_field(field)) {
  996 + } else if (is_function_field(field)) {
  997 + if (strcmp(field->name, "ip")) {
  998 + parse_error(ps, FILT_ERR_IP_FIELD_ONLY, 0);
  999 + return -EINVAL;
  1000 + }
  1001 + } else {
995 1002 if (field->is_signed)
996 1003 ret = strict_strtoll(pred->regex.pattern, 0, &val);
997 1004 else
998 1005  
... ... @@ -1338,10 +1345,7 @@
1338 1345  
1339 1346 strcpy(pred.regex.pattern, operand2);
1340 1347 pred.regex.len = strlen(pred.regex.pattern);
1341   -
1342   -#ifdef CONFIG_FTRACE_STARTUP_TEST
1343 1348 pred.field = field;
1344   -#endif
1345 1349 return init_pred(ps, field, &pred) ? NULL : &pred;
1346 1350 }
1347 1351  
... ... @@ -1954,6 +1958,148 @@
1954 1958 __free_filter(filter);
1955 1959 }
1956 1960  
  1961 +struct function_filter_data {
  1962 + struct ftrace_ops *ops;
  1963 + int first_filter;
  1964 + int first_notrace;
  1965 +};
  1966 +
  1967 +#ifdef CONFIG_FUNCTION_TRACER
  1968 +static char **
  1969 +ftrace_function_filter_re(char *buf, int len, int *count)
  1970 +{
  1971 + char *str, *sep, **re;
  1972 +
  1973 + str = kstrndup(buf, len, GFP_KERNEL);
  1974 + if (!str)
  1975 + return NULL;
  1976 +
  1977 + /*
  1978 + * The argv_split function takes white space
  1979 + * as a separator, so convert ',' into spaces.
  1980 + */
  1981 + while ((sep = strchr(str, ',')))
  1982 + *sep = ' ';
  1983 +
  1984 + re = argv_split(GFP_KERNEL, str, count);
  1985 + kfree(str);
  1986 + return re;
  1987 +}
  1988 +
  1989 +static int ftrace_function_set_regexp(struct ftrace_ops *ops, int filter,
  1990 + int reset, char *re, int len)
  1991 +{
  1992 + int ret;
  1993 +
  1994 + if (filter)
  1995 + ret = ftrace_set_filter(ops, re, len, reset);
  1996 + else
  1997 + ret = ftrace_set_notrace(ops, re, len, reset);
  1998 +
  1999 + return ret;
  2000 +}
  2001 +
  2002 +static int __ftrace_function_set_filter(int filter, char *buf, int len,
  2003 + struct function_filter_data *data)
  2004 +{
  2005 + int i, re_cnt, ret;
  2006 + int *reset;
  2007 + char **re;
  2008 +
  2009 + reset = filter ? &data->first_filter : &data->first_notrace;
  2010 +
  2011 + /*
  2012 + * The 'ip' field could have multiple filters set, separated
  2013 + * either by space or comma. We first cut the filter and apply
  2014 + * all pieces separatelly.
  2015 + */
  2016 + re = ftrace_function_filter_re(buf, len, &re_cnt);
  2017 + if (!re)
  2018 + return -EINVAL;
  2019 +
  2020 + for (i = 0; i < re_cnt; i++) {
  2021 + ret = ftrace_function_set_regexp(data->ops, filter, *reset,
  2022 + re[i], strlen(re[i]));
  2023 + if (ret)
  2024 + break;
  2025 +
  2026 + if (*reset)
  2027 + *reset = 0;
  2028 + }
  2029 +
  2030 + argv_free(re);
  2031 + return ret;
  2032 +}
  2033 +
  2034 +static int ftrace_function_check_pred(struct filter_pred *pred, int leaf)
  2035 +{
  2036 + struct ftrace_event_field *field = pred->field;
  2037 +
  2038 + if (leaf) {
  2039 + /*
  2040 + * Check the leaf predicate for function trace, verify:
  2041 + * - only '==' and '!=' is used
  2042 + * - the 'ip' field is used
  2043 + */
  2044 + if ((pred->op != OP_EQ) && (pred->op != OP_NE))
  2045 + return -EINVAL;
  2046 +
  2047 + if (strcmp(field->name, "ip"))
  2048 + return -EINVAL;
  2049 + } else {
  2050 + /*
  2051 + * Check the non leaf predicate for function trace, verify:
  2052 + * - only '||' is used
  2053 + */
  2054 + if (pred->op != OP_OR)
  2055 + return -EINVAL;
  2056 + }
  2057 +
  2058 + return 0;
  2059 +}
  2060 +
  2061 +static int ftrace_function_set_filter_cb(enum move_type move,
  2062 + struct filter_pred *pred,
  2063 + int *err, void *data)
  2064 +{
  2065 + /* Checking the node is valid for function trace. */
  2066 + if ((move != MOVE_DOWN) ||
  2067 + (pred->left != FILTER_PRED_INVALID)) {
  2068 + *err = ftrace_function_check_pred(pred, 0);
  2069 + } else {
  2070 + *err = ftrace_function_check_pred(pred, 1);
  2071 + if (*err)
  2072 + return WALK_PRED_ABORT;
  2073 +
  2074 + *err = __ftrace_function_set_filter(pred->op == OP_EQ,
  2075 + pred->regex.pattern,
  2076 + pred->regex.len,
  2077 + data);
  2078 + }
  2079 +
  2080 + return (*err) ? WALK_PRED_ABORT : WALK_PRED_DEFAULT;
  2081 +}
  2082 +
  2083 +static int ftrace_function_set_filter(struct perf_event *event,
  2084 + struct event_filter *filter)
  2085 +{
  2086 + struct function_filter_data data = {
  2087 + .first_filter = 1,
  2088 + .first_notrace = 1,
  2089 + .ops = &event->ftrace_ops,
  2090 + };
  2091 +
  2092 + return walk_pred_tree(filter->preds, filter->root,
  2093 + ftrace_function_set_filter_cb, &data);
  2094 +}
  2095 +#else
  2096 +static int ftrace_function_set_filter(struct perf_event *event,
  2097 + struct event_filter *filter)
  2098 +{
  2099 + return -ENODEV;
  2100 +}
  2101 +#endif /* CONFIG_FUNCTION_TRACER */
  2102 +
1957 2103 int ftrace_profile_set_filter(struct perf_event *event, int event_id,
1958 2104 char *filter_str)
1959 2105 {
1960 2106  
... ... @@ -1974,9 +2120,16 @@
1974 2120 goto out_unlock;
1975 2121  
1976 2122 err = create_filter(call, filter_str, false, &filter);
1977   - if (!err)
1978   - event->filter = filter;
  2123 + if (err)
  2124 + goto free_filter;
  2125 +
  2126 + if (ftrace_event_is_function(call))
  2127 + err = ftrace_function_set_filter(event, filter);
1979 2128 else
  2129 + event->filter = filter;
  2130 +
  2131 +free_filter:
  2132 + if (err || ftrace_event_is_function(call))
1980 2133 __free_filter(filter);
1981 2134  
1982 2135 out_unlock: