diff options
| -rw-r--r-- | include/linux/ftrace_event.h | 4 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 124 |
3 files changed, 87 insertions, 44 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 5c093ffc655b..26d3673d5143 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -101,6 +101,8 @@ void trace_current_buffer_discard_commit(struct ring_buffer_event *event); | |||
| 101 | 101 | ||
| 102 | void tracing_record_cmdline(struct task_struct *tsk); | 102 | void tracing_record_cmdline(struct task_struct *tsk); |
| 103 | 103 | ||
| 104 | struct event_filter; | ||
| 105 | |||
| 104 | struct ftrace_event_call { | 106 | struct ftrace_event_call { |
| 105 | struct list_head list; | 107 | struct list_head list; |
| 106 | char *name; | 108 | char *name; |
| @@ -116,7 +118,7 @@ struct ftrace_event_call { | |||
| 116 | int (*define_fields)(void); | 118 | int (*define_fields)(void); |
| 117 | struct list_head fields; | 119 | struct list_head fields; |
| 118 | int filter_active; | 120 | int filter_active; |
| 119 | void *filter; | 121 | struct event_filter *filter; |
| 120 | void *mod; | 122 | void *mod; |
| 121 | 123 | ||
| 122 | #ifdef CONFIG_EVENT_PROFILE | 124 | #ifdef CONFIG_EVENT_PROFILE |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 94305c7bc11c..758b0dbed552 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -750,13 +750,14 @@ struct event_filter { | |||
| 750 | int n_preds; | 750 | int n_preds; |
| 751 | struct filter_pred **preds; | 751 | struct filter_pred **preds; |
| 752 | char *filter_string; | 752 | char *filter_string; |
| 753 | bool no_reset; | ||
| 753 | }; | 754 | }; |
| 754 | 755 | ||
| 755 | struct event_subsystem { | 756 | struct event_subsystem { |
| 756 | struct list_head list; | 757 | struct list_head list; |
| 757 | const char *name; | 758 | const char *name; |
| 758 | struct dentry *entry; | 759 | struct dentry *entry; |
| 759 | void *filter; | 760 | struct event_filter *filter; |
| 760 | int nr_events; | 761 | int nr_events; |
| 761 | }; | 762 | }; |
| 762 | 763 | ||
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 1c80ef702b83..27c2dbea3710 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -420,7 +420,14 @@ oom: | |||
| 420 | } | 420 | } |
| 421 | EXPORT_SYMBOL_GPL(init_preds); | 421 | EXPORT_SYMBOL_GPL(init_preds); |
| 422 | 422 | ||
| 423 | static void filter_free_subsystem_preds(struct event_subsystem *system) | 423 | enum { |
| 424 | FILTER_DISABLE_ALL, | ||
| 425 | FILTER_INIT_NO_RESET, | ||
| 426 | FILTER_SKIP_NO_RESET, | ||
| 427 | }; | ||
| 428 | |||
| 429 | static void filter_free_subsystem_preds(struct event_subsystem *system, | ||
| 430 | int flag) | ||
| 424 | { | 431 | { |
| 425 | struct ftrace_event_call *call; | 432 | struct ftrace_event_call *call; |
| 426 | 433 | ||
| @@ -428,6 +435,14 @@ static void filter_free_subsystem_preds(struct event_subsystem *system) | |||
| 428 | if (!call->define_fields) | 435 | if (!call->define_fields) |
| 429 | continue; | 436 | continue; |
| 430 | 437 | ||
| 438 | if (flag == FILTER_INIT_NO_RESET) { | ||
| 439 | call->filter->no_reset = false; | ||
| 440 | continue; | ||
| 441 | } | ||
| 442 | |||
| 443 | if (flag == FILTER_SKIP_NO_RESET && call->filter->no_reset) | ||
| 444 | continue; | ||
| 445 | |||
| 431 | if (!strcmp(call->system, system->name)) { | 446 | if (!strcmp(call->system, system->name)) { |
| 432 | filter_disable_preds(call); | 447 | filter_disable_preds(call); |
| 433 | remove_filter_string(call->filter); | 448 | remove_filter_string(call->filter); |
| @@ -529,7 +544,8 @@ static filter_pred_fn_t select_comparison_fn(int op, int field_size, | |||
| 529 | 544 | ||
| 530 | static int filter_add_pred(struct filter_parse_state *ps, | 545 | static int filter_add_pred(struct filter_parse_state *ps, |
| 531 | struct ftrace_event_call *call, | 546 | struct ftrace_event_call *call, |
| 532 | struct filter_pred *pred) | 547 | struct filter_pred *pred, |
| 548 | bool dry_run) | ||
| 533 | { | 549 | { |
| 534 | struct ftrace_event_field *field; | 550 | struct ftrace_event_field *field; |
| 535 | filter_pred_fn_t fn; | 551 | filter_pred_fn_t fn; |
| @@ -541,10 +557,12 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 541 | 557 | ||
| 542 | if (pred->op == OP_AND) { | 558 | if (pred->op == OP_AND) { |
| 543 | pred->pop_n = 2; | 559 | pred->pop_n = 2; |
| 544 | return filter_add_pred_fn(ps, call, pred, filter_pred_and); | 560 | fn = filter_pred_and; |
| 561 | goto add_pred_fn; | ||
| 545 | } else if (pred->op == OP_OR) { | 562 | } else if (pred->op == OP_OR) { |
| 546 | pred->pop_n = 2; | 563 | pred->pop_n = 2; |
| 547 | return filter_add_pred_fn(ps, call, pred, filter_pred_or); | 564 | fn = filter_pred_or; |
| 565 | goto add_pred_fn; | ||
| 548 | } | 566 | } |
| 549 | 567 | ||
| 550 | field = find_event_field(call, pred->field_name); | 568 | field = find_event_field(call, pred->field_name); |
| @@ -567,9 +585,6 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 567 | else | 585 | else |
| 568 | fn = filter_pred_strloc; | 586 | fn = filter_pred_strloc; |
| 569 | pred->str_len = field->size; | 587 | pred->str_len = field->size; |
| 570 | if (pred->op == OP_NE) | ||
| 571 | pred->not = 1; | ||
| 572 | return filter_add_pred_fn(ps, call, pred, fn); | ||
| 573 | } else { | 588 | } else { |
| 574 | if (field->is_signed) | 589 | if (field->is_signed) |
| 575 | ret = strict_strtoll(pred->str_val, 0, &val); | 590 | ret = strict_strtoll(pred->str_val, 0, &val); |
| @@ -580,27 +595,33 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 580 | return -EINVAL; | 595 | return -EINVAL; |
| 581 | } | 596 | } |
| 582 | pred->val = val; | 597 | pred->val = val; |
| 583 | } | ||
| 584 | 598 | ||
| 585 | fn = select_comparison_fn(pred->op, field->size, field->is_signed); | 599 | fn = select_comparison_fn(pred->op, field->size, |
| 586 | if (!fn) { | 600 | field->is_signed); |
| 587 | parse_error(ps, FILT_ERR_INVALID_OP, 0); | 601 | if (!fn) { |
| 588 | return -EINVAL; | 602 | parse_error(ps, FILT_ERR_INVALID_OP, 0); |
| 603 | return -EINVAL; | ||
| 604 | } | ||
| 589 | } | 605 | } |
| 590 | 606 | ||
| 591 | if (pred->op == OP_NE) | 607 | if (pred->op == OP_NE) |
| 592 | pred->not = 1; | 608 | pred->not = 1; |
| 593 | 609 | ||
| 594 | return filter_add_pred_fn(ps, call, pred, fn); | 610 | add_pred_fn: |
| 611 | if (!dry_run) | ||
| 612 | return filter_add_pred_fn(ps, call, pred, fn); | ||
| 613 | return 0; | ||
| 595 | } | 614 | } |
| 596 | 615 | ||
| 597 | static int filter_add_subsystem_pred(struct filter_parse_state *ps, | 616 | static int filter_add_subsystem_pred(struct filter_parse_state *ps, |
| 598 | struct event_subsystem *system, | 617 | struct event_subsystem *system, |
| 599 | struct filter_pred *pred, | 618 | struct filter_pred *pred, |
| 600 | char *filter_string) | 619 | char *filter_string, |
| 620 | bool dry_run) | ||
| 601 | { | 621 | { |
| 602 | struct ftrace_event_call *call; | 622 | struct ftrace_event_call *call; |
| 603 | int err = 0; | 623 | int err = 0; |
| 624 | bool fail = true; | ||
| 604 | 625 | ||
| 605 | list_for_each_entry(call, &ftrace_events, list) { | 626 | list_for_each_entry(call, &ftrace_events, list) { |
| 606 | 627 | ||
| @@ -610,16 +631,24 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps, | |||
| 610 | if (strcmp(call->system, system->name)) | 631 | if (strcmp(call->system, system->name)) |
| 611 | continue; | 632 | continue; |
| 612 | 633 | ||
| 613 | err = filter_add_pred(ps, call, pred); | 634 | if (call->filter->no_reset) |
| 614 | if (err) { | 635 | continue; |
| 615 | filter_free_subsystem_preds(system); | 636 | |
| 616 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | 637 | err = filter_add_pred(ps, call, pred, dry_run); |
| 617 | goto out; | 638 | if (err) |
| 618 | } | 639 | call->filter->no_reset = true; |
| 619 | replace_filter_string(call->filter, filter_string); | 640 | else |
| 641 | fail = false; | ||
| 642 | |||
| 643 | if (!dry_run) | ||
| 644 | replace_filter_string(call->filter, filter_string); | ||
| 620 | } | 645 | } |
| 621 | out: | 646 | |
| 622 | return err; | 647 | if (fail) { |
| 648 | parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); | ||
| 649 | return err; | ||
| 650 | } | ||
| 651 | return 0; | ||
| 623 | } | 652 | } |
| 624 | 653 | ||
| 625 | static void parse_init(struct filter_parse_state *ps, | 654 | static void parse_init(struct filter_parse_state *ps, |
| @@ -978,12 +1007,14 @@ static int check_preds(struct filter_parse_state *ps) | |||
| 978 | static int replace_preds(struct event_subsystem *system, | 1007 | static int replace_preds(struct event_subsystem *system, |
| 979 | struct ftrace_event_call *call, | 1008 | struct ftrace_event_call *call, |
| 980 | struct filter_parse_state *ps, | 1009 | struct filter_parse_state *ps, |
| 981 | char *filter_string) | 1010 | char *filter_string, |
| 1011 | bool dry_run) | ||
| 982 | { | 1012 | { |
| 983 | char *operand1 = NULL, *operand2 = NULL; | 1013 | char *operand1 = NULL, *operand2 = NULL; |
| 984 | struct filter_pred *pred; | 1014 | struct filter_pred *pred; |
| 985 | struct postfix_elt *elt; | 1015 | struct postfix_elt *elt; |
| 986 | int err; | 1016 | int err; |
| 1017 | int n_preds = 0; | ||
| 987 | 1018 | ||
| 988 | err = check_preds(ps); | 1019 | err = check_preds(ps); |
| 989 | if (err) | 1020 | if (err) |
| @@ -1002,19 +1033,14 @@ static int replace_preds(struct event_subsystem *system, | |||
| 1002 | continue; | 1033 | continue; |
| 1003 | } | 1034 | } |
| 1004 | 1035 | ||
| 1036 | if (n_preds++ == MAX_FILTER_PRED) { | ||
| 1037 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); | ||
| 1038 | return -ENOSPC; | ||
| 1039 | } | ||
| 1040 | |||
| 1005 | if (elt->op == OP_AND || elt->op == OP_OR) { | 1041 | if (elt->op == OP_AND || elt->op == OP_OR) { |
| 1006 | pred = create_logical_pred(elt->op); | 1042 | pred = create_logical_pred(elt->op); |
| 1007 | if (call) | 1043 | goto add_pred; |
| 1008 | err = filter_add_pred(ps, call, pred); | ||
| 1009 | else | ||
| 1010 | err = filter_add_subsystem_pred(ps, system, | ||
| 1011 | pred, filter_string); | ||
| 1012 | filter_free_pred(pred); | ||
| 1013 | if (err) | ||
| 1014 | return err; | ||
| 1015 | |||
| 1016 | operand1 = operand2 = NULL; | ||
| 1017 | continue; | ||
| 1018 | } | 1044 | } |
| 1019 | 1045 | ||
| 1020 | if (!operand1 || !operand2) { | 1046 | if (!operand1 || !operand2) { |
| @@ -1023,11 +1049,12 @@ static int replace_preds(struct event_subsystem *system, | |||
| 1023 | } | 1049 | } |
| 1024 | 1050 | ||
| 1025 | pred = create_pred(elt->op, operand1, operand2); | 1051 | pred = create_pred(elt->op, operand1, operand2); |
| 1052 | add_pred: | ||
| 1026 | if (call) | 1053 | if (call) |
| 1027 | err = filter_add_pred(ps, call, pred); | 1054 | err = filter_add_pred(ps, call, pred, false); |
| 1028 | else | 1055 | else |
| 1029 | err = filter_add_subsystem_pred(ps, system, pred, | 1056 | err = filter_add_subsystem_pred(ps, system, pred, |
| 1030 | filter_string); | 1057 | filter_string, dry_run); |
| 1031 | filter_free_pred(pred); | 1058 | filter_free_pred(pred); |
| 1032 | if (err) | 1059 | if (err) |
| 1033 | return err; | 1060 | return err; |
| @@ -1068,7 +1095,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
| 1068 | goto out; | 1095 | goto out; |
| 1069 | } | 1096 | } |
| 1070 | 1097 | ||
| 1071 | err = replace_preds(NULL, call, ps, filter_string); | 1098 | err = replace_preds(NULL, call, ps, filter_string, false); |
| 1072 | if (err) | 1099 | if (err) |
| 1073 | append_filter_err(ps, call->filter); | 1100 | append_filter_err(ps, call->filter); |
| 1074 | 1101 | ||
| @@ -1092,7 +1119,7 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
| 1092 | mutex_lock(&event_mutex); | 1119 | mutex_lock(&event_mutex); |
| 1093 | 1120 | ||
| 1094 | if (!strcmp(strstrip(filter_string), "0")) { | 1121 | if (!strcmp(strstrip(filter_string), "0")) { |
| 1095 | filter_free_subsystem_preds(system); | 1122 | filter_free_subsystem_preds(system, FILTER_DISABLE_ALL); |
| 1096 | remove_filter_string(system->filter); | 1123 | remove_filter_string(system->filter); |
| 1097 | mutex_unlock(&event_mutex); | 1124 | mutex_unlock(&event_mutex); |
| 1098 | return 0; | 1125 | return 0; |
| @@ -1103,7 +1130,6 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
| 1103 | if (!ps) | 1130 | if (!ps) |
| 1104 | goto out_unlock; | 1131 | goto out_unlock; |
| 1105 | 1132 | ||
| 1106 | filter_free_subsystem_preds(system); | ||
| 1107 | replace_filter_string(system->filter, filter_string); | 1133 | replace_filter_string(system->filter, filter_string); |
| 1108 | 1134 | ||
| 1109 | parse_init(ps, filter_ops, filter_string); | 1135 | parse_init(ps, filter_ops, filter_string); |
| @@ -1113,9 +1139,23 @@ int apply_subsystem_event_filter(struct event_subsystem *system, | |||
| 1113 | goto out; | 1139 | goto out; |
| 1114 | } | 1140 | } |
| 1115 | 1141 | ||
| 1116 | err = replace_preds(system, NULL, ps, filter_string); | 1142 | filter_free_subsystem_preds(system, FILTER_INIT_NO_RESET); |
| 1117 | if (err) | 1143 | |
| 1144 | /* try to see the filter can be applied to which events */ | ||
| 1145 | err = replace_preds(system, NULL, ps, filter_string, true); | ||
| 1146 | if (err) { | ||
| 1147 | append_filter_err(ps, system->filter); | ||
| 1148 | goto out; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | filter_free_subsystem_preds(system, FILTER_SKIP_NO_RESET); | ||
| 1152 | |||
| 1153 | /* really apply the filter to the events */ | ||
| 1154 | err = replace_preds(system, NULL, ps, filter_string, false); | ||
| 1155 | if (err) { | ||
| 1118 | append_filter_err(ps, system->filter); | 1156 | append_filter_err(ps, system->filter); |
| 1157 | filter_free_subsystem_preds(system, 2); | ||
| 1158 | } | ||
| 1119 | 1159 | ||
| 1120 | out: | 1160 | out: |
| 1121 | filter_opstack_clear(ps); | 1161 | filter_opstack_clear(ps); |
