diff options
Diffstat (limited to 'kernel/trace/trace_selftest.c')
| -rw-r--r-- | kernel/trace/trace_selftest.c | 304 |
1 files changed, 283 insertions, 21 deletions
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 288541f977fb..2c00a691a540 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
| @@ -103,54 +103,67 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret) | |||
| 103 | 103 | ||
| 104 | static int trace_selftest_test_probe1_cnt; | 104 | static int trace_selftest_test_probe1_cnt; |
| 105 | static void trace_selftest_test_probe1_func(unsigned long ip, | 105 | static void trace_selftest_test_probe1_func(unsigned long ip, |
| 106 | unsigned long pip) | 106 | unsigned long pip, |
| 107 | struct ftrace_ops *op, | ||
| 108 | struct pt_regs *pt_regs) | ||
| 107 | { | 109 | { |
| 108 | trace_selftest_test_probe1_cnt++; | 110 | trace_selftest_test_probe1_cnt++; |
| 109 | } | 111 | } |
| 110 | 112 | ||
| 111 | static int trace_selftest_test_probe2_cnt; | 113 | static int trace_selftest_test_probe2_cnt; |
| 112 | static void trace_selftest_test_probe2_func(unsigned long ip, | 114 | static void trace_selftest_test_probe2_func(unsigned long ip, |
| 113 | unsigned long pip) | 115 | unsigned long pip, |
| 116 | struct ftrace_ops *op, | ||
| 117 | struct pt_regs *pt_regs) | ||
| 114 | { | 118 | { |
| 115 | trace_selftest_test_probe2_cnt++; | 119 | trace_selftest_test_probe2_cnt++; |
| 116 | } | 120 | } |
| 117 | 121 | ||
| 118 | static int trace_selftest_test_probe3_cnt; | 122 | static int trace_selftest_test_probe3_cnt; |
| 119 | static void trace_selftest_test_probe3_func(unsigned long ip, | 123 | static void trace_selftest_test_probe3_func(unsigned long ip, |
| 120 | unsigned long pip) | 124 | unsigned long pip, |
| 125 | struct ftrace_ops *op, | ||
| 126 | struct pt_regs *pt_regs) | ||
| 121 | { | 127 | { |
| 122 | trace_selftest_test_probe3_cnt++; | 128 | trace_selftest_test_probe3_cnt++; |
| 123 | } | 129 | } |
| 124 | 130 | ||
| 125 | static int trace_selftest_test_global_cnt; | 131 | static int trace_selftest_test_global_cnt; |
| 126 | static void trace_selftest_test_global_func(unsigned long ip, | 132 | static void trace_selftest_test_global_func(unsigned long ip, |
| 127 | unsigned long pip) | 133 | unsigned long pip, |
| 134 | struct ftrace_ops *op, | ||
| 135 | struct pt_regs *pt_regs) | ||
| 128 | { | 136 | { |
| 129 | trace_selftest_test_global_cnt++; | 137 | trace_selftest_test_global_cnt++; |
| 130 | } | 138 | } |
| 131 | 139 | ||
| 132 | static int trace_selftest_test_dyn_cnt; | 140 | static int trace_selftest_test_dyn_cnt; |
| 133 | static void trace_selftest_test_dyn_func(unsigned long ip, | 141 | static void trace_selftest_test_dyn_func(unsigned long ip, |
| 134 | unsigned long pip) | 142 | unsigned long pip, |
| 143 | struct ftrace_ops *op, | ||
| 144 | struct pt_regs *pt_regs) | ||
| 135 | { | 145 | { |
| 136 | trace_selftest_test_dyn_cnt++; | 146 | trace_selftest_test_dyn_cnt++; |
| 137 | } | 147 | } |
| 138 | 148 | ||
| 139 | static struct ftrace_ops test_probe1 = { | 149 | static struct ftrace_ops test_probe1 = { |
| 140 | .func = trace_selftest_test_probe1_func, | 150 | .func = trace_selftest_test_probe1_func, |
| 151 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 141 | }; | 152 | }; |
| 142 | 153 | ||
| 143 | static struct ftrace_ops test_probe2 = { | 154 | static struct ftrace_ops test_probe2 = { |
| 144 | .func = trace_selftest_test_probe2_func, | 155 | .func = trace_selftest_test_probe2_func, |
| 156 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 145 | }; | 157 | }; |
| 146 | 158 | ||
| 147 | static struct ftrace_ops test_probe3 = { | 159 | static struct ftrace_ops test_probe3 = { |
| 148 | .func = trace_selftest_test_probe3_func, | 160 | .func = trace_selftest_test_probe3_func, |
| 161 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 149 | }; | 162 | }; |
| 150 | 163 | ||
| 151 | static struct ftrace_ops test_global = { | 164 | static struct ftrace_ops test_global = { |
| 152 | .func = trace_selftest_test_global_func, | 165 | .func = trace_selftest_test_global_func, |
| 153 | .flags = FTRACE_OPS_FL_GLOBAL, | 166 | .flags = FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_RECURSION_SAFE, |
| 154 | }; | 167 | }; |
| 155 | 168 | ||
| 156 | static void print_counts(void) | 169 | static void print_counts(void) |
| @@ -393,10 +406,253 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace, | |||
| 393 | 406 | ||
| 394 | return ret; | 407 | return ret; |
| 395 | } | 408 | } |
| 409 | |||
| 410 | static int trace_selftest_recursion_cnt; | ||
| 411 | static void trace_selftest_test_recursion_func(unsigned long ip, | ||
| 412 | unsigned long pip, | ||
| 413 | struct ftrace_ops *op, | ||
| 414 | struct pt_regs *pt_regs) | ||
| 415 | { | ||
| 416 | /* | ||
| 417 | * This function is registered without the recursion safe flag. | ||
| 418 | * The ftrace infrastructure should provide the recursion | ||
| 419 | * protection. If not, this will crash the kernel! | ||
| 420 | */ | ||
| 421 | trace_selftest_recursion_cnt++; | ||
| 422 | DYN_FTRACE_TEST_NAME(); | ||
| 423 | } | ||
| 424 | |||
| 425 | static void trace_selftest_test_recursion_safe_func(unsigned long ip, | ||
| 426 | unsigned long pip, | ||
| 427 | struct ftrace_ops *op, | ||
| 428 | struct pt_regs *pt_regs) | ||
| 429 | { | ||
| 430 | /* | ||
| 431 | * We said we would provide our own recursion. By calling | ||
| 432 | * this function again, we should recurse back into this function | ||
| 433 | * and count again. But this only happens if the arch supports | ||
| 434 | * all of ftrace features and nothing else is using the function | ||
| 435 | * tracing utility. | ||
| 436 | */ | ||
| 437 | if (trace_selftest_recursion_cnt++) | ||
| 438 | return; | ||
| 439 | DYN_FTRACE_TEST_NAME(); | ||
| 440 | } | ||
| 441 | |||
| 442 | static struct ftrace_ops test_rec_probe = { | ||
| 443 | .func = trace_selftest_test_recursion_func, | ||
| 444 | }; | ||
| 445 | |||
| 446 | static struct ftrace_ops test_recsafe_probe = { | ||
| 447 | .func = trace_selftest_test_recursion_safe_func, | ||
| 448 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 449 | }; | ||
| 450 | |||
| 451 | static int | ||
| 452 | trace_selftest_function_recursion(void) | ||
| 453 | { | ||
| 454 | int save_ftrace_enabled = ftrace_enabled; | ||
| 455 | int save_tracer_enabled = tracer_enabled; | ||
| 456 | char *func_name; | ||
| 457 | int len; | ||
| 458 | int ret; | ||
| 459 | int cnt; | ||
| 460 | |||
| 461 | /* The previous test PASSED */ | ||
| 462 | pr_cont("PASSED\n"); | ||
| 463 | pr_info("Testing ftrace recursion: "); | ||
| 464 | |||
| 465 | |||
| 466 | /* enable tracing, and record the filter function */ | ||
| 467 | ftrace_enabled = 1; | ||
| 468 | tracer_enabled = 1; | ||
| 469 | |||
| 470 | /* Handle PPC64 '.' name */ | ||
| 471 | func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); | ||
| 472 | len = strlen(func_name); | ||
| 473 | |||
| 474 | ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1); | ||
| 475 | if (ret) { | ||
| 476 | pr_cont("*Could not set filter* "); | ||
| 477 | goto out; | ||
| 478 | } | ||
| 479 | |||
| 480 | ret = register_ftrace_function(&test_rec_probe); | ||
| 481 | if (ret) { | ||
| 482 | pr_cont("*could not register callback* "); | ||
| 483 | goto out; | ||
| 484 | } | ||
| 485 | |||
| 486 | DYN_FTRACE_TEST_NAME(); | ||
| 487 | |||
| 488 | unregister_ftrace_function(&test_rec_probe); | ||
| 489 | |||
| 490 | ret = -1; | ||
| 491 | if (trace_selftest_recursion_cnt != 1) { | ||
| 492 | pr_cont("*callback not called once (%d)* ", | ||
| 493 | trace_selftest_recursion_cnt); | ||
| 494 | goto out; | ||
| 495 | } | ||
| 496 | |||
| 497 | trace_selftest_recursion_cnt = 1; | ||
| 498 | |||
| 499 | pr_cont("PASSED\n"); | ||
| 500 | pr_info("Testing ftrace recursion safe: "); | ||
| 501 | |||
| 502 | ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1); | ||
| 503 | if (ret) { | ||
| 504 | pr_cont("*Could not set filter* "); | ||
| 505 | goto out; | ||
| 506 | } | ||
| 507 | |||
| 508 | ret = register_ftrace_function(&test_recsafe_probe); | ||
| 509 | if (ret) { | ||
| 510 | pr_cont("*could not register callback* "); | ||
| 511 | goto out; | ||
| 512 | } | ||
| 513 | |||
| 514 | DYN_FTRACE_TEST_NAME(); | ||
| 515 | |||
| 516 | unregister_ftrace_function(&test_recsafe_probe); | ||
| 517 | |||
| 518 | /* | ||
| 519 | * If arch supports all ftrace features, and no other task | ||
| 520 | * was on the list, we should be fine. | ||
| 521 | */ | ||
| 522 | if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC) | ||
| 523 | cnt = 2; /* Should have recursed */ | ||
| 524 | else | ||
| 525 | cnt = 1; | ||
| 526 | |||
| 527 | ret = -1; | ||
| 528 | if (trace_selftest_recursion_cnt != cnt) { | ||
| 529 | pr_cont("*callback not called expected %d times (%d)* ", | ||
| 530 | cnt, trace_selftest_recursion_cnt); | ||
| 531 | goto out; | ||
| 532 | } | ||
| 533 | |||
| 534 | ret = 0; | ||
| 535 | out: | ||
| 536 | ftrace_enabled = save_ftrace_enabled; | ||
| 537 | tracer_enabled = save_tracer_enabled; | ||
| 538 | |||
| 539 | return ret; | ||
| 540 | } | ||
| 396 | #else | 541 | #else |
| 397 | # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) | 542 | # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; }) |
| 543 | # define trace_selftest_function_recursion() ({ 0; }) | ||
| 398 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 544 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 399 | 545 | ||
| 546 | static enum { | ||
| 547 | TRACE_SELFTEST_REGS_START, | ||
| 548 | TRACE_SELFTEST_REGS_FOUND, | ||
| 549 | TRACE_SELFTEST_REGS_NOT_FOUND, | ||
| 550 | } trace_selftest_regs_stat; | ||
| 551 | |||
| 552 | static void trace_selftest_test_regs_func(unsigned long ip, | ||
| 553 | unsigned long pip, | ||
| 554 | struct ftrace_ops *op, | ||
| 555 | struct pt_regs *pt_regs) | ||
| 556 | { | ||
| 557 | if (pt_regs) | ||
| 558 | trace_selftest_regs_stat = TRACE_SELFTEST_REGS_FOUND; | ||
| 559 | else | ||
| 560 | trace_selftest_regs_stat = TRACE_SELFTEST_REGS_NOT_FOUND; | ||
| 561 | } | ||
| 562 | |||
| 563 | static struct ftrace_ops test_regs_probe = { | ||
| 564 | .func = trace_selftest_test_regs_func, | ||
| 565 | .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_SAVE_REGS, | ||
| 566 | }; | ||
| 567 | |||
| 568 | static int | ||
| 569 | trace_selftest_function_regs(void) | ||
| 570 | { | ||
| 571 | int save_ftrace_enabled = ftrace_enabled; | ||
| 572 | int save_tracer_enabled = tracer_enabled; | ||
| 573 | char *func_name; | ||
| 574 | int len; | ||
| 575 | int ret; | ||
| 576 | int supported = 0; | ||
| 577 | |||
| 578 | #ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS | ||
| 579 | supported = 1; | ||
| 580 | #endif | ||
| 581 | |||
| 582 | /* The previous test PASSED */ | ||
| 583 | pr_cont("PASSED\n"); | ||
| 584 | pr_info("Testing ftrace regs%s: ", | ||
| 585 | !supported ? "(no arch support)" : ""); | ||
| 586 | |||
| 587 | /* enable tracing, and record the filter function */ | ||
| 588 | ftrace_enabled = 1; | ||
| 589 | tracer_enabled = 1; | ||
| 590 | |||
| 591 | /* Handle PPC64 '.' name */ | ||
| 592 | func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); | ||
| 593 | len = strlen(func_name); | ||
| 594 | |||
| 595 | ret = ftrace_set_filter(&test_regs_probe, func_name, len, 1); | ||
| 596 | /* | ||
| 597 | * If DYNAMIC_FTRACE is not set, then we just trace all functions. | ||
| 598 | * This test really doesn't care. | ||
| 599 | */ | ||
| 600 | if (ret && ret != -ENODEV) { | ||
| 601 | pr_cont("*Could not set filter* "); | ||
| 602 | goto out; | ||
| 603 | } | ||
| 604 | |||
| 605 | ret = register_ftrace_function(&test_regs_probe); | ||
| 606 | /* | ||
| 607 | * Now if the arch does not support passing regs, then this should | ||
| 608 | * have failed. | ||
| 609 | */ | ||
| 610 | if (!supported) { | ||
| 611 | if (!ret) { | ||
| 612 | pr_cont("*registered save-regs without arch support* "); | ||
| 613 | goto out; | ||
| 614 | } | ||
| 615 | test_regs_probe.flags |= FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED; | ||
| 616 | ret = register_ftrace_function(&test_regs_probe); | ||
| 617 | } | ||
| 618 | if (ret) { | ||
| 619 | pr_cont("*could not register callback* "); | ||
| 620 | goto out; | ||
| 621 | } | ||
| 622 | |||
| 623 | |||
| 624 | DYN_FTRACE_TEST_NAME(); | ||
| 625 | |||
| 626 | unregister_ftrace_function(&test_regs_probe); | ||
| 627 | |||
| 628 | ret = -1; | ||
| 629 | |||
| 630 | switch (trace_selftest_regs_stat) { | ||
| 631 | case TRACE_SELFTEST_REGS_START: | ||
| 632 | pr_cont("*callback never called* "); | ||
| 633 | goto out; | ||
| 634 | |||
| 635 | case TRACE_SELFTEST_REGS_FOUND: | ||
| 636 | if (supported) | ||
| 637 | break; | ||
| 638 | pr_cont("*callback received regs without arch support* "); | ||
| 639 | goto out; | ||
| 640 | |||
| 641 | case TRACE_SELFTEST_REGS_NOT_FOUND: | ||
| 642 | if (!supported) | ||
| 643 | break; | ||
| 644 | pr_cont("*callback received NULL regs* "); | ||
| 645 | goto out; | ||
| 646 | } | ||
| 647 | |||
| 648 | ret = 0; | ||
| 649 | out: | ||
| 650 | ftrace_enabled = save_ftrace_enabled; | ||
| 651 | tracer_enabled = save_tracer_enabled; | ||
| 652 | |||
| 653 | return ret; | ||
| 654 | } | ||
| 655 | |||
| 400 | /* | 656 | /* |
| 401 | * Simple verification test of ftrace function tracer. | 657 | * Simple verification test of ftrace function tracer. |
| 402 | * Enable ftrace, sleep 1/10 second, and then read the trace | 658 | * Enable ftrace, sleep 1/10 second, and then read the trace |
| @@ -442,7 +698,14 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) | |||
| 442 | 698 | ||
| 443 | ret = trace_selftest_startup_dynamic_tracing(trace, tr, | 699 | ret = trace_selftest_startup_dynamic_tracing(trace, tr, |
| 444 | DYN_FTRACE_TEST_NAME); | 700 | DYN_FTRACE_TEST_NAME); |
| 701 | if (ret) | ||
| 702 | goto out; | ||
| 445 | 703 | ||
| 704 | ret = trace_selftest_function_recursion(); | ||
| 705 | if (ret) | ||
| 706 | goto out; | ||
| 707 | |||
| 708 | ret = trace_selftest_function_regs(); | ||
| 446 | out: | 709 | out: |
| 447 | ftrace_enabled = save_ftrace_enabled; | 710 | ftrace_enabled = save_ftrace_enabled; |
| 448 | tracer_enabled = save_tracer_enabled; | 711 | tracer_enabled = save_tracer_enabled; |
| @@ -778,6 +1041,8 @@ static int trace_wakeup_test_thread(void *data) | |||
| 778 | set_current_state(TASK_INTERRUPTIBLE); | 1041 | set_current_state(TASK_INTERRUPTIBLE); |
| 779 | schedule(); | 1042 | schedule(); |
| 780 | 1043 | ||
| 1044 | complete(x); | ||
| 1045 | |||
| 781 | /* we are awake, now wait to disappear */ | 1046 | /* we are awake, now wait to disappear */ |
| 782 | while (!kthread_should_stop()) { | 1047 | while (!kthread_should_stop()) { |
| 783 | /* | 1048 | /* |
| @@ -821,24 +1086,21 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr) | |||
| 821 | /* reset the max latency */ | 1086 | /* reset the max latency */ |
| 822 | tracing_max_latency = 0; | 1087 | tracing_max_latency = 0; |
| 823 | 1088 | ||
| 824 | /* sleep to let the RT thread sleep too */ | 1089 | while (p->on_rq) { |
| 825 | msleep(100); | 1090 | /* |
| 1091 | * Sleep to make sure the RT thread is asleep too. | ||
| 1092 | * On virtual machines we can't rely on timings, | ||
| 1093 | * but we want to make sure this test still works. | ||
| 1094 | */ | ||
| 1095 | msleep(100); | ||
| 1096 | } | ||
| 826 | 1097 | ||
| 827 | /* | 1098 | init_completion(&isrt); |
| 828 | * Yes this is slightly racy. It is possible that for some | ||
| 829 | * strange reason that the RT thread we created, did not | ||
| 830 | * call schedule for 100ms after doing the completion, | ||
| 831 | * and we do a wakeup on a task that already is awake. | ||
| 832 | * But that is extremely unlikely, and the worst thing that | ||
| 833 | * happens in such a case, is that we disable tracing. | ||
| 834 | * Honestly, if this race does happen something is horrible | ||
| 835 | * wrong with the system. | ||
| 836 | */ | ||
| 837 | 1099 | ||
| 838 | wake_up_process(p); | 1100 | wake_up_process(p); |
| 839 | 1101 | ||
| 840 | /* give a little time to let the thread wake up */ | 1102 | /* Wait for the task to wake up */ |
| 841 | msleep(100); | 1103 | wait_for_completion(&isrt); |
| 842 | 1104 | ||
| 843 | /* stop the tracing. */ | 1105 | /* stop the tracing. */ |
| 844 | tracing_stop(); | 1106 | tracing_stop(); |
