diff options
-rw-r--r-- | kernel/trace/trace.h | 3 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 143 |
2 files changed, 110 insertions, 36 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 1597bc0749c1..441fc1bc85d6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -661,7 +661,8 @@ struct ftrace_event_field { | |||
661 | }; | 661 | }; |
662 | 662 | ||
663 | struct event_filter { | 663 | struct event_filter { |
664 | int n_preds; | 664 | int n_preds; /* Number assigned */ |
665 | int a_preds; /* allocated */ | ||
665 | struct filter_pred **preds; | 666 | struct filter_pred **preds; |
666 | char *filter_string; | 667 | char *filter_string; |
667 | }; | 668 | }; |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 5d719b340a2b..aac6a6183e6a 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -362,6 +362,7 @@ int filter_match_preds(struct event_filter *filter, void *rec) | |||
362 | { | 362 | { |
363 | int match = -1, top = 0, val1 = 0, val2 = 0; | 363 | int match = -1, top = 0, val1 = 0, val2 = 0; |
364 | int stack[MAX_FILTER_PRED]; | 364 | int stack[MAX_FILTER_PRED]; |
365 | struct filter_pred **preds; | ||
365 | struct filter_pred *pred; | 366 | struct filter_pred *pred; |
366 | int n_preds = ACCESS_ONCE(filter->n_preds); | 367 | int n_preds = ACCESS_ONCE(filter->n_preds); |
367 | int i; | 368 | int i; |
@@ -370,8 +371,13 @@ int filter_match_preds(struct event_filter *filter, void *rec) | |||
370 | if (!n_preds) | 371 | if (!n_preds) |
371 | return 1; | 372 | return 1; |
372 | 373 | ||
374 | /* | ||
375 | * n_preds and filter->preds is protect with preemption disabled. | ||
376 | */ | ||
377 | preds = rcu_dereference_sched(filter->preds); | ||
378 | |||
373 | for (i = 0; i < n_preds; i++) { | 379 | for (i = 0; i < n_preds; i++) { |
374 | pred = filter->preds[i]; | 380 | pred = preds[i]; |
375 | if (!pred->pop_n) { | 381 | if (!pred->pop_n) { |
376 | match = pred->fn(pred, rec); | 382 | match = pred->fn(pred, rec); |
377 | stack[top++] = match; | 383 | stack[top++] = match; |
@@ -548,46 +554,55 @@ static int filter_set_pred(struct filter_pred *dest, | |||
548 | return 0; | 554 | return 0; |
549 | } | 555 | } |
550 | 556 | ||
557 | static void __free_preds(struct event_filter *filter) | ||
558 | { | ||
559 | int i; | ||
560 | |||
561 | if (filter->preds) { | ||
562 | for (i = 0; i < filter->a_preds; i++) { | ||
563 | if (filter->preds[i]) | ||
564 | filter_free_pred(filter->preds[i]); | ||
565 | } | ||
566 | kfree(filter->preds); | ||
567 | filter->preds = NULL; | ||
568 | } | ||
569 | filter->a_preds = 0; | ||
570 | filter->n_preds = 0; | ||
571 | } | ||
572 | |||
551 | static void filter_disable_preds(struct ftrace_event_call *call) | 573 | static void filter_disable_preds(struct ftrace_event_call *call) |
552 | { | 574 | { |
553 | struct event_filter *filter = call->filter; | 575 | struct event_filter *filter = call->filter; |
554 | int i; | 576 | int i; |
555 | 577 | ||
556 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | 578 | call->flags &= ~TRACE_EVENT_FL_FILTERED; |
579 | if (filter->preds) { | ||
580 | for (i = 0; i < filter->n_preds; i++) | ||
581 | filter->preds[i]->fn = filter_pred_none; | ||
582 | } | ||
557 | filter->n_preds = 0; | 583 | filter->n_preds = 0; |
558 | |||
559 | for (i = 0; i < MAX_FILTER_PRED; i++) | ||
560 | filter->preds[i]->fn = filter_pred_none; | ||
561 | } | 584 | } |
562 | 585 | ||
563 | static void __free_preds(struct event_filter *filter) | 586 | static void __free_filter(struct event_filter *filter) |
564 | { | 587 | { |
565 | int i; | ||
566 | |||
567 | if (!filter) | 588 | if (!filter) |
568 | return; | 589 | return; |
569 | 590 | ||
570 | for (i = 0; i < MAX_FILTER_PRED; i++) { | 591 | __free_preds(filter); |
571 | if (filter->preds[i]) | ||
572 | filter_free_pred(filter->preds[i]); | ||
573 | } | ||
574 | kfree(filter->preds); | ||
575 | kfree(filter->filter_string); | 592 | kfree(filter->filter_string); |
576 | kfree(filter); | 593 | kfree(filter); |
577 | } | 594 | } |
578 | 595 | ||
579 | void destroy_preds(struct ftrace_event_call *call) | 596 | void destroy_preds(struct ftrace_event_call *call) |
580 | { | 597 | { |
581 | __free_preds(call->filter); | 598 | __free_filter(call->filter); |
582 | call->filter = NULL; | 599 | call->filter = NULL; |
583 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | 600 | call->flags &= ~TRACE_EVENT_FL_FILTERED; |
584 | } | 601 | } |
585 | 602 | ||
586 | static struct event_filter *__alloc_preds(void) | 603 | static struct event_filter *__alloc_filter(void) |
587 | { | 604 | { |
588 | struct event_filter *filter; | 605 | struct event_filter *filter; |
589 | struct filter_pred *pred; | ||
590 | int i; | ||
591 | 606 | ||
592 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); | 607 | filter = kzalloc(sizeof(*filter), GFP_KERNEL); |
593 | if (!filter) | 608 | if (!filter) |
@@ -595,32 +610,63 @@ static struct event_filter *__alloc_preds(void) | |||
595 | 610 | ||
596 | filter->n_preds = 0; | 611 | filter->n_preds = 0; |
597 | 612 | ||
598 | filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); | 613 | return filter; |
614 | } | ||
615 | |||
616 | static int __alloc_preds(struct event_filter *filter, int n_preds) | ||
617 | { | ||
618 | struct filter_pred *pred; | ||
619 | int i; | ||
620 | |||
621 | if (filter->preds) { | ||
622 | if (filter->a_preds < n_preds) { | ||
623 | /* We need to reallocate */ | ||
624 | filter->n_preds = 0; | ||
625 | /* | ||
626 | * It is possible that the filter is currently | ||
627 | * being used. We need to zero out the number | ||
628 | * of preds, wait on preemption and then free | ||
629 | * the preds. | ||
630 | */ | ||
631 | synchronize_sched(); | ||
632 | __free_preds(filter); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | if (!filter->preds) { | ||
637 | filter->preds = | ||
638 | kzalloc(sizeof(*filter->preds) * n_preds, GFP_KERNEL); | ||
639 | filter->a_preds = n_preds; | ||
640 | } | ||
599 | if (!filter->preds) | 641 | if (!filter->preds) |
600 | goto oom; | 642 | return -ENOMEM; |
643 | |||
644 | if (WARN_ON(filter->a_preds < n_preds)) | ||
645 | return -EINVAL; | ||
601 | 646 | ||
602 | for (i = 0; i < MAX_FILTER_PRED; i++) { | 647 | for (i = 0; i < n_preds; i++) { |
603 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | 648 | pred = filter->preds[i]; |
649 | if (!pred) | ||
650 | pred = kzalloc(sizeof(*pred), GFP_KERNEL); | ||
604 | if (!pred) | 651 | if (!pred) |
605 | goto oom; | 652 | goto oom; |
606 | pred->fn = filter_pred_none; | 653 | pred->fn = filter_pred_none; |
607 | filter->preds[i] = pred; | 654 | filter->preds[i] = pred; |
608 | } | 655 | } |
609 | 656 | ||
610 | return filter; | 657 | return 0; |
611 | 658 | oom: | |
612 | oom: | ||
613 | __free_preds(filter); | 659 | __free_preds(filter); |
614 | return ERR_PTR(-ENOMEM); | 660 | return -ENOMEM; |
615 | } | 661 | } |
616 | 662 | ||
617 | static int init_preds(struct ftrace_event_call *call) | 663 | static int init_filter(struct ftrace_event_call *call) |
618 | { | 664 | { |
619 | if (call->filter) | 665 | if (call->filter) |
620 | return 0; | 666 | return 0; |
621 | 667 | ||
622 | call->flags &= ~TRACE_EVENT_FL_FILTERED; | 668 | call->flags &= ~TRACE_EVENT_FL_FILTERED; |
623 | call->filter = __alloc_preds(); | 669 | call->filter = __alloc_filter(); |
624 | if (IS_ERR(call->filter)) | 670 | if (IS_ERR(call->filter)) |
625 | return PTR_ERR(call->filter); | 671 | return PTR_ERR(call->filter); |
626 | 672 | ||
@@ -636,7 +682,7 @@ static int init_subsystem_preds(struct event_subsystem *system) | |||
636 | if (strcmp(call->class->system, system->name) != 0) | 682 | if (strcmp(call->class->system, system->name) != 0) |
637 | continue; | 683 | continue; |
638 | 684 | ||
639 | err = init_preds(call); | 685 | err = init_filter(call); |
640 | if (err) | 686 | if (err) |
641 | return err; | 687 | return err; |
642 | } | 688 | } |
@@ -665,7 +711,7 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, | |||
665 | { | 711 | { |
666 | int idx, err; | 712 | int idx, err; |
667 | 713 | ||
668 | if (filter->n_preds == MAX_FILTER_PRED) { | 714 | if (WARN_ON(filter->n_preds == filter->a_preds)) { |
669 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); | 715 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); |
670 | return -ENOSPC; | 716 | return -ENOSPC; |
671 | } | 717 | } |
@@ -1179,6 +1225,20 @@ static int check_preds(struct filter_parse_state *ps) | |||
1179 | return 0; | 1225 | return 0; |
1180 | } | 1226 | } |
1181 | 1227 | ||
1228 | static int count_preds(struct filter_parse_state *ps) | ||
1229 | { | ||
1230 | struct postfix_elt *elt; | ||
1231 | int n_preds = 0; | ||
1232 | |||
1233 | list_for_each_entry(elt, &ps->postfix, list) { | ||
1234 | if (elt->op == OP_NONE) | ||
1235 | continue; | ||
1236 | n_preds++; | ||
1237 | } | ||
1238 | |||
1239 | return n_preds; | ||
1240 | } | ||
1241 | |||
1182 | static int replace_preds(struct ftrace_event_call *call, | 1242 | static int replace_preds(struct ftrace_event_call *call, |
1183 | struct event_filter *filter, | 1243 | struct event_filter *filter, |
1184 | struct filter_parse_state *ps, | 1244 | struct filter_parse_state *ps, |
@@ -1191,10 +1251,23 @@ static int replace_preds(struct ftrace_event_call *call, | |||
1191 | int err; | 1251 | int err; |
1192 | int n_preds = 0; | 1252 | int n_preds = 0; |
1193 | 1253 | ||
1254 | n_preds = count_preds(ps); | ||
1255 | if (n_preds >= MAX_FILTER_PRED) { | ||
1256 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); | ||
1257 | return -ENOSPC; | ||
1258 | } | ||
1259 | |||
1194 | err = check_preds(ps); | 1260 | err = check_preds(ps); |
1195 | if (err) | 1261 | if (err) |
1196 | return err; | 1262 | return err; |
1197 | 1263 | ||
1264 | if (!dry_run) { | ||
1265 | err = __alloc_preds(filter, n_preds); | ||
1266 | if (err) | ||
1267 | return err; | ||
1268 | } | ||
1269 | |||
1270 | n_preds = 0; | ||
1198 | list_for_each_entry(elt, &ps->postfix, list) { | 1271 | list_for_each_entry(elt, &ps->postfix, list) { |
1199 | if (elt->op == OP_NONE) { | 1272 | if (elt->op == OP_NONE) { |
1200 | if (!operand1) | 1273 | if (!operand1) |
@@ -1208,7 +1281,7 @@ static int replace_preds(struct ftrace_event_call *call, | |||
1208 | continue; | 1281 | continue; |
1209 | } | 1282 | } |
1210 | 1283 | ||
1211 | if (n_preds++ == MAX_FILTER_PRED) { | 1284 | if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) { |
1212 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); | 1285 | parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); |
1213 | return -ENOSPC; | 1286 | return -ENOSPC; |
1214 | } | 1287 | } |
@@ -1283,7 +1356,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) | |||
1283 | 1356 | ||
1284 | mutex_lock(&event_mutex); | 1357 | mutex_lock(&event_mutex); |
1285 | 1358 | ||
1286 | err = init_preds(call); | 1359 | err = init_filter(call); |
1287 | if (err) | 1360 | if (err) |
1288 | goto out_unlock; | 1361 | goto out_unlock; |
1289 | 1362 | ||
@@ -1376,7 +1449,7 @@ void ftrace_profile_free_filter(struct perf_event *event) | |||
1376 | struct event_filter *filter = event->filter; | 1449 | struct event_filter *filter = event->filter; |
1377 | 1450 | ||
1378 | event->filter = NULL; | 1451 | event->filter = NULL; |
1379 | __free_preds(filter); | 1452 | __free_filter(filter); |
1380 | } | 1453 | } |
1381 | 1454 | ||
1382 | int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 1455 | int ftrace_profile_set_filter(struct perf_event *event, int event_id, |
@@ -1402,7 +1475,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, | |||
1402 | if (event->filter) | 1475 | if (event->filter) |
1403 | goto out_unlock; | 1476 | goto out_unlock; |
1404 | 1477 | ||
1405 | filter = __alloc_preds(); | 1478 | filter = __alloc_filter(); |
1406 | if (IS_ERR(filter)) { | 1479 | if (IS_ERR(filter)) { |
1407 | err = PTR_ERR(filter); | 1480 | err = PTR_ERR(filter); |
1408 | goto out_unlock; | 1481 | goto out_unlock; |
@@ -1411,7 +1484,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, | |||
1411 | err = -ENOMEM; | 1484 | err = -ENOMEM; |
1412 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); | 1485 | ps = kzalloc(sizeof(*ps), GFP_KERNEL); |
1413 | if (!ps) | 1486 | if (!ps) |
1414 | goto free_preds; | 1487 | goto free_filter; |
1415 | 1488 | ||
1416 | parse_init(ps, filter_ops, filter_str); | 1489 | parse_init(ps, filter_ops, filter_str); |
1417 | err = filter_parse(ps); | 1490 | err = filter_parse(ps); |
@@ -1427,9 +1500,9 @@ free_ps: | |||
1427 | postfix_clear(ps); | 1500 | postfix_clear(ps); |
1428 | kfree(ps); | 1501 | kfree(ps); |
1429 | 1502 | ||
1430 | free_preds: | 1503 | free_filter: |
1431 | if (err) | 1504 | if (err) |
1432 | __free_preds(filter); | 1505 | __free_filter(filter); |
1433 | 1506 | ||
1434 | out_unlock: | 1507 | out_unlock: |
1435 | mutex_unlock(&event_mutex); | 1508 | mutex_unlock(&event_mutex); |