4 * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
8 #include <linux/debugfs.h>
9 #include <linux/uaccess.h>
10 #include <linux/module.h>
11 #include <linux/ctype.h>
15 #define TRACE_SYSTEM "TRACE_SYSTEM"
17 #define events_for_each(event) \
18 for (event = __start_ftrace_events; \
19 (unsigned long)event < (unsigned long)__stop_ftrace_events; \
22 void event_trace_printk(unsigned long ip
, const char *fmt
, ...)
27 tracing_record_cmdline(current
);
28 trace_vprintk(ip
, task_curr_ret_stack(current
), fmt
, ap
);
32 static void ftrace_clear_events(void)
34 struct ftrace_event_call
*call
= (void *)__start_ftrace_events
;
37 while ((unsigned long)call
< (unsigned long)__stop_ftrace_events
) {
47 static int ftrace_set_clr_event(char *buf
, int set
)
49 struct ftrace_event_call
*call
= __start_ftrace_events
;
50 char *event
= NULL
, *sub
= NULL
, *match
;
54 * The buf format can be <subsystem>:<event-name>
55 * *:<event-name> means any event by that name.
56 * :<event-name> is the same.
58 * <subsystem>:* means all events in that subsystem
59 * <subsystem>: means the same.
61 * <name> (no ':') means all events in a subsystem with
62 * the name <name> or any event that matches <name>
65 match
= strsep(&buf
, ":");
71 if (!strlen(sub
) || strcmp(sub
, "*") == 0)
73 if (!strlen(event
) || strcmp(event
, "*") == 0)
77 events_for_each(call
) {
83 strcmp(match
, call
->name
) != 0 &&
84 strcmp(match
, call
->system
) != 0)
87 if (sub
&& strcmp(sub
, call
->system
) != 0)
90 if (event
&& strcmp(event
, call
->name
) != 0)
100 /* Already cleared? */
111 /* 128 should be much more than enough */
112 #define EVENT_BUF_SIZE 127
115 ftrace_event_write(struct file
*file
, const char __user
*ubuf
,
116 size_t cnt
, loff_t
*ppos
)
127 ret
= get_user(ch
, ubuf
++);
133 /* skip white space */
134 while (cnt
&& isspace(ch
)) {
135 ret
= get_user(ch
, ubuf
++);
142 /* Only white space found? */
149 buf
= kmalloc(EVENT_BUF_SIZE
+1, GFP_KERNEL
);
153 if (cnt
> EVENT_BUF_SIZE
)
154 cnt
= EVENT_BUF_SIZE
;
157 while (cnt
&& !isspace(ch
)) {
163 ret
= get_user(ch
, ubuf
++);
173 ret
= ftrace_set_clr_event(buf
, set
);
186 t_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
188 struct ftrace_event_call
*call
= m
->private;
189 struct ftrace_event_call
*next
= call
;
193 if ((unsigned long)call
>= (unsigned long)__stop_ftrace_events
)
201 static void *t_start(struct seq_file
*m
, loff_t
*pos
)
203 return t_next(m
, NULL
, pos
);
207 s_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
209 struct ftrace_event_call
*call
= m
->private;
210 struct ftrace_event_call
*next
;
215 if ((unsigned long)call
>= (unsigned long)__stop_ftrace_events
)
218 if (!call
->enabled
) {
229 static void *s_start(struct seq_file
*m
, loff_t
*pos
)
231 return s_next(m
, NULL
, pos
);
234 static int t_show(struct seq_file
*m
, void *v
)
236 struct ftrace_event_call
*call
= v
;
238 if (strcmp(call
->system
, TRACE_SYSTEM
) != 0)
239 seq_printf(m
, "%s:", call
->system
);
240 seq_printf(m
, "%s\n", call
->name
);
245 static void t_stop(struct seq_file
*m
, void *p
)
250 ftrace_event_seq_open(struct inode
*inode
, struct file
*file
)
253 const struct seq_operations
*seq_ops
;
255 if ((file
->f_mode
& FMODE_WRITE
) &&
256 !(file
->f_flags
& O_APPEND
))
257 ftrace_clear_events();
259 seq_ops
= inode
->i_private
;
260 ret
= seq_open(file
, seq_ops
);
262 struct seq_file
*m
= file
->private_data
;
264 m
->private = __start_ftrace_events
;
270 event_enable_read(struct file
*filp
, char __user
*ubuf
, size_t cnt
,
273 struct ftrace_event_call
*call
= filp
->private_data
;
281 return simple_read_from_buffer(ubuf
, cnt
, ppos
, buf
, 2);
285 event_enable_write(struct file
*filp
, const char __user
*ubuf
, size_t cnt
,
288 struct ftrace_event_call
*call
= filp
->private_data
;
293 if (cnt
>= sizeof(buf
))
296 if (copy_from_user(&buf
, ubuf
, cnt
))
301 ret
= strict_strtoul(buf
, 10, &val
);
330 static const struct seq_operations show_event_seq_ops
= {
337 static const struct seq_operations show_set_event_seq_ops
= {
344 static const struct file_operations ftrace_avail_fops
= {
345 .open
= ftrace_event_seq_open
,
348 .release
= seq_release
,
351 static const struct file_operations ftrace_set_event_fops
= {
352 .open
= ftrace_event_seq_open
,
354 .write
= ftrace_event_write
,
356 .release
= seq_release
,
359 static const struct file_operations ftrace_enable_fops
= {
360 .open
= tracing_open_generic
,
361 .read
= event_enable_read
,
362 .write
= event_enable_write
,
365 static struct dentry
*event_trace_events_dir(void)
367 static struct dentry
*d_tracer
;
368 static struct dentry
*d_events
;
373 d_tracer
= tracing_init_dentry();
377 d_events
= debugfs_create_dir("events", d_tracer
);
379 pr_warning("Could not create debugfs "
380 "'events' directory\n");
385 struct event_subsystem
{
386 struct list_head list
;
388 struct dentry
*entry
;
391 static LIST_HEAD(event_subsystems
);
393 static struct dentry
*
394 event_subsystem_dir(const char *name
, struct dentry
*d_events
)
396 struct event_subsystem
*system
;
398 /* First see if we did not already create this dir */
399 list_for_each_entry(system
, &event_subsystems
, list
) {
400 if (strcmp(system
->name
, name
) == 0)
401 return system
->entry
;
404 /* need to create new entry */
405 system
= kmalloc(sizeof(*system
), GFP_KERNEL
);
407 pr_warning("No memory to create event subsystem %s\n",
412 system
->entry
= debugfs_create_dir(name
, d_events
);
413 if (!system
->entry
) {
414 pr_warning("Could not create event subsystem %s\n",
421 list_add(&system
->list
, &event_subsystems
);
423 return system
->entry
;
427 event_create_dir(struct ftrace_event_call
*call
, struct dentry
*d_events
)
429 struct dentry
*entry
;
432 * If the trace point header did not define TRACE_SYSTEM
433 * then the system would be called "TRACE_SYSTEM".
435 if (strcmp(call
->system
, "TRACE_SYSTEM") != 0)
436 d_events
= event_subsystem_dir(call
->system
, d_events
);
438 call
->dir
= debugfs_create_dir(call
->name
, d_events
);
440 pr_warning("Could not create debugfs "
441 "'%s' directory\n", call
->name
);
445 entry
= debugfs_create_file("enable", 0644, call
->dir
, call
,
446 &ftrace_enable_fops
);
448 pr_warning("Could not create debugfs "
449 "'%s/enable' entry\n", call
->name
);
454 static __init
int event_trace_init(void)
456 struct ftrace_event_call
*call
= __start_ftrace_events
;
457 struct dentry
*d_tracer
;
458 struct dentry
*entry
;
459 struct dentry
*d_events
;
461 d_tracer
= tracing_init_dentry();
465 entry
= debugfs_create_file("available_events", 0444, d_tracer
,
466 (void *)&show_event_seq_ops
,
469 pr_warning("Could not create debugfs "
470 "'available_events' entry\n");
472 entry
= debugfs_create_file("set_event", 0644, d_tracer
,
473 (void *)&show_set_event_seq_ops
,
474 &ftrace_set_event_fops
);
476 pr_warning("Could not create debugfs "
477 "'set_event' entry\n");
479 d_events
= event_trace_events_dir();
483 events_for_each(call
) {
484 /* The linker may leave blanks */
487 event_create_dir(call
, d_events
);
492 fs_initcall(event_trace_init
);