diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace.h | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 124 | 
2 files changed, 84 insertions, 43 deletions
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); | 
