aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2009-08-13 16:34:53 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-08-26 18:46:40 -0400
commitbd1a5c849bdcc5c89e4a6a18216cd2b9a7a8a78f (patch)
tree1a807fef00b8a700d90683d4f1d480d95eec9669 /kernel/trace
parentb1cf540f0e5278ecfe8532557e547d833ed269d7 (diff)
tracing: Ftrace dynamic ftrace_event_call support
Add dynamic ftrace_event_call support to ftrace. Trace engines can add new ftrace_event_call to ftrace on the fly. Each operator function of the call takes an ftrace_event_call data structure as an argument, because these functions may be shared among several ftrace_event_calls. Changes from v13: - Define remove_subsystem_dir() always (revirt a2ca5e03), because trace_remove_event_call() uses it. - Modify syscall tracer because of ftrace_event_call change. [fweisbec@gmail.com: Fixed conflict against latest tracing/core] Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Avi Kivity <avi@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jason Baron <jbaron@redhat.com> Cc: Jim Keniston <jkenisto@us.ibm.com> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Przemysław Pawełczyk <przemyslaw@pawelczyk.it> Cc: Roland McGrath <roland@redhat.com> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Vegard Nossum <vegard.nossum@gmail.com> LKML-Reference: <20090813203453.31965.71901.stgit@localhost.localdomain> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events.c121
-rw-r--r--kernel/trace/trace_export.c18
-rw-r--r--kernel/trace/trace_syscalls.c20
3 files changed, 103 insertions, 56 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index d33bcdeffe69..8079bb511c43 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -27,8 +27,8 @@ DEFINE_MUTEX(event_mutex);
27 27
28LIST_HEAD(ftrace_events); 28LIST_HEAD(ftrace_events);
29 29
30int trace_define_field(struct ftrace_event_call *call, const char *type, 30int trace_define_field(struct ftrace_event_call *call, char *type,
31 const char *name, int offset, int size, int is_signed, 31 char *name, int offset, int size, int is_signed,
32 int filter_type) 32 int filter_type)
33{ 33{
34 struct ftrace_event_field *field; 34 struct ftrace_event_field *field;
@@ -92,9 +92,7 @@ int trace_define_common_fields(struct ftrace_event_call *call)
92} 92}
93EXPORT_SYMBOL_GPL(trace_define_common_fields); 93EXPORT_SYMBOL_GPL(trace_define_common_fields);
94 94
95#ifdef CONFIG_MODULES 95void trace_destroy_fields(struct ftrace_event_call *call)
96
97static void trace_destroy_fields(struct ftrace_event_call *call)
98{ 96{
99 struct ftrace_event_field *field, *next; 97 struct ftrace_event_field *field, *next;
100 98
@@ -106,8 +104,6 @@ static void trace_destroy_fields(struct ftrace_event_call *call)
106 } 104 }
107} 105}
108 106
109#endif /* CONFIG_MODULES */
110
111static void ftrace_event_enable_disable(struct ftrace_event_call *call, 107static void ftrace_event_enable_disable(struct ftrace_event_call *call,
112 int enable) 108 int enable)
113{ 109{
@@ -116,14 +112,14 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
116 if (call->enabled) { 112 if (call->enabled) {
117 call->enabled = 0; 113 call->enabled = 0;
118 tracing_stop_cmdline_record(); 114 tracing_stop_cmdline_record();
119 call->unregfunc(call->data); 115 call->unregfunc(call);
120 } 116 }
121 break; 117 break;
122 case 1: 118 case 1:
123 if (!call->enabled) { 119 if (!call->enabled) {
124 call->enabled = 1; 120 call->enabled = 1;
125 tracing_start_cmdline_record(); 121 tracing_start_cmdline_record();
126 call->regfunc(call->data); 122 call->regfunc(call);
127 } 123 }
128 break; 124 break;
129 } 125 }
@@ -991,27 +987,43 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
991 return 0; 987 return 0;
992} 988}
993 989
994#define for_each_event(event, start, end) \ 990static int __trace_add_event_call(struct ftrace_event_call *call)
995 for (event = start; \ 991{
996 (unsigned long)event < (unsigned long)end; \ 992 struct dentry *d_events;
997 event++) 993 int ret;
998 994
999#ifdef CONFIG_MODULES 995 if (!call->name)
996 return -EINVAL;
1000 997
1001static LIST_HEAD(ftrace_module_file_list); 998 if (call->raw_init) {
999 ret = call->raw_init(call);
1000 if (ret < 0) {
1001 if (ret != -ENOSYS)
1002 pr_warning("Could not initialize trace "
1003 "events/%s\n", call->name);
1004 return ret;
1005 }
1006 }
1002 1007
1003/* 1008 d_events = event_trace_events_dir();
1004 * Modules must own their file_operations to keep up with 1009 if (!d_events)
1005 * reference counting. 1010 return -ENOENT;
1006 */ 1011
1007struct ftrace_module_file_ops { 1012 list_add(&call->list, &ftrace_events);
1008 struct list_head list; 1013 return event_create_dir(call, d_events, &ftrace_event_id_fops,
1009 struct module *mod; 1014 &ftrace_enable_fops, &ftrace_event_filter_fops,
1010 struct file_operations id; 1015 &ftrace_event_format_fops);
1011 struct file_operations enable; 1016}
1012 struct file_operations format; 1017
1013 struct file_operations filter; 1018/* Add an additional event_call dynamically */
1014}; 1019int trace_add_event_call(struct ftrace_event_call *call)
1020{
1021 int ret;
1022 mutex_lock(&event_mutex);
1023 ret = __trace_add_event_call(call);
1024 mutex_unlock(&event_mutex);
1025 return ret;
1026}
1015 1027
1016static void remove_subsystem_dir(const char *name) 1028static void remove_subsystem_dir(const char *name)
1017{ 1029{
@@ -1039,6 +1051,48 @@ static void remove_subsystem_dir(const char *name)
1039 } 1051 }
1040} 1052}
1041 1053
1054static void __trace_remove_event_call(struct ftrace_event_call *call)
1055{
1056 ftrace_event_enable_disable(call, 0);
1057 if (call->event)
1058 __unregister_ftrace_event(call->event);
1059 debugfs_remove_recursive(call->dir);
1060 list_del(&call->list);
1061 trace_destroy_fields(call);
1062 destroy_preds(call);
1063 remove_subsystem_dir(call->system);
1064}
1065
1066/* Remove an event_call */
1067void trace_remove_event_call(struct ftrace_event_call *call)
1068{
1069 mutex_lock(&event_mutex);
1070 __trace_remove_event_call(call);
1071 mutex_unlock(&event_mutex);
1072}
1073
1074#define for_each_event(event, start, end) \
1075 for (event = start; \
1076 (unsigned long)event < (unsigned long)end; \
1077 event++)
1078
1079#ifdef CONFIG_MODULES
1080
1081static LIST_HEAD(ftrace_module_file_list);
1082
1083/*
1084 * Modules must own their file_operations to keep up with
1085 * reference counting.
1086 */
1087struct ftrace_module_file_ops {
1088 struct list_head list;
1089 struct module *mod;
1090 struct file_operations id;
1091 struct file_operations enable;
1092 struct file_operations format;
1093 struct file_operations filter;
1094};
1095
1042static struct ftrace_module_file_ops * 1096static struct ftrace_module_file_ops *
1043trace_create_file_ops(struct module *mod) 1097trace_create_file_ops(struct module *mod)
1044{ 1098{
@@ -1096,7 +1150,7 @@ static void trace_module_add_events(struct module *mod)
1096 if (!call->name) 1150 if (!call->name)
1097 continue; 1151 continue;
1098 if (call->raw_init) { 1152 if (call->raw_init) {
1099 ret = call->raw_init(); 1153 ret = call->raw_init(call);
1100 if (ret < 0) { 1154 if (ret < 0) {
1101 if (ret != -ENOSYS) 1155 if (ret != -ENOSYS)
1102 pr_warning("Could not initialize trace " 1156 pr_warning("Could not initialize trace "
@@ -1131,14 +1185,7 @@ static void trace_module_remove_events(struct module *mod)
1131 list_for_each_entry_safe(call, p, &ftrace_events, list) { 1185 list_for_each_entry_safe(call, p, &ftrace_events, list) {
1132 if (call->mod == mod) { 1186 if (call->mod == mod) {
1133 found = true; 1187 found = true;
1134 ftrace_event_enable_disable(call, 0); 1188 __trace_remove_event_call(call);
1135 if (call->event)
1136 __unregister_ftrace_event(call->event);
1137 debugfs_remove_recursive(call->dir);
1138 list_del(&call->list);
1139 trace_destroy_fields(call);
1140 destroy_preds(call);
1141 remove_subsystem_dir(call->system);
1142 } 1189 }
1143 } 1190 }
1144 1191
@@ -1256,7 +1303,7 @@ static __init int event_trace_init(void)
1256 if (!call->name) 1303 if (!call->name)
1257 continue; 1304 continue;
1258 if (call->raw_init) { 1305 if (call->raw_init) {
1259 ret = call->raw_init(); 1306 ret = call->raw_init(call);
1260 if (ret < 0) { 1307 if (ret < 0) {
1261 if (ret != -ENOSYS) 1308 if (ret != -ENOSYS)
1262 pr_warning("Could not initialize trace " 1309 pr_warning("Could not initialize trace "
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 029a91f42287..9cbe7f1930ea 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -117,10 +117,16 @@ ftrace_format_##call(struct ftrace_event_call *unused, \
117#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \ 117#define TRACE_FIELD_SPECIAL(type_item, item, len, cmd) \
118 cmd; 118 cmd;
119 119
120static int ftrace_raw_init_event(struct ftrace_event_call *event_call)
121{
122 INIT_LIST_HEAD(&event_call->fields);
123 init_preds(event_call);
124 return 0;
125}
126
120#undef TRACE_EVENT_FORMAT 127#undef TRACE_EVENT_FORMAT
121#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ 128#define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \
122int ftrace_define_fields_##call(struct ftrace_event_call *event_call); \ 129int ftrace_define_fields_##call(struct ftrace_event_call *event_call); \
123static int ftrace_raw_init_event_##call(void); \
124 \ 130 \
125struct ftrace_event_call __used \ 131struct ftrace_event_call __used \
126__attribute__((__aligned__(4))) \ 132__attribute__((__aligned__(4))) \
@@ -128,16 +134,10 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
128 .name = #call, \ 134 .name = #call, \
129 .id = proto, \ 135 .id = proto, \
130 .system = __stringify(TRACE_SYSTEM), \ 136 .system = __stringify(TRACE_SYSTEM), \
131 .raw_init = ftrace_raw_init_event_##call, \ 137 .raw_init = ftrace_raw_init_event, \
132 .show_format = ftrace_format_##call, \ 138 .show_format = ftrace_format_##call, \
133 .define_fields = ftrace_define_fields_##call, \ 139 .define_fields = ftrace_define_fields_##call, \
134}; \ 140};
135static int ftrace_raw_init_event_##call(void) \
136{ \
137 INIT_LIST_HEAD(&event_##call.fields); \
138 init_preds(&event_##call); \
139 return 0; \
140} \
141 141
142#undef TRACE_EVENT_FORMAT_NOFILTER 142#undef TRACE_EVENT_FORMAT_NOFILTER
143#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \ 143#define TRACE_EVENT_FORMAT_NOFILTER(call, proto, args, fmt, tstruct, \
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 85291c4de406..5931933587e9 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -193,8 +193,8 @@ int syscall_enter_define_fields(struct ftrace_event_call *call)
193 return ret; 193 return ret;
194 194
195 for (i = 0; i < meta->nb_args; i++) { 195 for (i = 0; i < meta->nb_args; i++) {
196 ret = trace_define_field(call, meta->types[i], 196 ret = trace_define_field(call, (char *)meta->types[i],
197 meta->args[i], offset, 197 (char *)meta->args[i], offset,
198 sizeof(unsigned long), 0, 198 sizeof(unsigned long), 0,
199 FILTER_OTHER); 199 FILTER_OTHER);
200 offset += sizeof(unsigned long); 200 offset += sizeof(unsigned long);
@@ -277,13 +277,13 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
277 trace_current_buffer_unlock_commit(event, 0, 0); 277 trace_current_buffer_unlock_commit(event, 0, 0);
278} 278}
279 279
280int reg_event_syscall_enter(void *ptr) 280int reg_event_syscall_enter(struct ftrace_event_call *call)
281{ 281{
282 int ret = 0; 282 int ret = 0;
283 int num; 283 int num;
284 char *name; 284 char *name;
285 285
286 name = (char *)ptr; 286 name = (char *)call->data;
287 num = syscall_name_to_nr(name); 287 num = syscall_name_to_nr(name);
288 if (num < 0 || num >= FTRACE_SYSCALL_MAX) 288 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
289 return -ENOSYS; 289 return -ENOSYS;
@@ -301,12 +301,12 @@ int reg_event_syscall_enter(void *ptr)
301 return ret; 301 return ret;
302} 302}
303 303
304void unreg_event_syscall_enter(void *ptr) 304void unreg_event_syscall_enter(struct ftrace_event_call *call)
305{ 305{
306 int num; 306 int num;
307 char *name; 307 char *name;
308 308
309 name = (char *)ptr; 309 name = (char *)call->data;
310 num = syscall_name_to_nr(name); 310 num = syscall_name_to_nr(name);
311 if (num < 0 || num >= FTRACE_SYSCALL_MAX) 311 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
312 return; 312 return;
@@ -318,13 +318,13 @@ void unreg_event_syscall_enter(void *ptr)
318 mutex_unlock(&syscall_trace_lock); 318 mutex_unlock(&syscall_trace_lock);
319} 319}
320 320
321int reg_event_syscall_exit(void *ptr) 321int reg_event_syscall_exit(struct ftrace_event_call *call)
322{ 322{
323 int ret = 0; 323 int ret = 0;
324 int num; 324 int num;
325 char *name; 325 char *name;
326 326
327 name = (char *)ptr; 327 name = (char *)call->data;
328 num = syscall_name_to_nr(name); 328 num = syscall_name_to_nr(name);
329 if (num < 0 || num >= FTRACE_SYSCALL_MAX) 329 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
330 return -ENOSYS; 330 return -ENOSYS;
@@ -342,12 +342,12 @@ int reg_event_syscall_exit(void *ptr)
342 return ret; 342 return ret;
343} 343}
344 344
345void unreg_event_syscall_exit(void *ptr) 345void unreg_event_syscall_exit(struct ftrace_event_call *call)
346{ 346{
347 int num; 347 int num;
348 char *name; 348 char *name;
349 349
350 name = (char *)ptr; 350 name = (char *)call->data;
351 num = syscall_name_to_nr(name); 351 num = syscall_name_to_nr(name);
352 if (num < 0 || num >= FTRACE_SYSCALL_MAX) 352 if (num < 0 || num >= FTRACE_SYSCALL_MAX)
353 return; 353 return;