aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-04-10 14:53:50 -0400
committerSteven Rostedt <rostedt@goodmis.org>2009-04-14 12:58:03 -0400
commit6d723736e472f7a0cd5b62c84152fceead241328 (patch)
tree8df2f6c47ebdfdeb8979758c877a5abbd9c06aef
parent17c873ec280a03894bc718af817f7f24fa787ae1 (diff)
tracing/events: add support for modules to TRACE_EVENT
Impact: allow modules to add TRACE_EVENTS on load This patch adds the final hooks to allow modules to use the TRACE_EVENT macro. A notifier and a data structure are used to link the TRACE_EVENTs defined in the module to connect them with the ftrace event tracing system. It also adds the necessary automated clean ups to the trace events when a module is removed. Cc: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/ftrace_event.h3
-rw-r--r--include/linux/module.h4
-rw-r--r--include/linux/trace_seq.h2
-rw-r--r--include/trace/ftrace.h1
-rw-r--r--kernel/module.c7
-rw-r--r--kernel/trace/trace_events.c128
6 files changed, 113 insertions, 32 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 17810853b4f8..75f3ac01a87c 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -7,6 +7,7 @@
7 7
8struct trace_array; 8struct trace_array;
9struct tracer; 9struct tracer;
10struct dentry;
10 11
11/* 12/*
12 * The trace entry - the most basic unit of tracing. This is what 13 * The trace entry - the most basic unit of tracing. This is what
@@ -87,6 +88,7 @@ struct ftrace_event_call {
87 char *name; 88 char *name;
88 char *system; 89 char *system;
89 struct dentry *dir; 90 struct dentry *dir;
91 struct trace_event *event;
90 int enabled; 92 int enabled;
91 int (*regfunc)(void); 93 int (*regfunc)(void);
92 void (*unregfunc)(void); 94 void (*unregfunc)(void);
@@ -97,6 +99,7 @@ struct ftrace_event_call {
97 struct list_head fields; 99 struct list_head fields;
98 int n_preds; 100 int n_preds;
99 struct filter_pred **preds; 101 struct filter_pred **preds;
102 void *mod;
100 103
101#ifdef CONFIG_EVENT_PROFILE 104#ifdef CONFIG_EVENT_PROFILE
102 atomic_t profile_count; 105 atomic_t profile_count;
diff --git a/include/linux/module.h b/include/linux/module.h
index 627ac082e2a6..6155fa44168b 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -337,6 +337,10 @@ struct module
337 const char **trace_bprintk_fmt_start; 337 const char **trace_bprintk_fmt_start;
338 unsigned int num_trace_bprintk_fmt; 338 unsigned int num_trace_bprintk_fmt;
339#endif 339#endif
340#ifdef CONFIG_EVENT_TRACING
341 struct ftrace_event_call *trace_events;
342 unsigned int num_trace_events;
343#endif
340 344
341#ifdef CONFIG_MODULE_UNLOAD 345#ifdef CONFIG_MODULE_UNLOAD
342 /* What modules depend on me? */ 346 /* What modules depend on me? */
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index 28051da876dd..15ca2c71af13 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -1,6 +1,8 @@
1#ifndef _LINUX_TRACE_SEQ_H 1#ifndef _LINUX_TRACE_SEQ_H
2#define _LINUX_TRACE_SEQ_H 2#define _LINUX_TRACE_SEQ_H
3 3
4#include <linux/fs.h>
5
4/* 6/*
5 * Trace sequences are used to allow a function to call several other functions 7 * Trace sequences are used to allow a function to call several other functions
6 * to create a string of data to use (up to a max of PAGE_SIZE. 8 * to create a string of data to use (up to a max of PAGE_SIZE.
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 955b967acd74..60c5323bee64 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -477,6 +477,7 @@ __attribute__((__aligned__(4))) \
477__attribute__((section("_ftrace_events"))) event_##call = { \ 477__attribute__((section("_ftrace_events"))) event_##call = { \
478 .name = #call, \ 478 .name = #call, \
479 .system = __stringify(TRACE_SYSTEM), \ 479 .system = __stringify(TRACE_SYSTEM), \
480 .event = &ftrace_event_type_##call, \
480 .raw_init = ftrace_raw_init_event_##call, \ 481 .raw_init = ftrace_raw_init_event_##call, \
481 .regfunc = ftrace_raw_reg_event_##call, \ 482 .regfunc = ftrace_raw_reg_event_##call, \
482 .unregfunc = ftrace_raw_unreg_event_##call, \ 483 .unregfunc = ftrace_raw_unreg_event_##call, \
diff --git a/kernel/module.c b/kernel/module.c
index e797812a4d95..a0394706f10c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -18,6 +18,7 @@
18*/ 18*/
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/moduleloader.h> 20#include <linux/moduleloader.h>
21#include <linux/ftrace_event.h>
21#include <linux/init.h> 22#include <linux/init.h>
22#include <linux/kallsyms.h> 23#include <linux/kallsyms.h>
23#include <linux/fs.h> 24#include <linux/fs.h>
@@ -2172,6 +2173,12 @@ static noinline struct module *load_module(void __user *umod,
2172 sizeof(*mod->tracepoints), 2173 sizeof(*mod->tracepoints),
2173 &mod->num_tracepoints); 2174 &mod->num_tracepoints);
2174#endif 2175#endif
2176#ifdef CONFIG_EVENT_TRACING
2177 mod->trace_events = section_objs(hdr, sechdrs, secstrings,
2178 "_ftrace_events",
2179 sizeof(*mod->trace_events),
2180 &mod->num_trace_events);
2181#endif
2175 2182
2176#ifdef CONFIG_MODVERSIONS 2183#ifdef CONFIG_MODVERSIONS
2177 if ((mod->num_syms && !mod->crcs) 2184 if ((mod->num_syms && !mod->crcs)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 8b9e621b80b4..a4b177720a6c 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -713,7 +713,13 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
713 return d_events; 713 return d_events;
714 } 714 }
715 715
716 system->name = name; 716 system->name = kstrdup(name, GFP_KERNEL);
717 if (!system->name) {
718 debugfs_remove(system->entry);
719 kfree(system);
720 return d_events;
721 }
722
717 list_add(&system->list, &event_subsystems); 723 list_add(&system->list, &event_subsystems);
718 724
719 system->preds = NULL; 725 system->preds = NULL;
@@ -738,7 +744,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
738 * If the trace point header did not define TRACE_SYSTEM 744 * If the trace point header did not define TRACE_SYSTEM
739 * then the system would be called "TRACE_SYSTEM". 745 * then the system would be called "TRACE_SYSTEM".
740 */ 746 */
741 if (strcmp(call->system, "TRACE_SYSTEM") != 0) 747 if (strcmp(call->system, TRACE_SYSTEM) != 0)
742 d_events = event_subsystem_dir(call->system, d_events); 748 d_events = event_subsystem_dir(call->system, d_events);
743 749
744 if (call->raw_init) { 750 if (call->raw_init) {
@@ -757,21 +763,13 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
757 return -1; 763 return -1;
758 } 764 }
759 765
760 if (call->regfunc) { 766 if (call->regfunc)
761 entry = debugfs_create_file("enable", 0644, call->dir, call, 767 entry = trace_create_file("enable", 0644, call->dir, call,
762 &ftrace_enable_fops); 768 &ftrace_enable_fops);
763 if (!entry)
764 pr_warning("Could not create debugfs "
765 "'%s/enable' entry\n", call->name);
766 }
767 769
768 if (call->id) { 770 if (call->id)
769 entry = debugfs_create_file("id", 0444, call->dir, call, 771 entry = trace_create_file("id", 0444, call->dir, call,
770 &ftrace_event_id_fops); 772 &ftrace_event_id_fops);
771 if (!entry)
772 pr_warning("Could not create debugfs '%s/id' entry\n",
773 call->name);
774 }
775 773
776 if (call->define_fields) { 774 if (call->define_fields) {
777 ret = call->define_fields(); 775 ret = call->define_fields();
@@ -780,40 +778,102 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
780 " events/%s\n", call->name); 778 " events/%s\n", call->name);
781 return ret; 779 return ret;
782 } 780 }
783 entry = debugfs_create_file("filter", 0644, call->dir, call, 781 entry = trace_create_file("filter", 0644, call->dir, call,
784 &ftrace_event_filter_fops); 782 &ftrace_event_filter_fops);
785 if (!entry)
786 pr_warning("Could not create debugfs "
787 "'%s/filter' entry\n", call->name);
788 } 783 }
789 784
790 /* A trace may not want to export its format */ 785 /* A trace may not want to export its format */
791 if (!call->show_format) 786 if (!call->show_format)
792 return 0; 787 return 0;
793 788
794 entry = debugfs_create_file("format", 0444, call->dir, call, 789 entry = trace_create_file("format", 0444, call->dir, call,
795 &ftrace_event_format_fops); 790 &ftrace_event_format_fops);
796 if (!entry) 791
797 pr_warning("Could not create debugfs " 792 return 0;
798 "'%s/format' entry\n", call->name); 793}
794
795#define for_each_event(event, start, end) \
796 for (event = start; \
797 (unsigned long)event < (unsigned long)end; \
798 event++)
799
800static void trace_module_add_events(struct module *mod)
801{
802 struct ftrace_event_call *call, *start, *end;
803 struct dentry *d_events;
804
805 start = mod->trace_events;
806 end = mod->trace_events + mod->num_trace_events;
807
808 if (start == end)
809 return;
810
811 d_events = event_trace_events_dir();
812 if (!d_events)
813 return;
814
815 for_each_event(call, start, end) {
816 /* The linker may leave blanks */
817 if (!call->name)
818 continue;
819 call->mod = mod;
820 list_add(&call->list, &ftrace_events);
821 event_create_dir(call, d_events);
822 }
823}
824
825static void trace_module_remove_events(struct module *mod)
826{
827 struct ftrace_event_call *call, *p;
828
829 list_for_each_entry_safe(call, p, &ftrace_events, list) {
830 if (call->mod == mod) {
831 if (call->enabled) {
832 call->enabled = 0;
833 call->unregfunc();
834 }
835 if (call->event)
836 unregister_ftrace_event(call->event);
837 debugfs_remove_recursive(call->dir);
838 list_del(&call->list);
839 }
840 }
841}
842
843int trace_module_notify(struct notifier_block *self,
844 unsigned long val, void *data)
845{
846 struct module *mod = data;
847
848 mutex_lock(&event_mutex);
849 switch (val) {
850 case MODULE_STATE_COMING:
851 trace_module_add_events(mod);
852 break;
853 case MODULE_STATE_GOING:
854 trace_module_remove_events(mod);
855 break;
856 }
857 mutex_unlock(&event_mutex);
799 858
800 return 0; 859 return 0;
801} 860}
802 861
862struct notifier_block trace_module_nb = {
863 .notifier_call = trace_module_notify,
864 .priority = 0,
865};
866
803extern struct ftrace_event_call __start_ftrace_events[]; 867extern struct ftrace_event_call __start_ftrace_events[];
804extern struct ftrace_event_call __stop_ftrace_events[]; 868extern struct ftrace_event_call __stop_ftrace_events[];
805 869
806#define for_each_event(event) \
807 for (event = __start_ftrace_events; \
808 (unsigned long)event < (unsigned long)__stop_ftrace_events; \
809 event++)
810
811static __init int event_trace_init(void) 870static __init int event_trace_init(void)
812{ 871{
813 struct ftrace_event_call *call; 872 struct ftrace_event_call *call;
814 struct dentry *d_tracer; 873 struct dentry *d_tracer;
815 struct dentry *entry; 874 struct dentry *entry;
816 struct dentry *d_events; 875 struct dentry *d_events;
876 int ret;
817 877
818 d_tracer = tracing_init_dentry(); 878 d_tracer = tracing_init_dentry();
819 if (!d_tracer) 879 if (!d_tracer)
@@ -837,7 +897,7 @@ static __init int event_trace_init(void)
837 if (!d_events) 897 if (!d_events)
838 return 0; 898 return 0;
839 899
840 for_each_event(call) { 900 for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
841 /* The linker may leave blanks */ 901 /* The linker may leave blanks */
842 if (!call->name) 902 if (!call->name)
843 continue; 903 continue;
@@ -845,6 +905,10 @@ static __init int event_trace_init(void)
845 event_create_dir(call, d_events); 905 event_create_dir(call, d_events);
846 } 906 }
847 907
908 ret = register_module_notifier(&trace_module_nb);
909 if (!ret)
910 pr_warning("Failed to register trace events module notifier\n");
911
848 return 0; 912 return 0;
849} 913}
850fs_initcall(event_trace_init); 914fs_initcall(event_trace_init);