aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.c92
-rw-r--r--kernel/trace/trace.h26
2 files changed, 112 insertions, 6 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 2596b5a968c4..9531fddcfb8d 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).
@@ -529,6 +543,14 @@ int register_tracer(struct tracer *type)
529 } 543 }
530 } 544 }
531 545
546 if (!type->set_flag)
547 type->set_flag = &dummy_set_flag;
548 if (!type->flags)
549 type->flags = &dummy_tracer_flags;
550 else
551 if (!type->flags->opts)
552 type->flags->opts = dummy_tracer_opt;
553
532#ifdef CONFIG_FTRACE_STARTUP_TEST 554#ifdef CONFIG_FTRACE_STARTUP_TEST
533 if (type->selftest) { 555 if (type->selftest) {
534 struct tracer *saved_tracer = current_trace; 556 struct tracer *saved_tracer = current_trace;
@@ -2426,10 +2448,13 @@ static ssize_t
2426tracing_trace_options_read(struct file *filp, char __user *ubuf, 2448tracing_trace_options_read(struct file *filp, char __user *ubuf,
2427 size_t cnt, loff_t *ppos) 2449 size_t cnt, loff_t *ppos)
2428{ 2450{
2451 int i;
2429 char *buf; 2452 char *buf;
2430 int r = 0; 2453 int r = 0;
2431 int len = 0; 2454 int len = 0;
2432 int i; 2455 u32 tracer_flags = current_trace->flags->val;
2456 struct tracer_opt *trace_opts = current_trace->flags->opts;
2457
2433 2458
2434 /* calulate max size */ 2459 /* calulate max size */
2435 for (i = 0; trace_options[i]; i++) { 2460 for (i = 0; trace_options[i]; i++) {
@@ -2437,6 +2462,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
2437 len += 3; /* "no" and space */ 2462 len += 3; /* "no" and space */
2438 } 2463 }
2439 2464
2465 /*
2466 * Increase the size with names of options specific
2467 * of the current tracer.
2468 */
2469 for (i = 0; trace_opts[i].name; i++) {
2470 len += strlen(trace_opts[i].name);
2471 len += 3; /* "no" and space */
2472 }
2473
2440 /* +2 for \n and \0 */ 2474 /* +2 for \n and \0 */
2441 buf = kmalloc(len + 2, GFP_KERNEL); 2475 buf = kmalloc(len + 2, GFP_KERNEL);
2442 if (!buf) 2476 if (!buf)
@@ -2449,6 +2483,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
2449 r += sprintf(buf + r, "no%s ", trace_options[i]); 2483 r += sprintf(buf + r, "no%s ", trace_options[i]);
2450 } 2484 }
2451 2485
2486 for (i = 0; trace_opts[i].name; i++) {
2487 if (tracer_flags & trace_opts[i].bit)
2488 r += sprintf(buf + r, "%s ",
2489 trace_opts[i].name);
2490 else
2491 r += sprintf(buf + r, "no%s ",
2492 trace_opts[i].name);
2493 }
2494
2452 r += sprintf(buf + r, "\n"); 2495 r += sprintf(buf + r, "\n");
2453 WARN_ON(r >= len + 2); 2496 WARN_ON(r >= len + 2);
2454 2497
@@ -2459,6 +2502,40 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
2459 return r; 2502 return r;
2460} 2503}
2461 2504
2505/* Try to assign a tracer specific option */
2506static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
2507{
2508 struct tracer_flags *trace_flags = trace->flags;
2509 struct tracer_opt *opts = NULL;
2510 int ret = 0, i = 0;
2511 int len;
2512
2513 for (i = 0; trace_flags->opts[i].name; i++) {
2514 opts = &trace_flags->opts[i];
2515 len = strlen(opts->name);
2516
2517 if (strncmp(cmp, opts->name, len) == 0) {
2518 ret = trace->set_flag(trace_flags->val,
2519 opts->bit, !neg);
2520 break;
2521 }
2522 }
2523 /* Not found */
2524 if (!trace_flags->opts[i].name)
2525 return -EINVAL;
2526
2527 /* Refused to handle */
2528 if (ret)
2529 return ret;
2530
2531 if (neg)
2532 trace_flags->val &= ~opts->bit;
2533 else
2534 trace_flags->val |= opts->bit;
2535
2536 return 0;
2537}
2538
2462static ssize_t 2539static ssize_t
2463tracing_trace_options_write(struct file *filp, const char __user *ubuf, 2540tracing_trace_options_write(struct file *filp, const char __user *ubuf,
2464 size_t cnt, loff_t *ppos) 2541 size_t cnt, loff_t *ppos)
@@ -2466,6 +2543,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
2466 char buf[64]; 2543 char buf[64];
2467 char *cmp = buf; 2544 char *cmp = buf;
2468 int neg = 0; 2545 int neg = 0;
2546 int ret;
2469 int i; 2547 int i;
2470 2548
2471 if (cnt >= sizeof(buf)) 2549 if (cnt >= sizeof(buf))
@@ -2492,11 +2570,13 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
2492 break; 2570 break;
2493 } 2571 }
2494 } 2572 }
2495 /* 2573
2496 * If no option could be set, return an error: 2574 /* If no option could be set, test the specific tracer options */
2497 */ 2575 if (!trace_options[i]) {
2498 if (!trace_options[i]) 2576 ret = set_tracer_option(current_trace, cmp, neg);
2499 return -EINVAL; 2577 if (ret)
2578 return ret;
2579 }
2500 2580
2501 filp->f_pos += cnt; 2581 filp->f_pos += cnt;
2502 2582
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 37947f6b92bf..9d22618bf99f 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -259,6 +259,29 @@ enum print_line_t {
259 TRACE_TYPE_UNHANDLED = 2 /* Relay to other output functions */ 259 TRACE_TYPE_UNHANDLED = 2 /* Relay to other output functions */
260}; 260};
261 261
262
263/*
264 * An option specific to a tracer. This is a boolean value.
265 * The bit is the bit index that sets its value on the
266 * flags value in struct tracer_flags.
267 */
268struct tracer_opt {
269 const char *name; /* Will appear on the trace_options file */
270 u32 bit; /* Mask assigned in val field in tracer_flags */
271};
272
273/*
274 * The set of specific options for a tracer. Your tracer
275 * have to set the initial value of the flags val.
276 */
277struct tracer_flags {
278 u32 val;
279 struct tracer_opt *opts;
280};
281
282/* Makes more easy to define a tracer opt */
283#define TRACER_OPT(s, b) .name = #s, .bit = b
284
262/* 285/*
263 * A specific tracer, represented by methods that operate on a trace array: 286 * A specific tracer, represented by methods that operate on a trace array:
264 */ 287 */
@@ -280,8 +303,11 @@ struct tracer {
280 struct trace_array *tr); 303 struct trace_array *tr);
281#endif 304#endif
282 enum print_line_t (*print_line)(struct trace_iterator *iter); 305 enum print_line_t (*print_line)(struct trace_iterator *iter);
306 /* If you handled the flag setting, return 0 */
307 int (*set_flag)(u32 old_flags, u32 bit, int set);
283 struct tracer *next; 308 struct tracer *next;
284 int print_max; 309 int print_max;
310 struct tracer_flags *flags;
285}; 311};
286 312
287struct trace_seq { 313struct trace_seq {