diff options
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5653c6b07ba1..4ee6f0375222 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -43,6 +43,20 @@ | |||
43 | unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX; | 43 | unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX; |
44 | unsigned long __read_mostly tracing_thresh; | 44 | unsigned long __read_mostly tracing_thresh; |
45 | 45 | ||
46 | /* For tracers that don't implement custom flags */ | ||
47 | static struct tracer_opt dummy_tracer_opt[] = { | ||
48 | { } | ||
49 | }; | ||
50 | |||
51 | static struct tracer_flags dummy_tracer_flags = { | ||
52 | .val = 0, | ||
53 | .opts = dummy_tracer_opt | ||
54 | }; | ||
55 | |||
56 | static int dummy_set_flag(u32 old_flags, u32 bit, int set) | ||
57 | { | ||
58 | return 0; | ||
59 | } | ||
46 | 60 | ||
47 | /* | 61 | /* |
48 | * Kill all tracing for good (never come back). | 62 | * Kill all tracing for good (never come back). |
@@ -537,6 +551,14 @@ int register_tracer(struct tracer *type) | |||
537 | } | 551 | } |
538 | } | 552 | } |
539 | 553 | ||
554 | if (!type->set_flag) | ||
555 | type->set_flag = &dummy_set_flag; | ||
556 | if (!type->flags) | ||
557 | type->flags = &dummy_tracer_flags; | ||
558 | else | ||
559 | if (!type->flags->opts) | ||
560 | type->flags->opts = dummy_tracer_opt; | ||
561 | |||
540 | #ifdef CONFIG_FTRACE_STARTUP_TEST | 562 | #ifdef CONFIG_FTRACE_STARTUP_TEST |
541 | if (type->selftest) { | 563 | if (type->selftest) { |
542 | struct tracer *saved_tracer = current_trace; | 564 | struct tracer *saved_tracer = current_trace; |
@@ -840,6 +862,7 @@ static void __trace_function_return(struct trace_array *tr, | |||
840 | entry->parent_ip = trace->ret; | 862 | entry->parent_ip = trace->ret; |
841 | entry->rettime = trace->rettime; | 863 | entry->rettime = trace->rettime; |
842 | entry->calltime = trace->calltime; | 864 | entry->calltime = trace->calltime; |
865 | entry->overrun = trace->overrun; | ||
843 | ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags); | 866 | ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags); |
844 | } | 867 | } |
845 | #endif | 868 | #endif |
@@ -2436,10 +2459,13 @@ static ssize_t | |||
2436 | tracing_trace_options_read(struct file *filp, char __user *ubuf, | 2459 | tracing_trace_options_read(struct file *filp, char __user *ubuf, |
2437 | size_t cnt, loff_t *ppos) | 2460 | size_t cnt, loff_t *ppos) |
2438 | { | 2461 | { |
2462 | int i; | ||
2439 | char *buf; | 2463 | char *buf; |
2440 | int r = 0; | 2464 | int r = 0; |
2441 | int len = 0; | 2465 | int len = 0; |
2442 | int i; | 2466 | u32 tracer_flags = current_trace->flags->val; |
2467 | struct tracer_opt *trace_opts = current_trace->flags->opts; | ||
2468 | |||
2443 | 2469 | ||
2444 | /* calulate max size */ | 2470 | /* calulate max size */ |
2445 | for (i = 0; trace_options[i]; i++) { | 2471 | for (i = 0; trace_options[i]; i++) { |
@@ -2447,6 +2473,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, | |||
2447 | len += 3; /* "no" and space */ | 2473 | len += 3; /* "no" and space */ |
2448 | } | 2474 | } |
2449 | 2475 | ||
2476 | /* | ||
2477 | * Increase the size with names of options specific | ||
2478 | * of the current tracer. | ||
2479 | */ | ||
2480 | for (i = 0; trace_opts[i].name; i++) { | ||
2481 | len += strlen(trace_opts[i].name); | ||
2482 | len += 3; /* "no" and space */ | ||
2483 | } | ||
2484 | |||
2450 | /* +2 for \n and \0 */ | 2485 | /* +2 for \n and \0 */ |
2451 | buf = kmalloc(len + 2, GFP_KERNEL); | 2486 | buf = kmalloc(len + 2, GFP_KERNEL); |
2452 | if (!buf) | 2487 | if (!buf) |
@@ -2459,6 +2494,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, | |||
2459 | r += sprintf(buf + r, "no%s ", trace_options[i]); | 2494 | r += sprintf(buf + r, "no%s ", trace_options[i]); |
2460 | } | 2495 | } |
2461 | 2496 | ||
2497 | for (i = 0; trace_opts[i].name; i++) { | ||
2498 | if (tracer_flags & trace_opts[i].bit) | ||
2499 | r += sprintf(buf + r, "%s ", | ||
2500 | trace_opts[i].name); | ||
2501 | else | ||
2502 | r += sprintf(buf + r, "no%s ", | ||
2503 | trace_opts[i].name); | ||
2504 | } | ||
2505 | |||
2462 | r += sprintf(buf + r, "\n"); | 2506 | r += sprintf(buf + r, "\n"); |
2463 | WARN_ON(r >= len + 2); | 2507 | WARN_ON(r >= len + 2); |
2464 | 2508 | ||
@@ -2469,6 +2513,40 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf, | |||
2469 | return r; | 2513 | return r; |
2470 | } | 2514 | } |
2471 | 2515 | ||
2516 | /* Try to assign a tracer specific option */ | ||
2517 | static int set_tracer_option(struct tracer *trace, char *cmp, int neg) | ||
2518 | { | ||
2519 | struct tracer_flags *trace_flags = trace->flags; | ||
2520 | struct tracer_opt *opts = NULL; | ||
2521 | int ret = 0, i = 0; | ||
2522 | int len; | ||
2523 | |||
2524 | for (i = 0; trace_flags->opts[i].name; i++) { | ||
2525 | opts = &trace_flags->opts[i]; | ||
2526 | len = strlen(opts->name); | ||
2527 | |||
2528 | if (strncmp(cmp, opts->name, len) == 0) { | ||
2529 | ret = trace->set_flag(trace_flags->val, | ||
2530 | opts->bit, !neg); | ||
2531 | break; | ||
2532 | } | ||
2533 | } | ||
2534 | /* Not found */ | ||
2535 | if (!trace_flags->opts[i].name) | ||
2536 | return -EINVAL; | ||
2537 | |||
2538 | /* Refused to handle */ | ||
2539 | if (ret) | ||
2540 | return ret; | ||
2541 | |||
2542 | if (neg) | ||
2543 | trace_flags->val &= ~opts->bit; | ||
2544 | else | ||
2545 | trace_flags->val |= opts->bit; | ||
2546 | |||
2547 | return 0; | ||
2548 | } | ||
2549 | |||
2472 | static ssize_t | 2550 | static ssize_t |
2473 | tracing_trace_options_write(struct file *filp, const char __user *ubuf, | 2551 | tracing_trace_options_write(struct file *filp, const char __user *ubuf, |
2474 | size_t cnt, loff_t *ppos) | 2552 | size_t cnt, loff_t *ppos) |
@@ -2476,6 +2554,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
2476 | char buf[64]; | 2554 | char buf[64]; |
2477 | char *cmp = buf; | 2555 | char *cmp = buf; |
2478 | int neg = 0; | 2556 | int neg = 0; |
2557 | int ret; | ||
2479 | int i; | 2558 | int i; |
2480 | 2559 | ||
2481 | if (cnt >= sizeof(buf)) | 2560 | if (cnt >= sizeof(buf)) |
@@ -2502,11 +2581,13 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
2502 | break; | 2581 | break; |
2503 | } | 2582 | } |
2504 | } | 2583 | } |
2505 | /* | 2584 | |
2506 | * If no option could be set, return an error: | 2585 | /* If no option could be set, test the specific tracer options */ |
2507 | */ | 2586 | if (!trace_options[i]) { |
2508 | if (!trace_options[i]) | 2587 | ret = set_tracer_option(current_trace, cmp, neg); |
2509 | return -EINVAL; | 2588 | if (ret) |
2589 | return ret; | ||
2590 | } | ||
2510 | 2591 | ||
2511 | filp->f_pos += cnt; | 2592 | filp->f_pos += cnt; |
2512 | 2593 | ||