aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c93
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 @@
43unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX; 43unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX;
44unsigned long __read_mostly tracing_thresh; 44unsigned long __read_mostly tracing_thresh;
45 45
46/* For tracers that don't implement custom flags */
47static struct tracer_opt dummy_tracer_opt[] = {
48 { }
49};
50
51static struct tracer_flags dummy_tracer_flags = {
52 .val = 0,
53 .opts = dummy_tracer_opt
54};
55
56static 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
2436tracing_trace_options_read(struct file *filp, char __user *ubuf, 2459tracing_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 */
2517static 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
2472static ssize_t 2550static ssize_t
2473tracing_trace_options_write(struct file *filp, const char __user *ubuf, 2551tracing_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