diff options
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r-- | kernel/trace/trace_events.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 6d2c842a0248..87feb0117ce2 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -400,6 +400,133 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
400 | return cnt; | 400 | return cnt; |
401 | } | 401 | } |
402 | 402 | ||
403 | static ssize_t | ||
404 | system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
405 | loff_t *ppos) | ||
406 | { | ||
407 | const char *system = filp->private_data; | ||
408 | struct ftrace_event_call *call; | ||
409 | char buf[2]; | ||
410 | int set = -1; | ||
411 | int all = 0; | ||
412 | int ret; | ||
413 | |||
414 | if (system[0] == '*') | ||
415 | all = 1; | ||
416 | |||
417 | mutex_lock(&event_mutex); | ||
418 | list_for_each_entry(call, &ftrace_events, list) { | ||
419 | if (!call->name || !call->regfunc) | ||
420 | continue; | ||
421 | |||
422 | if (!all && strcmp(call->system, system) != 0) | ||
423 | continue; | ||
424 | |||
425 | /* | ||
426 | * We need to find out if all the events are set | ||
427 | * or if all events or cleared, or if we have | ||
428 | * a mixture. | ||
429 | */ | ||
430 | if (call->enabled) { | ||
431 | switch (set) { | ||
432 | case -1: | ||
433 | set = 1; | ||
434 | break; | ||
435 | case 0: | ||
436 | set = 2; | ||
437 | break; | ||
438 | } | ||
439 | } else { | ||
440 | switch (set) { | ||
441 | case -1: | ||
442 | set = 0; | ||
443 | break; | ||
444 | case 1: | ||
445 | set = 2; | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | /* | ||
450 | * If we have a mixture, no need to look further. | ||
451 | */ | ||
452 | if (set == 2) | ||
453 | break; | ||
454 | } | ||
455 | mutex_unlock(&event_mutex); | ||
456 | |||
457 | buf[1] = '\n'; | ||
458 | switch (set) { | ||
459 | case 0: | ||
460 | buf[0] = '0'; | ||
461 | break; | ||
462 | case 1: | ||
463 | buf[0] = '1'; | ||
464 | break; | ||
465 | case 2: | ||
466 | buf[0] = 'X'; | ||
467 | break; | ||
468 | default: | ||
469 | buf[0] = '?'; | ||
470 | } | ||
471 | |||
472 | ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, 2); | ||
473 | |||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | static ssize_t | ||
478 | system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
479 | loff_t *ppos) | ||
480 | { | ||
481 | const char *system = filp->private_data; | ||
482 | unsigned long val; | ||
483 | char *command; | ||
484 | char buf[64]; | ||
485 | ssize_t ret; | ||
486 | |||
487 | if (cnt >= sizeof(buf)) | ||
488 | return -EINVAL; | ||
489 | |||
490 | if (copy_from_user(&buf, ubuf, cnt)) | ||
491 | return -EFAULT; | ||
492 | |||
493 | buf[cnt] = 0; | ||
494 | |||
495 | ret = strict_strtoul(buf, 10, &val); | ||
496 | if (ret < 0) | ||
497 | return ret; | ||
498 | |||
499 | ret = tracing_update_buffers(); | ||
500 | if (ret < 0) | ||
501 | return ret; | ||
502 | |||
503 | switch (val) { | ||
504 | case 0: | ||
505 | case 1: | ||
506 | break; | ||
507 | |||
508 | default: | ||
509 | return -EINVAL; | ||
510 | } | ||
511 | |||
512 | command = kstrdup(system, GFP_KERNEL); | ||
513 | if (!command) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | ret = ftrace_set_clr_event(command, val); | ||
517 | if (ret) | ||
518 | goto out_free; | ||
519 | |||
520 | ret = cnt; | ||
521 | |||
522 | out_free: | ||
523 | kfree(command); | ||
524 | |||
525 | *ppos += cnt; | ||
526 | |||
527 | return ret; | ||
528 | } | ||
529 | |||
403 | extern char *__bad_type_size(void); | 530 | extern char *__bad_type_size(void); |
404 | 531 | ||
405 | #undef FIELD | 532 | #undef FIELD |
@@ -686,6 +813,12 @@ static const struct file_operations ftrace_subsystem_filter_fops = { | |||
686 | .write = subsystem_filter_write, | 813 | .write = subsystem_filter_write, |
687 | }; | 814 | }; |
688 | 815 | ||
816 | static const struct file_operations ftrace_system_enable_fops = { | ||
817 | .open = tracing_open_generic, | ||
818 | .read = system_enable_read, | ||
819 | .write = system_enable_write, | ||
820 | }; | ||
821 | |||
689 | static const struct file_operations ftrace_show_header_fops = { | 822 | static const struct file_operations ftrace_show_header_fops = { |
690 | .open = tracing_open_generic, | 823 | .open = tracing_open_generic, |
691 | .read = show_header, | 824 | .read = show_header, |
@@ -768,6 +901,10 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
768 | "'%s/filter' entry\n", name); | 901 | "'%s/filter' entry\n", name); |
769 | } | 902 | } |
770 | 903 | ||
904 | entry = trace_create_file("enable", 0644, system->entry, | ||
905 | (void *)system->name, | ||
906 | &ftrace_system_enable_fops); | ||
907 | |||
771 | return system->entry; | 908 | return system->entry; |
772 | } | 909 | } |
773 | 910 | ||
@@ -1041,6 +1178,9 @@ static __init int event_trace_init(void) | |||
1041 | ring_buffer_print_entry_header, | 1178 | ring_buffer_print_entry_header, |
1042 | &ftrace_show_header_fops); | 1179 | &ftrace_show_header_fops); |
1043 | 1180 | ||
1181 | trace_create_file("enable", 0644, d_events, | ||
1182 | "*:*", &ftrace_system_enable_fops); | ||
1183 | |||
1044 | for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { | 1184 | for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { |
1045 | /* The linker may leave blanks */ | 1185 | /* The linker may leave blanks */ |
1046 | if (!call->name) | 1186 | if (!call->name) |