aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-05-06 22:52:15 -0400
committerSteven Rostedt <rostedt@goodmis.org>2009-05-06 23:11:42 -0400
commit8ae79a138e88aceeeb07077bff2883245fb7c218 (patch)
treeebb58fcf7d06af26c5855f664e769f850de4b434
parent9456f0fa6d3cb944d3b9fc31c9a244e0362c26ea (diff)
tracing: add hierarchical enabling of events
With the current event directory, you can only enable individual events. The file debugfs/tracing/set_event is used to be able to enable or disable several events at once. But that can still be awkward. This patch adds hierarchical enabling of events. That is, each directory in debugfs/tracing/events has an "enable" file. This file can enable or disable all events within the directory and below. # echo 1 > /debugfs/tracing/events/enable will enable all events. # echo 1 > /debugfs/tracing/events/sched/enable will enable all events in the sched subsystem. # echo 1 > /debugfs/tracing/events/enable # echo 0 > /debugfs/tracing/events/irq/enable will enable all events, but then disable just the irq subsystem events. When reading one of these enable files, there are four results: 0 - all events this file affects are disabled 1 - all events this file affects are enabled X - there is a mixture of events enabled and disabled ? - this file does not affect any event Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--kernel/trace/trace_events.c140
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
403static ssize_t
404system_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
477static ssize_t
478system_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
403extern char *__bad_type_size(void); 530extern 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
816static 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
689static const struct file_operations ftrace_show_header_fops = { 822static 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)