Skip to content

Commit 752be5c

Browse files
mhiramatrostedt
authored andcommitted
tracing/eprobe: Add eprobe filter support
Add the filter option to the event probe. This is useful if user wants to derive a new event based on the condition of the original event. E.g. echo 'e:egroup/stat_runtime_4core sched/sched_stat_runtime \ runtime=$runtime:u32 if cpu < 4' >> ../dynamic_events Then it can filter the events only on first 4 cores. Note that the fields used for 'if' must be the fields in the original events, not eprobe events. Link: https://lkml.kernel.org/r/165932114513.2850673.2592206685744598080.stgit@devnote2 Cc: Tzvetomir Stoyanov <[email protected]> Cc: Ingo Molnar <[email protected]> Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent f76349c commit 752be5c

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

kernel/trace/trace_eprobe.c

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ struct trace_eprobe {
2626
/* tracepoint event */
2727
const char *event_name;
2828

29+
/* filter string for the tracepoint */
30+
char *filter_str;
31+
2932
struct trace_event_call *event;
3033

3134
struct dyn_event devent;
@@ -664,14 +667,15 @@ static struct event_trigger_data *
664667
new_eprobe_trigger(struct trace_eprobe *ep, struct trace_event_file *file)
665668
{
666669
struct event_trigger_data *trigger;
670+
struct event_filter *filter = NULL;
667671
struct eprobe_data *edata;
672+
int ret;
668673

669674
edata = kzalloc(sizeof(*edata), GFP_KERNEL);
670675
trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
671676
if (!trigger || !edata) {
672-
kfree(edata);
673-
kfree(trigger);
674-
return ERR_PTR(-ENOMEM);
677+
ret = -ENOMEM;
678+
goto error;
675679
}
676680

677681
trigger->flags = EVENT_TRIGGER_FL_PROBE;
@@ -686,13 +690,25 @@ new_eprobe_trigger(struct trace_eprobe *ep, struct trace_event_file *file)
686690
trigger->cmd_ops = &event_trigger_cmd;
687691

688692
INIT_LIST_HEAD(&trigger->list);
689-
RCU_INIT_POINTER(trigger->filter, NULL);
693+
694+
if (ep->filter_str) {
695+
ret = create_event_filter(file->tr, file->event_call,
696+
ep->filter_str, false, &filter);
697+
if (ret)
698+
goto error;
699+
}
700+
RCU_INIT_POINTER(trigger->filter, filter);
690701

691702
edata->file = file;
692703
edata->ep = ep;
693704
trigger->private_data = edata;
694705

695706
return trigger;
707+
error:
708+
free_event_filter(filter);
709+
kfree(edata);
710+
kfree(trigger);
711+
return ERR_PTR(ret);
696712
}
697713

698714
static int enable_eprobe(struct trace_eprobe *ep,
@@ -726,6 +742,7 @@ static int disable_eprobe(struct trace_eprobe *ep,
726742
{
727743
struct event_trigger_data *trigger = NULL, *iter;
728744
struct trace_event_file *file;
745+
struct event_filter *filter;
729746
struct eprobe_data *edata;
730747

731748
file = find_event_file(tr, ep->event_system, ep->event_name);
@@ -752,6 +769,10 @@ static int disable_eprobe(struct trace_eprobe *ep,
752769
/* Make sure nothing is using the edata or trigger */
753770
tracepoint_synchronize_unregister();
754771

772+
filter = rcu_access_pointer(trigger->filter);
773+
774+
if (filter)
775+
free_event_filter(filter);
755776
kfree(edata);
756777
kfree(trigger);
757778

@@ -927,12 +948,62 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
927948
return ret;
928949
}
929950

951+
static int trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, const char *argv[])
952+
{
953+
struct event_filter *dummy;
954+
int i, ret, len = 0;
955+
char *p;
956+
957+
if (argc == 0) {
958+
trace_probe_log_err(0, NO_EP_FILTER);
959+
return -EINVAL;
960+
}
961+
962+
/* Recover the filter string */
963+
for (i = 0; i < argc; i++)
964+
len += strlen(argv[i]) + 1;
965+
966+
ep->filter_str = kzalloc(len, GFP_KERNEL);
967+
if (!ep->filter_str)
968+
return -ENOMEM;
969+
970+
p = ep->filter_str;
971+
for (i = 0; i < argc; i++) {
972+
ret = snprintf(p, len, "%s ", argv[i]);
973+
if (ret < 0)
974+
goto error;
975+
if (ret > len) {
976+
ret = -E2BIG;
977+
goto error;
978+
}
979+
p += ret;
980+
len -= ret;
981+
}
982+
p[-1] = '\0';
983+
984+
/*
985+
* Ensure the filter string can be parsed correctly. Note, this
986+
* filter string is for the original event, not for the eprobe.
987+
*/
988+
ret = create_event_filter(top_trace_array(), ep->event, ep->filter_str,
989+
true, &dummy);
990+
free_event_filter(dummy);
991+
if (ret)
992+
goto error;
993+
994+
return 0;
995+
error:
996+
kfree(ep->filter_str);
997+
ep->filter_str = NULL;
998+
return ret;
999+
}
1000+
9301001
static int __trace_eprobe_create(int argc, const char *argv[])
9311002
{
9321003
/*
9331004
* Argument syntax:
934-
* e[:[GRP/][ENAME]] SYSTEM.EVENT [FETCHARGS]
935-
* Fetch args:
1005+
* e[:[GRP/][ENAME]] SYSTEM.EVENT [FETCHARGS] [if FILTER]
1006+
* Fetch args (no space):
9361007
* <name>=$<field>[:TYPE]
9371008
*/
9381009
const char *event = NULL, *group = EPROBE_EVENT_SYSTEM;
@@ -942,8 +1013,8 @@ static int __trace_eprobe_create(int argc, const char *argv[])
9421013
char buf1[MAX_EVENT_NAME_LEN];
9431014
char buf2[MAX_EVENT_NAME_LEN];
9441015
char gbuf[MAX_EVENT_NAME_LEN];
945-
int ret = 0;
946-
int i;
1016+
int ret = 0, filter_idx = 0;
1017+
int i, filter_cnt;
9471018

9481019
if (argc < 2 || argv[0][0] != 'e')
9491020
return -ECANCELED;
@@ -973,6 +1044,15 @@ static int __trace_eprobe_create(int argc, const char *argv[])
9731044
event = buf1;
9741045
}
9751046

1047+
for (i = 2; i < argc; i++) {
1048+
if (!strcmp(argv[i], "if")) {
1049+
filter_idx = i + 1;
1050+
filter_cnt = argc - filter_idx;
1051+
argc = i;
1052+
break;
1053+
}
1054+
}
1055+
9761056
mutex_lock(&event_mutex);
9771057
event_call = find_and_get_event(sys_name, sys_event);
9781058
ep = alloc_event_probe(group, event, event_call, argc - 2);
@@ -988,6 +1068,14 @@ static int __trace_eprobe_create(int argc, const char *argv[])
9881068
goto error;
9891069
}
9901070

1071+
if (filter_idx) {
1072+
trace_probe_log_set_index(filter_idx);
1073+
ret = trace_eprobe_parse_filter(ep, filter_cnt, argv + filter_idx);
1074+
if (ret)
1075+
goto parse_error;
1076+
} else
1077+
ep->filter_str = NULL;
1078+
9911079
argc -= 2; argv += 2;
9921080
/* parse arguments */
9931081
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {

kernel/trace/trace_probe.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
445445
C(SAME_PROBE, "There is already the exact same probe event"),\
446446
C(NO_EVENT_INFO, "This requires both group and event name to attach"),\
447447
C(BAD_ATTACH_EVENT, "Attached event does not exist"),\
448-
C(BAD_ATTACH_ARG, "Attached event does not have this field"),
448+
C(BAD_ATTACH_ARG, "Attached event does not have this field"),\
449+
C(NO_EP_FILTER, "No filter rule after 'if'"),
449450

450451
#undef C
451452
#define C(a, b) TP_ERR_##a

0 commit comments

Comments
 (0)