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(); |