summaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorTom Zanussi <tzanussi@gmail.com>2009-04-28 03:04:59 -0500
committerIngo Molnar <mingo@elte.hu>2009-04-29 14:06:11 +0200
commit8b3725621074040d380664964ffbc40610aef8c6 (patch)
tree3a78292a08cc9c87653be2e42d084a7d7f5989bf /kernel/trace/trace_events.c
parenta118e4d1402f1349fe3d953493e4168a300a752d (diff)
tracing/filters: a better event parser
Replace the current event parser hack with a better one. Filters are no longer specified predicate by predicate, but all at once and can use parens and any of the following operators: numeric fields: ==, !=, <, <=, >, >= string fields: ==, != predicates can be combined with the logical operators: &&, || examples: "common_preempt_count > 4" > filter "((sig >= 10 && sig < 15) || sig == 17) && comm != bash" > filter If there was an error, the erroneous string along with an error message can be seen by looking at the filter e.g.: ((sig >= 10 && sig < 15) || dsig == 17) && comm != bash ^ parse_error: Field not found Currently the caret for an error always appears at the beginning of the filter; a real position should be used, but the error message should be useful even without it. To clear a filter, '0' can be written to the filter file. Filters can also be set or cleared for a complete subsystem by writing the same filter as would be written to an individual event to the filter file at the root of the subsytem. Note however, that if any event in the subsystem lacks a field specified in the filter being set, the set will fail and all filters in the subsytem are automatically cleared. This change from the previous version was made because using only the fields that happen to exist for a given event would most likely result in a meaningless filter. Because the logical operators are now implemented as predicates, the maximum number of predicates in a filter was increased from 8 to 16. [ Impact: add new, extended trace-filter implementation ] Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: fweisbec@gmail.com Cc: Li Zefan <lizf@cn.fujitsu.com> LKML-Reference: <1240905899.6416.121.camel@tropicana> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c86
1 files changed, 35 insertions, 51 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index bbbea747937..f789ca540fe 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -492,7 +492,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
trace_seq_init(s);
- filter_print_preds(call, s);
+ print_event_filter(call, s);
r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
kfree(s);
@@ -505,40 +505,26 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct ftrace_event_call *call = filp->private_data;
- char buf[64], *pbuf = buf;
- struct filter_pred *pred;
+ char *buf;
int err;
- if (cnt >= sizeof(buf))
+ if (cnt >= PAGE_SIZE)
return -EINVAL;
- if (copy_from_user(&buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = '\0';
-
- pred = kzalloc(sizeof(*pred), GFP_KERNEL);
- if (!pred)
+ buf = (char *)__get_free_page(GFP_TEMPORARY);
+ if (!buf)
return -ENOMEM;
- err = filter_parse(&pbuf, pred);
- if (err < 0) {
- filter_free_pred(pred);
- return err;
- }
-
- if (pred->clear) {
- filter_disable_preds(call);
- filter_free_pred(pred);
- return cnt;
+ if (copy_from_user(buf, ubuf, cnt)) {
+ free_page((unsigned long) buf);
+ return -EFAULT;
}
+ buf[cnt] = '\0';
- err = filter_add_pred(call, pred);
- if (err < 0) {
- filter_free_pred(pred);
+ err = apply_event_filter(call, buf);
+ free_page((unsigned long) buf);
+ if (err < 0)
return err;
- }
-
- filter_free_pred(pred);
*ppos += cnt;
@@ -562,7 +548,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
trace_seq_init(s);
- filter_print_subsystem_preds(system, s);
+ print_subsystem_event_filter(system, s);
r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
kfree(s);
@@ -575,38 +561,26 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct event_subsystem *system = filp->private_data;
- char buf[64], *pbuf = buf;
- struct filter_pred *pred;
+ char *buf;
int err;
- if (cnt >= sizeof(buf))
+ if (cnt >= PAGE_SIZE)
return -EINVAL;
- if (copy_from_user(&buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = '\0';
-
- pred = kzalloc(sizeof(*pred), GFP_KERNEL);
- if (!pred)
+ buf = (char *)__get_free_page(GFP_TEMPORARY);
+ if (!buf)
return -ENOMEM;
- err = filter_parse(&pbuf, pred);
- if (err < 0) {
- filter_free_pred(pred);
- return err;
- }
-
- if (pred->clear) {
- filter_free_subsystem_preds(system);
- filter_free_pred(pred);
- return cnt;
+ if (copy_from_user(buf, ubuf, cnt)) {
+ free_page((unsigned long) buf);
+ return -EFAULT;
}
+ buf[cnt] = '\0';
- err = filter_add_subsystem_pred(system, pred);
- if (err < 0) {
- filter_free_pred(pred);
+ err = apply_subsystem_event_filter(system, buf);
+ free_page((unsigned long) buf);
+ if (err < 0)
return err;
- }
*ppos += cnt;
@@ -760,11 +734,21 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
system->filter = NULL;
+ system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
+ if (!system->filter) {
+ pr_warning("Could not allocate filter for subsystem "
+ "'%s'\n", name);
+ return system->entry;
+ }
+
entry = debugfs_create_file("filter", 0644, system->entry, system,
&ftrace_subsystem_filter_fops);
- if (!entry)
+ if (!entry) {
+ kfree(system->filter);
+ system->filter = NULL;
pr_warning("Could not create debugfs "
"'%s/filter' entry\n", name);
+ }
return system->entry;
}