diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-24 14:15:08 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-24 21:54:08 -0500 |
commit | 1473e4417c79f12d91ef91a469699bfa911f510f (patch) | |
tree | 07ae02d5383367ed883616646f885be71f7431dd /kernel/trace/trace_events.c | |
parent | f3fe8e4a38fd19dbb3f8ffb1826aa840ae304a65 (diff) |
tracing: make event directory structure
This patch adds the directory /debug/tracing/events/ that will contain
all the registered trace points.
# ls /debug/tracing/events/
sched_kthread_stop sched_process_fork sched_switch
sched_kthread_stop_ret sched_process_free sched_wait_task
sched_migrate_task sched_process_wait sched_wakeup
sched_process_exit sched_signal_send sched_wakeup_new
# ls /debug/tracing/events/sched_switch/
enable
# cat /debug/tracing/events/sched_switch/enable
1
# cat /debug/tracing/set_event
sched_switch
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r-- | kernel/trace/trace_events.c | 137 |
1 files changed, 132 insertions, 5 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 05bc80ec8d2c..3bcb9df93342 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -12,6 +12,11 @@ | |||
12 | 12 | ||
13 | #include "trace_events.h" | 13 | #include "trace_events.h" |
14 | 14 | ||
15 | #define events_for_each(event) \ | ||
16 | for (event = __start_ftrace_events; \ | ||
17 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | ||
18 | event++) | ||
19 | |||
15 | void event_trace_printk(unsigned long ip, const char *fmt, ...) | 20 | void event_trace_printk(unsigned long ip, const char *fmt, ...) |
16 | { | 21 | { |
17 | va_list ap; | 22 | va_list ap; |
@@ -39,15 +44,16 @@ static void ftrace_clear_events(void) | |||
39 | 44 | ||
40 | static int ftrace_set_clr_event(char *buf, int set) | 45 | static int ftrace_set_clr_event(char *buf, int set) |
41 | { | 46 | { |
42 | struct ftrace_event_call *call = (void *)__start_ftrace_events; | 47 | struct ftrace_event_call *call = __start_ftrace_events; |
43 | 48 | ||
44 | 49 | ||
45 | while ((unsigned long)call < (unsigned long)__stop_ftrace_events) { | 50 | events_for_each(call) { |
46 | 51 | ||
47 | if (strcmp(buf, call->name) != 0) { | 52 | if (!call->name) |
48 | call++; | 53 | continue; |
54 | |||
55 | if (strcmp(buf, call->name) != 0) | ||
49 | continue; | 56 | continue; |
50 | } | ||
51 | 57 | ||
52 | if (set) { | 58 | if (set) { |
53 | /* Already set? */ | 59 | /* Already set? */ |
@@ -223,6 +229,67 @@ ftrace_event_seq_open(struct inode *inode, struct file *file) | |||
223 | return ret; | 229 | return ret; |
224 | } | 230 | } |
225 | 231 | ||
232 | static ssize_t | ||
233 | event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
234 | loff_t *ppos) | ||
235 | { | ||
236 | struct ftrace_event_call *call = filp->private_data; | ||
237 | char *buf; | ||
238 | |||
239 | if (call->enabled) | ||
240 | buf = "1\n"; | ||
241 | else | ||
242 | buf = "0\n"; | ||
243 | |||
244 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2); | ||
245 | } | ||
246 | |||
247 | static ssize_t | ||
248 | event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
249 | loff_t *ppos) | ||
250 | { | ||
251 | struct ftrace_event_call *call = filp->private_data; | ||
252 | char buf[64]; | ||
253 | unsigned long val; | ||
254 | int ret; | ||
255 | |||
256 | if (cnt >= sizeof(buf)) | ||
257 | return -EINVAL; | ||
258 | |||
259 | if (copy_from_user(&buf, ubuf, cnt)) | ||
260 | return -EFAULT; | ||
261 | |||
262 | buf[cnt] = 0; | ||
263 | |||
264 | ret = strict_strtoul(buf, 10, &val); | ||
265 | if (ret < 0) | ||
266 | return ret; | ||
267 | |||
268 | switch (val) { | ||
269 | case 0: | ||
270 | if (!call->enabled) | ||
271 | break; | ||
272 | |||
273 | call->enabled = 0; | ||
274 | call->unregfunc(); | ||
275 | break; | ||
276 | case 1: | ||
277 | if (call->enabled) | ||
278 | break; | ||
279 | |||
280 | call->enabled = 1; | ||
281 | call->regfunc(); | ||
282 | break; | ||
283 | |||
284 | default: | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | *ppos += cnt; | ||
289 | |||
290 | return cnt; | ||
291 | } | ||
292 | |||
226 | static const struct seq_operations show_event_seq_ops = { | 293 | static const struct seq_operations show_event_seq_ops = { |
227 | .start = t_start, | 294 | .start = t_start, |
228 | .next = t_next, | 295 | .next = t_next, |
@@ -252,10 +319,59 @@ static const struct file_operations ftrace_set_event_fops = { | |||
252 | .release = seq_release, | 319 | .release = seq_release, |
253 | }; | 320 | }; |
254 | 321 | ||
322 | static const struct file_operations ftrace_enable_fops = { | ||
323 | .open = tracing_open_generic, | ||
324 | .read = event_enable_read, | ||
325 | .write = event_enable_write, | ||
326 | }; | ||
327 | |||
328 | static struct dentry *event_trace_events_dir(void) | ||
329 | { | ||
330 | static struct dentry *d_tracer; | ||
331 | static struct dentry *d_events; | ||
332 | |||
333 | if (d_events) | ||
334 | return d_events; | ||
335 | |||
336 | d_tracer = tracing_init_dentry(); | ||
337 | if (!d_tracer) | ||
338 | return NULL; | ||
339 | |||
340 | d_events = debugfs_create_dir("events", d_tracer); | ||
341 | if (!d_events) | ||
342 | pr_warning("Could not create debugfs " | ||
343 | "'events' directory\n"); | ||
344 | |||
345 | return d_events; | ||
346 | } | ||
347 | |||
348 | static int | ||
349 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | ||
350 | { | ||
351 | struct dentry *entry; | ||
352 | |||
353 | call->dir = debugfs_create_dir(call->name, d_events); | ||
354 | if (!call->dir) { | ||
355 | pr_warning("Could not create debugfs " | ||
356 | "'%s' directory\n", call->name); | ||
357 | return -1; | ||
358 | } | ||
359 | |||
360 | entry = debugfs_create_file("enable", 0644, call->dir, call, | ||
361 | &ftrace_enable_fops); | ||
362 | if (!entry) | ||
363 | pr_warning("Could not create debugfs " | ||
364 | "'%s/enable' entry\n", call->name); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
255 | static __init int event_trace_init(void) | 369 | static __init int event_trace_init(void) |
256 | { | 370 | { |
371 | struct ftrace_event_call *call = __start_ftrace_events; | ||
257 | struct dentry *d_tracer; | 372 | struct dentry *d_tracer; |
258 | struct dentry *entry; | 373 | struct dentry *entry; |
374 | struct dentry *d_events; | ||
259 | 375 | ||
260 | d_tracer = tracing_init_dentry(); | 376 | d_tracer = tracing_init_dentry(); |
261 | if (!d_tracer) | 377 | if (!d_tracer) |
@@ -275,6 +391,17 @@ static __init int event_trace_init(void) | |||
275 | pr_warning("Could not create debugfs " | 391 | pr_warning("Could not create debugfs " |
276 | "'set_event' entry\n"); | 392 | "'set_event' entry\n"); |
277 | 393 | ||
394 | d_events = event_trace_events_dir(); | ||
395 | if (!d_events) | ||
396 | return 0; | ||
397 | |||
398 | events_for_each(call) { | ||
399 | /* The linker may leave blanks */ | ||
400 | if (!call->name) | ||
401 | continue; | ||
402 | event_create_dir(call, d_events); | ||
403 | } | ||
404 | |||
278 | return 0; | 405 | return 0; |
279 | } | 406 | } |
280 | fs_initcall(event_trace_init); | 407 | fs_initcall(event_trace_init); |