diff options
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r-- | kernel/trace/trace_events.c | 294 |
1 files changed, 264 insertions, 30 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3bcb9df93342..1d07f800a9ce 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -10,7 +10,9 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/ctype.h> | 11 | #include <linux/ctype.h> |
12 | 12 | ||
13 | #include "trace_events.h" | 13 | #include "trace.h" |
14 | |||
15 | #define TRACE_SYSTEM "TRACE_SYSTEM" | ||
14 | 16 | ||
15 | #define events_for_each(event) \ | 17 | #define events_for_each(event) \ |
16 | for (event = __start_ftrace_events; \ | 18 | for (event = __start_ftrace_events; \ |
@@ -42,35 +44,87 @@ static void ftrace_clear_events(void) | |||
42 | } | 44 | } |
43 | } | 45 | } |
44 | 46 | ||
47 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, | ||
48 | int enable) | ||
49 | { | ||
50 | |||
51 | switch (enable) { | ||
52 | case 0: | ||
53 | if (call->enabled) { | ||
54 | call->enabled = 0; | ||
55 | call->unregfunc(); | ||
56 | } | ||
57 | if (call->raw_enabled) { | ||
58 | call->raw_enabled = 0; | ||
59 | call->raw_unreg(); | ||
60 | } | ||
61 | break; | ||
62 | case 1: | ||
63 | if (!call->enabled && | ||
64 | (call->type & TRACE_EVENT_TYPE_PRINTF)) { | ||
65 | call->enabled = 1; | ||
66 | call->regfunc(); | ||
67 | } | ||
68 | if (!call->raw_enabled && | ||
69 | (call->type & TRACE_EVENT_TYPE_RAW)) { | ||
70 | call->raw_enabled = 1; | ||
71 | call->raw_reg(); | ||
72 | } | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
45 | static int ftrace_set_clr_event(char *buf, int set) | 77 | static int ftrace_set_clr_event(char *buf, int set) |
46 | { | 78 | { |
47 | struct ftrace_event_call *call = __start_ftrace_events; | 79 | struct ftrace_event_call *call = __start_ftrace_events; |
48 | 80 | char *event = NULL, *sub = NULL, *match; | |
81 | int ret = -EINVAL; | ||
82 | |||
83 | /* | ||
84 | * The buf format can be <subsystem>:<event-name> | ||
85 | * *:<event-name> means any event by that name. | ||
86 | * :<event-name> is the same. | ||
87 | * | ||
88 | * <subsystem>:* means all events in that subsystem | ||
89 | * <subsystem>: means the same. | ||
90 | * | ||
91 | * <name> (no ':') means all events in a subsystem with | ||
92 | * the name <name> or any event that matches <name> | ||
93 | */ | ||
94 | |||
95 | match = strsep(&buf, ":"); | ||
96 | if (buf) { | ||
97 | sub = match; | ||
98 | event = buf; | ||
99 | match = NULL; | ||
100 | |||
101 | if (!strlen(sub) || strcmp(sub, "*") == 0) | ||
102 | sub = NULL; | ||
103 | if (!strlen(event) || strcmp(event, "*") == 0) | ||
104 | event = NULL; | ||
105 | } | ||
49 | 106 | ||
50 | events_for_each(call) { | 107 | events_for_each(call) { |
51 | 108 | ||
52 | if (!call->name) | 109 | if (!call->name) |
53 | continue; | 110 | continue; |
54 | 111 | ||
55 | if (strcmp(buf, call->name) != 0) | 112 | if (match && |
113 | strcmp(match, call->name) != 0 && | ||
114 | strcmp(match, call->system) != 0) | ||
56 | continue; | 115 | continue; |
57 | 116 | ||
58 | if (set) { | 117 | if (sub && strcmp(sub, call->system) != 0) |
59 | /* Already set? */ | 118 | continue; |
60 | if (call->enabled) | 119 | |
61 | return 0; | 120 | if (event && strcmp(event, call->name) != 0) |
62 | call->enabled = 1; | 121 | continue; |
63 | call->regfunc(); | 122 | |
64 | } else { | 123 | ftrace_event_enable_disable(call, set); |
65 | /* Already cleared? */ | 124 | |
66 | if (!call->enabled) | 125 | ret = 0; |
67 | return 0; | ||
68 | call->enabled = 0; | ||
69 | call->unregfunc(); | ||
70 | } | ||
71 | return 0; | ||
72 | } | 126 | } |
73 | return -EINVAL; | 127 | return ret; |
74 | } | 128 | } |
75 | 129 | ||
76 | /* 128 should be much more than enough */ | 130 | /* 128 should be much more than enough */ |
@@ -200,6 +254,8 @@ static int t_show(struct seq_file *m, void *v) | |||
200 | { | 254 | { |
201 | struct ftrace_event_call *call = v; | 255 | struct ftrace_event_call *call = v; |
202 | 256 | ||
257 | if (strcmp(call->system, TRACE_SYSTEM) != 0) | ||
258 | seq_printf(m, "%s:", call->system); | ||
203 | seq_printf(m, "%s\n", call->name); | 259 | seq_printf(m, "%s\n", call->name); |
204 | 260 | ||
205 | return 0; | 261 | return 0; |
@@ -236,7 +292,7 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
236 | struct ftrace_event_call *call = filp->private_data; | 292 | struct ftrace_event_call *call = filp->private_data; |
237 | char *buf; | 293 | char *buf; |
238 | 294 | ||
239 | if (call->enabled) | 295 | if (call->enabled || call->raw_enabled) |
240 | buf = "1\n"; | 296 | buf = "1\n"; |
241 | else | 297 | else |
242 | buf = "0\n"; | 298 | buf = "0\n"; |
@@ -267,18 +323,8 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
267 | 323 | ||
268 | switch (val) { | 324 | switch (val) { |
269 | case 0: | 325 | case 0: |
270 | if (!call->enabled) | ||
271 | break; | ||
272 | |||
273 | call->enabled = 0; | ||
274 | call->unregfunc(); | ||
275 | break; | ||
276 | case 1: | 326 | case 1: |
277 | if (call->enabled) | 327 | ftrace_event_enable_disable(call, val); |
278 | break; | ||
279 | |||
280 | call->enabled = 1; | ||
281 | call->regfunc(); | ||
282 | break; | 328 | break; |
283 | 329 | ||
284 | default: | 330 | default: |
@@ -290,6 +336,107 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
290 | return cnt; | 336 | return cnt; |
291 | } | 337 | } |
292 | 338 | ||
339 | static ssize_t | ||
340 | event_type_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
341 | loff_t *ppos) | ||
342 | { | ||
343 | struct ftrace_event_call *call = filp->private_data; | ||
344 | char buf[16]; | ||
345 | int r = 0; | ||
346 | |||
347 | if (call->type & TRACE_EVENT_TYPE_PRINTF) | ||
348 | r += sprintf(buf, "printf\n"); | ||
349 | |||
350 | if (call->type & TRACE_EVENT_TYPE_RAW) | ||
351 | r += sprintf(buf+r, "raw\n"); | ||
352 | |||
353 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
354 | } | ||
355 | |||
356 | static ssize_t | ||
357 | event_type_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
358 | loff_t *ppos) | ||
359 | { | ||
360 | struct ftrace_event_call *call = filp->private_data; | ||
361 | char buf[64]; | ||
362 | |||
363 | /* | ||
364 | * If there's only one type, we can't change it. | ||
365 | * And currently we always have printf type, and we | ||
366 | * may or may not have raw type. | ||
367 | * | ||
368 | * This is a redundant check, the file should be read | ||
369 | * only if this is the case anyway. | ||
370 | */ | ||
371 | |||
372 | if (!call->raw_init) | ||
373 | return -EPERM; | ||
374 | |||
375 | if (cnt >= sizeof(buf)) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (copy_from_user(&buf, ubuf, cnt)) | ||
379 | return -EFAULT; | ||
380 | |||
381 | buf[cnt] = 0; | ||
382 | |||
383 | if (!strncmp(buf, "printf", 6) && | ||
384 | (!buf[6] || isspace(buf[6]))) { | ||
385 | |||
386 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
387 | |||
388 | /* | ||
389 | * If raw enabled, the disable it and enable | ||
390 | * printf type. | ||
391 | */ | ||
392 | if (call->raw_enabled) { | ||
393 | call->raw_enabled = 0; | ||
394 | call->raw_unreg(); | ||
395 | |||
396 | call->enabled = 1; | ||
397 | call->regfunc(); | ||
398 | } | ||
399 | |||
400 | } else if (!strncmp(buf, "raw", 3) && | ||
401 | (!buf[3] || isspace(buf[3]))) { | ||
402 | |||
403 | call->type = TRACE_EVENT_TYPE_RAW; | ||
404 | |||
405 | /* | ||
406 | * If printf enabled, the disable it and enable | ||
407 | * raw type. | ||
408 | */ | ||
409 | if (call->enabled) { | ||
410 | call->enabled = 0; | ||
411 | call->unregfunc(); | ||
412 | |||
413 | call->raw_enabled = 1; | ||
414 | call->raw_reg(); | ||
415 | } | ||
416 | } else | ||
417 | return -EINVAL; | ||
418 | |||
419 | *ppos += cnt; | ||
420 | |||
421 | return cnt; | ||
422 | } | ||
423 | |||
424 | static ssize_t | ||
425 | event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
426 | loff_t *ppos) | ||
427 | { | ||
428 | struct ftrace_event_call *call = filp->private_data; | ||
429 | char buf[16]; | ||
430 | int r = 0; | ||
431 | |||
432 | r += sprintf(buf, "printf\n"); | ||
433 | |||
434 | if (call->raw_init) | ||
435 | r += sprintf(buf+r, "raw\n"); | ||
436 | |||
437 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
438 | } | ||
439 | |||
293 | static const struct seq_operations show_event_seq_ops = { | 440 | static const struct seq_operations show_event_seq_ops = { |
294 | .start = t_start, | 441 | .start = t_start, |
295 | .next = t_next, | 442 | .next = t_next, |
@@ -325,6 +472,17 @@ static const struct file_operations ftrace_enable_fops = { | |||
325 | .write = event_enable_write, | 472 | .write = event_enable_write, |
326 | }; | 473 | }; |
327 | 474 | ||
475 | static const struct file_operations ftrace_type_fops = { | ||
476 | .open = tracing_open_generic, | ||
477 | .read = event_type_read, | ||
478 | .write = event_type_write, | ||
479 | }; | ||
480 | |||
481 | static const struct file_operations ftrace_available_types_fops = { | ||
482 | .open = tracing_open_generic, | ||
483 | .read = event_available_types_read, | ||
484 | }; | ||
485 | |||
328 | static struct dentry *event_trace_events_dir(void) | 486 | static struct dentry *event_trace_events_dir(void) |
329 | { | 487 | { |
330 | static struct dentry *d_tracer; | 488 | static struct dentry *d_tracer; |
@@ -345,10 +503,71 @@ static struct dentry *event_trace_events_dir(void) | |||
345 | return d_events; | 503 | return d_events; |
346 | } | 504 | } |
347 | 505 | ||
506 | struct event_subsystem { | ||
507 | struct list_head list; | ||
508 | const char *name; | ||
509 | struct dentry *entry; | ||
510 | }; | ||
511 | |||
512 | static LIST_HEAD(event_subsystems); | ||
513 | |||
514 | static struct dentry * | ||
515 | event_subsystem_dir(const char *name, struct dentry *d_events) | ||
516 | { | ||
517 | struct event_subsystem *system; | ||
518 | |||
519 | /* First see if we did not already create this dir */ | ||
520 | list_for_each_entry(system, &event_subsystems, list) { | ||
521 | if (strcmp(system->name, name) == 0) | ||
522 | return system->entry; | ||
523 | } | ||
524 | |||
525 | /* need to create new entry */ | ||
526 | system = kmalloc(sizeof(*system), GFP_KERNEL); | ||
527 | if (!system) { | ||
528 | pr_warning("No memory to create event subsystem %s\n", | ||
529 | name); | ||
530 | return d_events; | ||
531 | } | ||
532 | |||
533 | system->entry = debugfs_create_dir(name, d_events); | ||
534 | if (!system->entry) { | ||
535 | pr_warning("Could not create event subsystem %s\n", | ||
536 | name); | ||
537 | kfree(system); | ||
538 | return d_events; | ||
539 | } | ||
540 | |||
541 | system->name = name; | ||
542 | list_add(&system->list, &event_subsystems); | ||
543 | |||
544 | return system->entry; | ||
545 | } | ||
546 | |||
348 | static int | 547 | static int |
349 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | 548 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) |
350 | { | 549 | { |
351 | struct dentry *entry; | 550 | struct dentry *entry; |
551 | int ret; | ||
552 | |||
553 | /* | ||
554 | * If the trace point header did not define TRACE_SYSTEM | ||
555 | * then the system would be called "TRACE_SYSTEM". | ||
556 | */ | ||
557 | if (strcmp(call->system, "TRACE_SYSTEM") != 0) | ||
558 | d_events = event_subsystem_dir(call->system, d_events); | ||
559 | |||
560 | if (call->raw_init) { | ||
561 | ret = call->raw_init(); | ||
562 | if (ret < 0) { | ||
563 | pr_warning("Could not initialize trace point" | ||
564 | " events/%s\n", call->name); | ||
565 | return ret; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | /* default the output to printf */ | ||
570 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
352 | 571 | ||
353 | call->dir = debugfs_create_dir(call->name, d_events); | 572 | call->dir = debugfs_create_dir(call->name, d_events); |
354 | if (!call->dir) { | 573 | if (!call->dir) { |
@@ -363,6 +582,21 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
363 | pr_warning("Could not create debugfs " | 582 | pr_warning("Could not create debugfs " |
364 | "'%s/enable' entry\n", call->name); | 583 | "'%s/enable' entry\n", call->name); |
365 | 584 | ||
585 | /* Only let type be writable, if we can change it */ | ||
586 | entry = debugfs_create_file("type", | ||
587 | call->raw_init ? 0644 : 0444, | ||
588 | call->dir, call, | ||
589 | &ftrace_type_fops); | ||
590 | if (!entry) | ||
591 | pr_warning("Could not create debugfs " | ||
592 | "'%s/type' entry\n", call->name); | ||
593 | |||
594 | entry = debugfs_create_file("available_types", 0444, call->dir, call, | ||
595 | &ftrace_available_types_fops); | ||
596 | if (!entry) | ||
597 | pr_warning("Could not create debugfs " | ||
598 | "'%s/type' available_types\n", call->name); | ||
599 | |||
366 | return 0; | 600 | return 0; |
367 | } | 601 | } |
368 | 602 | ||