tracing: make the set_event and available_events subsystem aware
[cascardo/linux.git] / kernel / trace / trace_events.c
1 /*
2  * event tracer
3  *
4  * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
5  *
6  */
7
8 #include <linux/debugfs.h>
9 #include <linux/uaccess.h>
10 #include <linux/module.h>
11 #include <linux/ctype.h>
12
13 #include "trace_events.h"
14
15 #define TRACE_SYSTEM "TRACE_SYSTEM"
16
17 #define events_for_each(event)                                          \
18         for (event = __start_ftrace_events;                             \
19              (unsigned long)event < (unsigned long)__stop_ftrace_events; \
20              event++)
21
22 void event_trace_printk(unsigned long ip, const char *fmt, ...)
23 {
24         va_list ap;
25
26         va_start(ap, fmt);
27         tracing_record_cmdline(current);
28         trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
29         va_end(ap);
30 }
31
32 static void ftrace_clear_events(void)
33 {
34         struct ftrace_event_call *call = (void *)__start_ftrace_events;
35
36
37         while ((unsigned long)call < (unsigned long)__stop_ftrace_events) {
38
39                 if (call->enabled) {
40                         call->enabled = 0;
41                         call->unregfunc();
42                 }
43                 call++;
44         }
45 }
46
47 static int ftrace_set_clr_event(char *buf, int set)
48 {
49         struct ftrace_event_call *call = __start_ftrace_events;
50         char *event = NULL, *sub = NULL, *match;
51         int ret = -EINVAL;
52
53         /*
54          * The buf format can be <subsystem>:<event-name>
55          *  *:<event-name> means any event by that name.
56          *  :<event-name> is the same.
57          *
58          *  <subsystem>:* means all events in that subsystem
59          *  <subsystem>: means the same.
60          *
61          *  <name> (no ':') means all events in a subsystem with
62          *  the name <name> or any event that matches <name>
63          */
64
65         match = strsep(&buf, ":");
66         if (buf) {
67                 sub = match;
68                 event = buf;
69                 match = NULL;
70
71                 if (!strlen(sub) || strcmp(sub, "*") == 0)
72                         sub = NULL;
73                 if (!strlen(event) || strcmp(event, "*") == 0)
74                         event = NULL;
75         }
76
77         events_for_each(call) {
78
79                 if (!call->name)
80                         continue;
81
82                 if (match &&
83                     strcmp(match, call->name) != 0 &&
84                     strcmp(match, call->system) != 0)
85                         continue;
86
87                 if (sub && strcmp(sub, call->system) != 0)
88                         continue;
89
90                 if (event && strcmp(event, call->name) != 0)
91                         continue;
92
93                 if (set) {
94                         /* Already set? */
95                         if (call->enabled)
96                                 return 0;
97                         call->enabled = 1;
98                         call->regfunc();
99                 } else {
100                         /* Already cleared? */
101                         if (!call->enabled)
102                                 return 0;
103                         call->enabled = 0;
104                         call->unregfunc();
105                 }
106                 ret = 0;
107         }
108         return ret;
109 }
110
111 /* 128 should be much more than enough */
112 #define EVENT_BUF_SIZE          127
113
114 static ssize_t
115 ftrace_event_write(struct file *file, const char __user *ubuf,
116                    size_t cnt, loff_t *ppos)
117 {
118         size_t read = 0;
119         int i, set = 1;
120         ssize_t ret;
121         char *buf;
122         char ch;
123
124         if (!cnt || cnt < 0)
125                 return 0;
126
127         ret = get_user(ch, ubuf++);
128         if (ret)
129                 return ret;
130         read++;
131         cnt--;
132
133         /* skip white space */
134         while (cnt && isspace(ch)) {
135                 ret = get_user(ch, ubuf++);
136                 if (ret)
137                         return ret;
138                 read++;
139                 cnt--;
140         }
141
142         /* Only white space found? */
143         if (isspace(ch)) {
144                 file->f_pos += read;
145                 ret = read;
146                 return ret;
147         }
148
149         buf = kmalloc(EVENT_BUF_SIZE+1, GFP_KERNEL);
150         if (!buf)
151                 return -ENOMEM;
152
153         if (cnt > EVENT_BUF_SIZE)
154                 cnt = EVENT_BUF_SIZE;
155
156         i = 0;
157         while (cnt && !isspace(ch)) {
158                 if (!i && ch == '!')
159                         set = 0;
160                 else
161                         buf[i++] = ch;
162
163                 ret = get_user(ch, ubuf++);
164                 if (ret)
165                         goto out_free;
166                 read++;
167                 cnt--;
168         }
169         buf[i] = 0;
170
171         file->f_pos += read;
172
173         ret = ftrace_set_clr_event(buf, set);
174         if (ret)
175                 goto out_free;
176
177         ret = read;
178
179  out_free:
180         kfree(buf);
181
182         return ret;
183 }
184
185 static void *
186 t_next(struct seq_file *m, void *v, loff_t *pos)
187 {
188         struct ftrace_event_call *call = m->private;
189         struct ftrace_event_call *next = call;
190
191         (*pos)++;
192
193         if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
194                 return NULL;
195
196         m->private = ++next;
197
198         return call;
199 }
200
201 static void *t_start(struct seq_file *m, loff_t *pos)
202 {
203         return t_next(m, NULL, pos);
204 }
205
206 static void *
207 s_next(struct seq_file *m, void *v, loff_t *pos)
208 {
209         struct ftrace_event_call *call = m->private;
210         struct ftrace_event_call *next;
211
212         (*pos)++;
213
214  retry:
215         if ((unsigned long)call >= (unsigned long)__stop_ftrace_events)
216                 return NULL;
217
218         if (!call->enabled) {
219                 call++;
220                 goto retry;
221         }
222
223         next = call;
224         m->private = ++next;
225
226         return call;
227 }
228
229 static void *s_start(struct seq_file *m, loff_t *pos)
230 {
231         return s_next(m, NULL, pos);
232 }
233
234 static int t_show(struct seq_file *m, void *v)
235 {
236         struct ftrace_event_call *call = v;
237
238         if (strcmp(call->system, TRACE_SYSTEM) != 0)
239                 seq_printf(m, "%s:", call->system);
240         seq_printf(m, "%s\n", call->name);
241
242         return 0;
243 }
244
245 static void t_stop(struct seq_file *m, void *p)
246 {
247 }
248
249 static int
250 ftrace_event_seq_open(struct inode *inode, struct file *file)
251 {
252         int ret;
253         const struct seq_operations *seq_ops;
254
255         if ((file->f_mode & FMODE_WRITE) &&
256             !(file->f_flags & O_APPEND))
257                 ftrace_clear_events();
258
259         seq_ops = inode->i_private;
260         ret = seq_open(file, seq_ops);
261         if (!ret) {
262                 struct seq_file *m = file->private_data;
263
264                 m->private = __start_ftrace_events;
265         }
266         return ret;
267 }
268
269 static ssize_t
270 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
271                   loff_t *ppos)
272 {
273         struct ftrace_event_call *call = filp->private_data;
274         char *buf;
275
276         if (call->enabled)
277                 buf = "1\n";
278         else
279                 buf = "0\n";
280
281         return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
282 }
283
284 static ssize_t
285 event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
286                    loff_t *ppos)
287 {
288         struct ftrace_event_call *call = filp->private_data;
289         char buf[64];
290         unsigned long val;
291         int ret;
292
293         if (cnt >= sizeof(buf))
294                 return -EINVAL;
295
296         if (copy_from_user(&buf, ubuf, cnt))
297                 return -EFAULT;
298
299         buf[cnt] = 0;
300
301         ret = strict_strtoul(buf, 10, &val);
302         if (ret < 0)
303                 return ret;
304
305         switch (val) {
306         case 0:
307                 if (!call->enabled)
308                         break;
309
310                 call->enabled = 0;
311                 call->unregfunc();
312                 break;
313         case 1:
314                 if (call->enabled)
315                         break;
316
317                 call->enabled = 1;
318                 call->regfunc();
319                 break;
320
321         default:
322                 return -EINVAL;
323         }
324
325         *ppos += cnt;
326
327         return cnt;
328 }
329
330 static const struct seq_operations show_event_seq_ops = {
331         .start = t_start,
332         .next = t_next,
333         .show = t_show,
334         .stop = t_stop,
335 };
336
337 static const struct seq_operations show_set_event_seq_ops = {
338         .start = s_start,
339         .next = s_next,
340         .show = t_show,
341         .stop = t_stop,
342 };
343
344 static const struct file_operations ftrace_avail_fops = {
345         .open = ftrace_event_seq_open,
346         .read = seq_read,
347         .llseek = seq_lseek,
348         .release = seq_release,
349 };
350
351 static const struct file_operations ftrace_set_event_fops = {
352         .open = ftrace_event_seq_open,
353         .read = seq_read,
354         .write = ftrace_event_write,
355         .llseek = seq_lseek,
356         .release = seq_release,
357 };
358
359 static const struct file_operations ftrace_enable_fops = {
360         .open = tracing_open_generic,
361         .read = event_enable_read,
362         .write = event_enable_write,
363 };
364
365 static struct dentry *event_trace_events_dir(void)
366 {
367         static struct dentry *d_tracer;
368         static struct dentry *d_events;
369
370         if (d_events)
371                 return d_events;
372
373         d_tracer = tracing_init_dentry();
374         if (!d_tracer)
375                 return NULL;
376
377         d_events = debugfs_create_dir("events", d_tracer);
378         if (!d_events)
379                 pr_warning("Could not create debugfs "
380                            "'events' directory\n");
381
382         return d_events;
383 }
384
385 struct event_subsystem {
386         struct list_head        list;
387         const char              *name;
388         struct dentry           *entry;
389 };
390
391 static LIST_HEAD(event_subsystems);
392
393 static struct dentry *
394 event_subsystem_dir(const char *name, struct dentry *d_events)
395 {
396         struct event_subsystem *system;
397
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;
402         }
403
404         /* need to create new entry */
405         system = kmalloc(sizeof(*system), GFP_KERNEL);
406         if (!system) {
407                 pr_warning("No memory to create event subsystem %s\n",
408                            name);
409                 return d_events;
410         }
411
412         system->entry = debugfs_create_dir(name, d_events);
413         if (!system->entry) {
414                 pr_warning("Could not create event subsystem %s\n",
415                            name);
416                 kfree(system);
417                 return d_events;
418         }
419
420         system->name = name;
421         list_add(&system->list, &event_subsystems);
422
423         return system->entry;
424 }
425
426 static int
427 event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
428 {
429         struct dentry *entry;
430
431         /*
432          * If the trace point header did not define TRACE_SYSTEM
433          * then the system would be called "TRACE_SYSTEM".
434          */
435         if (strcmp(call->system, "TRACE_SYSTEM") != 0)
436                 d_events = event_subsystem_dir(call->system, d_events);
437
438         call->dir = debugfs_create_dir(call->name, d_events);
439         if (!call->dir) {
440                 pr_warning("Could not create debugfs "
441                            "'%s' directory\n", call->name);
442                 return -1;
443         }
444
445         entry = debugfs_create_file("enable", 0644, call->dir, call,
446                                     &ftrace_enable_fops);
447         if (!entry)
448                 pr_warning("Could not create debugfs "
449                            "'%s/enable' entry\n", call->name);
450
451         return 0;
452 }
453
454 static __init int event_trace_init(void)
455 {
456         struct ftrace_event_call *call = __start_ftrace_events;
457         struct dentry *d_tracer;
458         struct dentry *entry;
459         struct dentry *d_events;
460
461         d_tracer = tracing_init_dentry();
462         if (!d_tracer)
463                 return 0;
464
465         entry = debugfs_create_file("available_events", 0444, d_tracer,
466                                     (void *)&show_event_seq_ops,
467                                     &ftrace_avail_fops);
468         if (!entry)
469                 pr_warning("Could not create debugfs "
470                            "'available_events' entry\n");
471
472         entry = debugfs_create_file("set_event", 0644, d_tracer,
473                                     (void *)&show_set_event_seq_ops,
474                                     &ftrace_set_event_fops);
475         if (!entry)
476                 pr_warning("Could not create debugfs "
477                            "'set_event' entry\n");
478
479         d_events = event_trace_events_dir();
480         if (!d_events)
481                 return 0;
482
483         events_for_each(call) {
484                 /* The linker may leave blanks */
485                 if (!call->name)
486                         continue;
487                 event_create_dir(call, d_events);
488         }
489
490         return 0;
491 }
492 fs_initcall(event_trace_init);