ABI runtime fixes
[lttng-modules.git] / ltt-trace-control.c
CommitLineData
1c8284eb
MD
1/*
2 * LTT trace control module over debugfs.
3 *
4 * Copyright 2008 - Zhaolei <zhaolei@cn.fujitsu.com>
5 *
6 * Copyright 2009 - Gui Jianfeng <guijianfeng@cn.fujitsu.com>
7 * Make mark-control work in debugfs
8 *
9 * Dual LGPL v2.1/GPL v2 license.
10 */
11
12/*
13 * Todo:
14 * Impl read operations for control file to read attributes
15 * Create a README file in ltt control dir, for display help info
16 */
17
18#include <linux/module.h>
19#include <linux/fs.h>
20#include <linux/uaccess.h>
21#include <linux/debugfs.h>
22#include <linux/notifier.h>
23#include <linux/jiffies.h>
24#include <linux/marker.h>
25
26#include "ltt-tracer.h"
27
28#define LTT_CONTROL_DIR "control"
29#define MARKERS_CONTROL_DIR "markers"
30#define LTT_SETUP_TRACE_FILE "setup_trace"
31#define LTT_DESTROY_TRACE_FILE "destroy_trace"
32
33#define LTT_WRITE_MAXLEN (128)
34
35struct dentry *ltt_control_dir, *ltt_setup_trace_file, *ltt_destroy_trace_file,
36 *markers_control_dir;
37
38/*
39 * the traces_lock nests inside control_lock.
40 * control_lock protects the consistency of directories presented in ltt
41 * directory.
42 */
43static DEFINE_MUTEX(control_lock);
44
45/*
46 * big note about locking for marker control files :
47 * If a marker control file is added/removed manually racing with module
48 * load/unload, there may be warning messages appearing, but those two
49 * operations should be able to execute concurrently without any lock
50 * synchronizing their operation one wrt another.
51 * Locking the marker mutex, module mutex and also keeping a mutex here
52 * from mkdir/rmdir _and_ from the notifier called from module load/unload makes
53 * life miserable and just asks for deadlocks.
54 */
55
56/*
57 * lookup a file/dir in parent dir.
58 * only designed to work well for debugfs.
59 * (although it maybe ok for other fs)
60 *
61 * return:
62 * file/dir's dentry on success
63 * NULL on failure
64 */
65static struct dentry *dir_lookup(struct dentry *parent, const char *name)
66{
67 struct qstr q;
68 struct dentry *d;
69
70 q.name = name;
71 q.len = strlen(name);
72 q.hash = full_name_hash(q.name, q.len);
73
74 d = d_lookup(parent, &q);
75 if (d)
76 dput(d);
77
78 return d;
79}
80
81
82static ssize_t alloc_write(struct file *file, const char __user *user_buf,
83 size_t count, loff_t *ppos)
84{
85 int err = 0;
86 int buf_size;
87 char *buf = (char *)__get_free_page(GFP_KERNEL);
88 char *cmd = (char *)__get_free_page(GFP_KERNEL);
89
90 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
91 err = copy_from_user(buf, user_buf, buf_size);
92 if (err)
93 goto err_copy_from_user;
94 buf[buf_size] = 0;
95
96 if (sscanf(buf, "%s", cmd) != 1) {
97 err = -EPERM;
98 goto err_get_cmd;
99 }
100
101 if ((cmd[0] != 'Y' && cmd[0] != 'y' && cmd[0] != '1') || cmd[1]) {
102 err = -EPERM;
103 goto err_bad_cmd;
104 }
105
106 err = ltt_trace_alloc(file->f_dentry->d_parent->d_name.name);
107 if (IS_ERR_VALUE(err)) {
108 printk(KERN_ERR "alloc_write: ltt_trace_alloc failed: %d\n",
109 err);
110 goto err_alloc_trace;
111 }
112
113 free_page((unsigned long)buf);
114 free_page((unsigned long)cmd);
115 return count;
116
117err_alloc_trace:
118err_bad_cmd:
119err_get_cmd:
120err_copy_from_user:
121 free_page((unsigned long)buf);
122 free_page((unsigned long)cmd);
123 return err;
124}
125
126static const struct file_operations ltt_alloc_operations = {
127 .write = alloc_write,
128};
129
130
131static ssize_t enabled_write(struct file *file, const char __user *user_buf,
132 size_t count, loff_t *ppos)
133{
134 int err = 0;
135 int buf_size;
136 char *buf = (char *)__get_free_page(GFP_KERNEL);
137 char *cmd = (char *)__get_free_page(GFP_KERNEL);
138
139 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
140 err = copy_from_user(buf, user_buf, buf_size);
141 if (err)
142 goto err_copy_from_user;
143 buf[buf_size] = 0;
144
145 if (sscanf(buf, "%s", cmd) != 1) {
146 err = -EPERM;
147 goto err_get_cmd;
148 }
149
150 if (cmd[1]) {
151 err = -EPERM;
152 goto err_bad_cmd;
153 }
154
155 switch (cmd[0]) {
156 case 'Y':
157 case 'y':
158 case '1':
159 err = ltt_trace_start(file->f_dentry->d_parent->d_name.name);
160 if (IS_ERR_VALUE(err)) {
161 printk(KERN_ERR
162 "enabled_write: ltt_trace_start failed: %d\n",
163 err);
164 err = -EPERM;
165 goto err_start_trace;
166 }
167 break;
168 case 'N':
169 case 'n':
170 case '0':
171 err = ltt_trace_stop(file->f_dentry->d_parent->d_name.name);
172 if (IS_ERR_VALUE(err)) {
173 printk(KERN_ERR
174 "enabled_write: ltt_trace_stop failed: %d\n",
175 err);
176 err = -EPERM;
177 goto err_stop_trace;
178 }
179 break;
180 default:
181 err = -EPERM;
182 goto err_bad_cmd;
183 }
184
185 free_page((unsigned long)buf);
186 free_page((unsigned long)cmd);
187 return count;
188
189err_stop_trace:
190err_start_trace:
191err_bad_cmd:
192err_get_cmd:
193err_copy_from_user:
194 free_page((unsigned long)buf);
195 free_page((unsigned long)cmd);
196 return err;
197}
198
199static const struct file_operations ltt_enabled_operations = {
200 .write = enabled_write,
201};
202
203
204static ssize_t trans_write(struct file *file, const char __user *user_buf,
205 size_t count, loff_t *ppos)
206{
207 char *buf = (char *)__get_free_page(GFP_KERNEL);
208 char *trans_name = (char *)__get_free_page(GFP_KERNEL);
209 int err = 0;
210 int buf_size;
211
212 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
213 err = copy_from_user(buf, user_buf, buf_size);
214 if (err)
215 goto err_copy_from_user;
216 buf[buf_size] = 0;
217
218 if (sscanf(buf, "%s", trans_name) != 1) {
219 err = -EPERM;
220 goto err_get_transname;
221 }
222
223 err = ltt_trace_set_type(file->f_dentry->d_parent->d_name.name,
224 trans_name);
225 if (IS_ERR_VALUE(err)) {
226 printk(KERN_ERR "trans_write: ltt_trace_set_type failed: %d\n",
227 err);
228 goto err_set_trans;
229 }
230
231 free_page((unsigned long)buf);
232 free_page((unsigned long)trans_name);
233 return count;
234
235err_set_trans:
236err_get_transname:
237err_copy_from_user:
238 free_page((unsigned long)buf);
239 free_page((unsigned long)trans_name);
240 return err;
241}
242
243static const struct file_operations ltt_trans_operations = {
244 .write = trans_write,
245};
246
247
248static ssize_t channel_subbuf_num_write(struct file *file,
249 const char __user *user_buf, size_t count, loff_t *ppos)
250{
251 int err = 0;
252 int buf_size;
253 unsigned int num;
254 const char *channel_name;
255 const char *trace_name;
256 char *buf = (char *)__get_free_page(GFP_KERNEL);
257
258 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
259 err = copy_from_user(buf, user_buf, buf_size);
260 if (err)
261 goto err_copy_from_user;
262 buf[buf_size] = 0;
263
264 if (sscanf(buf, "%u", &num) != 1) {
265 err = -EPERM;
266 goto err_get_number;
267 }
268
269 channel_name = file->f_dentry->d_parent->d_name.name;
270 trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
271
272 err = ltt_trace_set_channel_subbufcount(trace_name, channel_name, num);
273 if (IS_ERR_VALUE(err)) {
274 printk(KERN_ERR "channel_subbuf_num_write: "
275 "ltt_trace_set_channel_subbufcount failed: %d\n", err);
276 goto err_set_subbufcount;
277 }
278
279 free_page((unsigned long)buf);
280 return count;
281
282err_set_subbufcount:
283err_get_number:
284err_copy_from_user:
285 free_page((unsigned long)buf);
286 return err;
287}
288
289static const struct file_operations ltt_channel_subbuf_num_operations = {
290 .write = channel_subbuf_num_write,
291};
292
293
294static
295ssize_t channel_subbuf_size_write(struct file *file,
296 const char __user *user_buf,
297 size_t count, loff_t *ppos)
298{
299 int err = 0;
300 int buf_size;
301 unsigned int num;
302 const char *channel_name;
303 const char *trace_name;
304 char *buf = (char *)__get_free_page(GFP_KERNEL);
305
306 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
307 err = copy_from_user(buf, user_buf, buf_size);
308 if (err)
309 goto err_copy_from_user;
310 buf[buf_size] = 0;
311
312 if (sscanf(buf, "%u", &num) != 1) {
313 err = -EPERM;
314 goto err_get_number;
315 }
316
317 channel_name = file->f_dentry->d_parent->d_name.name;
318 trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
319
320 err = ltt_trace_set_channel_subbufsize(trace_name, channel_name, num);
321 if (IS_ERR_VALUE(err)) {
322 printk(KERN_ERR "channel_subbuf_size_write: "
323 "ltt_trace_set_channel_subbufsize failed: %d\n", err);
324 goto err_set_subbufsize;
325 }
326
327 free_page((unsigned long)buf);
328 return count;
329
330err_set_subbufsize:
331err_get_number:
332err_copy_from_user:
333 free_page((unsigned long)buf);
334 return err;
335}
336
337static const struct file_operations ltt_channel_subbuf_size_operations = {
338 .write = channel_subbuf_size_write,
339};
340
341static
342ssize_t channel_switch_timer_write(struct file *file,
343 const char __user *user_buf,
344 size_t count, loff_t *ppos)
345{
346 int err = 0;
347 int buf_size;
348 unsigned long num;
349 const char *channel_name;
350 const char *trace_name;
351 char *buf = (char *)__get_free_page(GFP_KERNEL);
352
353 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
354 err = copy_from_user(buf, user_buf, buf_size);
355 if (err)
356 goto err_copy_from_user;
357 buf[buf_size] = 0;
358
359 if (sscanf(buf, "%lu", &num) != 1) {
360 err = -EPERM;
361 goto err_get_number;
362 }
363
364 channel_name = file->f_dentry->d_parent->d_name.name;
365 trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
366
7514523f
MD
367 /* Convert from ms to us */
368 num *= 1000;
1c8284eb
MD
369
370 err = ltt_trace_set_channel_switch_timer(trace_name, channel_name, num);
371 if (IS_ERR_VALUE(err)) {
372 printk(KERN_ERR "channel_switch_timer_write: "
373 "ltt_trace_set_channel_switch_timer failed: %d\n", err);
374 goto err_set_switch_timer;
375 }
376
377 free_page((unsigned long)buf);
378 return count;
379
380err_set_switch_timer:
381err_get_number:
382err_copy_from_user:
383 free_page((unsigned long)buf);
384 return err;
385}
386
387static struct file_operations ltt_channel_switch_timer_operations = {
388 .write = channel_switch_timer_write,
389};
390
391static
392ssize_t channel_overwrite_write(struct file *file,
393 const char __user *user_buf, size_t count,
394 loff_t *ppos)
395{
396 int err = 0;
397 int buf_size;
398 const char *channel_name;
399 const char *trace_name;
400 char *buf = (char *)__get_free_page(GFP_KERNEL);
401 char *cmd = (char *)__get_free_page(GFP_KERNEL);
402
403 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
404 err = copy_from_user(buf, user_buf, buf_size);
405 if (err)
406 goto err_copy_from_user;
407 buf[buf_size] = 0;
408
409 if (sscanf(buf, "%s", cmd) != 1) {
410 err = -EPERM;
411 goto err_get_cmd;
412 }
413
414 if (cmd[1]) {
415 err = -EPERM;
416 goto err_bad_cmd;
417 }
418
419 channel_name = file->f_dentry->d_parent->d_name.name;
420 trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
421
422 switch (cmd[0]) {
423 case 'Y':
424 case 'y':
425 case '1':
426 err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
427 1);
428 if (IS_ERR_VALUE(err)) {
429 printk(KERN_ERR "channel_overwrite_write: "
430 "ltt_trace_set_channel_overwrite failed: %d\n",
431 err);
432 goto err_set_subbufsize;
433 }
434 break;
435 case 'N':
436 case 'n':
437 case '0':
438 err = ltt_trace_set_channel_overwrite(trace_name, channel_name,
439 0);
440 if (IS_ERR_VALUE(err)) {
441 printk(KERN_ERR "channel_overwrite_write: "
442 "ltt_trace_set_channel_overwrite failed: %d\n",
443 err);
444 goto err_set_subbufsize;
445 }
446 break;
447 default:
448 err = -EPERM;
449 goto err_bad_cmd;
450 }
451
452 free_page((unsigned long)buf);
453 free_page((unsigned long)cmd);
454 return count;
455
456err_set_subbufsize:
457err_bad_cmd:
458err_get_cmd:
459err_copy_from_user:
460 free_page((unsigned long)buf);
461 free_page((unsigned long)cmd);
462 return err;
463}
464
465static const struct file_operations ltt_channel_overwrite_operations = {
466 .write = channel_overwrite_write,
467};
468
469
470static
471ssize_t channel_enable_write(struct file *file,
472 const char __user *user_buf, size_t count,
473 loff_t *ppos)
474{
475 int err = 0;
476 int buf_size;
477 const char *channel_name;
478 const char *trace_name;
479 char *buf = (char *)__get_free_page(GFP_KERNEL);
480 char *cmd = (char *)__get_free_page(GFP_KERNEL);
481
482 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
483 err = copy_from_user(buf, user_buf, buf_size);
484 if (err)
485 goto err_copy_from_user;
486 buf[buf_size] = 0;
487
488 if (sscanf(buf, "%s", cmd) != 1) {
489 err = -EPERM;
490 goto err_get_cmd;
491 }
492
493 if (cmd[1]) {
494 err = -EPERM;
495 goto err_bad_cmd;
496 }
497
498 channel_name = file->f_dentry->d_parent->d_name.name;
499 trace_name = file->f_dentry->d_parent->d_parent->d_parent->d_name.name;
500
501 switch (cmd[0]) {
502 case 'Y':
503 case 'y':
504 case '1':
505 err = ltt_trace_set_channel_enable(trace_name, channel_name,
506 1);
507 if (IS_ERR_VALUE(err)) {
508 printk(KERN_ERR "channel_enable_write: "
509 "ltt_trace_set_channel_enable failed: %d\n",
510 err);
511 goto err_set_subbufsize;
512 }
513 break;
514 case 'N':
515 case 'n':
516 case '0':
517 err = ltt_trace_set_channel_enable(trace_name, channel_name,
518 0);
519 if (IS_ERR_VALUE(err)) {
520 printk(KERN_ERR "channel_enable_write: "
521 "ltt_trace_set_channel_enable failed: %d\n",
522 err);
523 goto err_set_subbufsize;
524 }
525 break;
526 default:
527 err = -EPERM;
528 goto err_bad_cmd;
529 }
530
531 free_page((unsigned long)buf);
532 free_page((unsigned long)cmd);
533 return count;
534
535err_set_subbufsize:
536err_bad_cmd:
537err_get_cmd:
538err_copy_from_user:
539 free_page((unsigned long)buf);
540 free_page((unsigned long)cmd);
541 return err;
542}
543
544static const struct file_operations ltt_channel_enable_operations = {
545 .write = channel_enable_write,
546};
547
548
549static int _create_trace_control_dir(const char *trace_name,
550 struct ltt_trace *trace)
551{
552 int err;
553 struct dentry *trace_root, *channel_root;
554 struct dentry *tmp_den;
555 int i;
556
557 /* debugfs/control/trace_name */
558 trace_root = debugfs_create_dir(trace_name, ltt_control_dir);
559 if (IS_ERR(trace_root) || !trace_root) {
560 printk(KERN_ERR "_create_trace_control_dir: "
561 "create control root dir of %s failed\n", trace_name);
562 err = -ENOMEM;
563 goto err_create_trace_root;
564 }
565
566 /* debugfs/control/trace_name/alloc */
567 tmp_den = debugfs_create_file("alloc", S_IWUSR, trace_root, NULL,
568 &ltt_alloc_operations);
569 if (IS_ERR(tmp_den) || !tmp_den) {
570 printk(KERN_ERR "_create_trace_control_dir: "
571 "create file of alloc failed\n");
572 err = -ENOMEM;
573 goto err_create_subdir;
574 }
575
576 /* debugfs/control/trace_name/trans */
577 tmp_den = debugfs_create_file("trans", S_IWUSR, trace_root, NULL,
578 &ltt_trans_operations);
579 if (IS_ERR(tmp_den) || !tmp_den) {
580 printk(KERN_ERR "_create_trace_control_dir: "
581 "create file of trans failed\n");
582 err = -ENOMEM;
583 goto err_create_subdir;
584 }
585
586 /* debugfs/control/trace_name/enabled */
587 tmp_den = debugfs_create_file("enabled", S_IWUSR, trace_root, NULL,
588 &ltt_enabled_operations);
589 if (IS_ERR(tmp_den) || !tmp_den) {
590 printk(KERN_ERR "_create_trace_control_dir: "
591 "create file of enabled failed\n");
592 err = -ENOMEM;
593 goto err_create_subdir;
594 }
595
596 /* debugfs/control/trace_name/channel/ */
597 channel_root = debugfs_create_dir("channel", trace_root);
598 if (IS_ERR(channel_root) || !channel_root) {
599 printk(KERN_ERR "_create_trace_control_dir: "
600 "create dir of channel failed\n");
601 err = -ENOMEM;
602 goto err_create_subdir;
603 }
604
605 /*
606 * Create dir and files in debugfs/ltt/control/trace_name/channel/
607 * Following things(without <>) will be created:
608 * `-- <control>
609 * `-- <trace_name>
610 * `-- <channel>
611 * |-- <channel_name>
612 * | |-- enable
613 * | |-- overwrite
614 * | |-- subbuf_num
615 * | |-- subbuf_size
616 * | `-- switch_timer
617 * `-- ...
618 */
619
620 for (i = 0; i < trace->nr_channels; i++) {
621 struct dentry *channel_den;
622 struct ltt_chan *chan;
623
624 chan = &trace->channels[i];
625 if (!chan->active)
626 continue;
627 channel_den = debugfs_create_dir(chan->a.filename,
628 channel_root);
629 if (IS_ERR(channel_den) || !channel_den) {
630 printk(KERN_ERR "_create_trace_control_dir: "
631 "create channel dir of %s failed\n",
632 chan->a.filename);
633 err = -ENOMEM;
634 goto err_create_subdir;
635 }
636
637 tmp_den = debugfs_create_file("subbuf_num", S_IWUSR,
638 channel_den, NULL,
639 &ltt_channel_subbuf_num_operations);
640 if (IS_ERR(tmp_den) || !tmp_den) {
641 printk(KERN_ERR "_create_trace_control_dir: "
642 "create subbuf_num in %s failed\n",
643 chan->a.filename);
644 err = -ENOMEM;
645 goto err_create_subdir;
646 }
647
648 tmp_den = debugfs_create_file("subbuf_size", S_IWUSR,
649 channel_den, NULL,
650 &ltt_channel_subbuf_size_operations);
651 if (IS_ERR(tmp_den) || !tmp_den) {
652 printk(KERN_ERR "_create_trace_control_dir: "
653 "create subbuf_size in %s failed\n",
654 chan->a.filename);
655 err = -ENOMEM;
656 goto err_create_subdir;
657 }
658
659 tmp_den = debugfs_create_file("enable", S_IWUSR, channel_den,
660 NULL,
661 &ltt_channel_enable_operations);
662 if (IS_ERR(tmp_den) || !tmp_den) {
663 printk(KERN_ERR "_create_trace_control_dir: "
664 "create enable in %s failed\n",
665 chan->a.filename);
666 err = -ENOMEM;
667 goto err_create_subdir;
668 }
669
670 tmp_den = debugfs_create_file("overwrite", S_IWUSR, channel_den,
671 NULL,
672 &ltt_channel_overwrite_operations);
673 if (IS_ERR(tmp_den) || !tmp_den) {
674 printk(KERN_ERR "_create_trace_control_dir: "
675 "create overwrite in %s failed\n",
676 chan->a.filename);
677 err = -ENOMEM;
678 goto err_create_subdir;
679 }
680
681 tmp_den = debugfs_create_file("switch_timer", S_IWUSR,
682 channel_den, NULL,
683 &ltt_channel_switch_timer_operations);
684 if (IS_ERR(tmp_den) || !tmp_den) {
685 printk(KERN_ERR "_create_trace_control_dir: "
686 "create switch_timer in %s failed\n",
687 chan->a.filename);
688 err = -ENOMEM;
689 goto err_create_subdir;
690 }
691 }
692
693 return 0;
694
695err_create_subdir:
696 debugfs_remove_recursive(trace_root);
697err_create_trace_root:
698 return err;
699}
700
701static
702ssize_t setup_trace_write(struct file *file, const char __user *user_buf,
703 size_t count, loff_t *ppos)
704{
705 int err = 0;
706 int buf_size;
707 struct ltt_trace *trace;
708 char *buf = (char *)__get_free_page(GFP_KERNEL);
709 char *trace_name = (char *)__get_free_page(GFP_KERNEL);
710
711 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
712 err = copy_from_user(buf, user_buf, buf_size);
713 if (err)
714 goto err_copy_from_user;
715 buf[buf_size] = 0;
716
717 if (sscanf(buf, "%s", trace_name) != 1) {
718 err = -EPERM;
719 goto err_get_tracename;
720 }
721
722 mutex_lock(&control_lock);
723 ltt_lock_traces();
724
725 err = _ltt_trace_setup(trace_name);
726 if (IS_ERR_VALUE(err)) {
727 printk(KERN_ERR
728 "setup_trace_write: ltt_trace_setup failed: %d\n", err);
729 goto err_setup_trace;
730 }
731 trace = _ltt_trace_find_setup(trace_name);
732 BUG_ON(!trace);
733 err = _create_trace_control_dir(trace_name, trace);
734 if (IS_ERR_VALUE(err)) {
735 printk(KERN_ERR "setup_trace_write: "
736 "_create_trace_control_dir failed: %d\n", err);
737 goto err_create_trace_control_dir;
738 }
739
740 ltt_unlock_traces();
741 mutex_unlock(&control_lock);
742
743 free_page((unsigned long)buf);
744 free_page((unsigned long)trace_name);
745 return count;
746
747err_create_trace_control_dir:
748 ltt_trace_destroy(trace_name);
749err_setup_trace:
750 ltt_unlock_traces();
751 mutex_unlock(&control_lock);
752err_get_tracename:
753err_copy_from_user:
754 free_page((unsigned long)buf);
755 free_page((unsigned long)trace_name);
756 return err;
757}
758
759static const struct file_operations ltt_setup_trace_operations = {
760 .write = setup_trace_write,
761};
762
763static
764ssize_t destroy_trace_write(struct file *file, const char __user *user_buf,
765 size_t count, loff_t *ppos)
766{
767 struct dentry *trace_den;
768 int buf_size;
769 int err = 0;
770 char *buf = (char *)__get_free_page(GFP_KERNEL);
771 char *trace_name = (char *)__get_free_page(GFP_KERNEL);
772
773 buf_size = min_t(size_t, count, PAGE_SIZE - 1);
774 err = copy_from_user(buf, user_buf, buf_size);
775 if (err)
776 goto err_copy_from_user;
777 buf[buf_size] = 0;
778
779 if (sscanf(buf, "%s", trace_name) != 1) {
780 err = -EPERM;
781 goto err_get_tracename;
782 }
783
784 mutex_lock(&control_lock);
785
786 err = ltt_trace_destroy(trace_name);
787 if (IS_ERR_VALUE(err)) {
788 printk(KERN_ERR
789 "destroy_trace_write: ltt_trace_destroy failed: %d\n",
790 err);
791 err = -EPERM;
792 goto err_destroy_trace;
793 }
794
795 trace_den = dir_lookup(ltt_control_dir, trace_name);
796 if (!trace_den) {
797 printk(KERN_ERR
798 "destroy_trace_write: lookup for %s's dentry failed\n",
799 trace_name);
800 err = -ENOENT;
801 goto err_get_dentry;
802 }
803
804 debugfs_remove_recursive(trace_den);
805
806 mutex_unlock(&control_lock);
807
808 free_page((unsigned long)buf);
809 free_page((unsigned long)trace_name);
810 return count;
811
812err_get_dentry:
813err_destroy_trace:
814 mutex_unlock(&control_lock);
815err_get_tracename:
816err_copy_from_user:
817 free_page((unsigned long)buf);
818 free_page((unsigned long)trace_name);
819 return err;
820}
821
822static const struct file_operations ltt_destroy_trace_operations = {
823 .write = destroy_trace_write,
824};
825
826static void init_marker_dir(struct dentry *dentry,
827 const struct inode_operations *opt)
828{
829 dentry->d_inode->i_op = opt;
830}
831
832static
833ssize_t marker_enable_read(struct file *filp, char __user *ubuf,
834 size_t cnt, loff_t *ppos)
835{
836 char *buf;
837 const char *channel, *marker;
838 int len, enabled, present;
839
840 marker = filp->f_dentry->d_parent->d_name.name;
841 channel = filp->f_dentry->d_parent->d_parent->d_name.name;
842
843 len = 0;
844 buf = (char *)__get_free_page(GFP_KERNEL);
845
846 /*
847 * Note: we cannot take the marker lock to make these two checks
848 * atomic, because the marker mutex nests inside the module mutex, taken
849 * inside the marker present check.
850 */
851 enabled = is_marker_enabled(channel, marker);
852 present = is_marker_present(channel, marker);
853
854 if (enabled && present)
855 len = snprintf(buf, PAGE_SIZE, "%d\n", 1);
856 else if (enabled && !present)
857 len = snprintf(buf, PAGE_SIZE, "%d\n", 2);
858 else
859 len = snprintf(buf, PAGE_SIZE, "%d\n", 0);
860
861
862 if (len >= PAGE_SIZE) {
863 len = PAGE_SIZE;
864 buf[PAGE_SIZE] = '\0';
865 }
866 len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
867 free_page((unsigned long)buf);
868
869 return len;
870}
871
872static
873ssize_t marker_enable_write(struct file *filp, const char __user *ubuf,
874 size_t cnt, loff_t *ppos)
875{
876 char *buf = (char *)__get_free_page(GFP_KERNEL);
877 int buf_size;
878 ssize_t ret = 0;
879 const char *channel, *marker;
880
881 marker = filp->f_dentry->d_parent->d_name.name;
882 channel = filp->f_dentry->d_parent->d_parent->d_name.name;
883
884 buf_size = min_t(size_t, cnt, PAGE_SIZE - 1);
885 ret = copy_from_user(buf, ubuf, buf_size);
886 if (ret)
887 goto end;
888
889 buf[buf_size] = 0;
890
891 switch (buf[0]) {
892 case 'Y':
893 case 'y':
894 case '1':
895 ret = ltt_marker_connect(channel, marker, "default");
896 if (ret)
897 goto end;
898 break;
899 case 'N':
900 case 'n':
901 case '0':
902 ret = ltt_marker_disconnect(channel, marker, "default");
903 if (ret)
904 goto end;
905 break;
906 default:
907 ret = -EPERM;
908 goto end;
909 }
910 ret = cnt;
911end:
912 free_page((unsigned long)buf);
913 return ret;
914}
915
916static const struct file_operations enable_fops = {
917 .read = marker_enable_read,
918 .write = marker_enable_write,
919};
920
921/*
922 * In practice, the output size should never be larger than 4096 kB. If it
923 * ever happens, the output will simply be truncated.
924 */
925static
926ssize_t marker_info_read(struct file *filp, char __user *ubuf,
927 size_t cnt, loff_t *ppos)
928{
929 char *buf;
930 const char *channel, *marker;
931 int len;
932 struct marker_iter iter;
933
934 marker = filp->f_dentry->d_parent->d_name.name;
935 channel = filp->f_dentry->d_parent->d_parent->d_name.name;
936
937 len = 0;
938 buf = (char *)__get_free_page(GFP_KERNEL);
939
940 if (is_marker_enabled(channel, marker) &&
941 !is_marker_present(channel, marker)) {
942 len += snprintf(buf + len, PAGE_SIZE - len,
943 "Marker Pre-enabled\n");
944 goto out;
945 }
946
947 marker_iter_reset(&iter);
948 marker_iter_start(&iter);
949 for (; iter.marker != NULL; marker_iter_next(&iter)) {
950 if (!strcmp(iter.marker->channel, channel) &&
951 !strcmp(iter.marker->name, marker))
952 len += snprintf(buf + len, PAGE_SIZE - len,
953 "Location: %s\n"
954 "format: \"%s\"\nstate: %d\n"
955 "event_id: %hu\n"
956 "call: 0x%p\n"
957 "probe %s : 0x%p\n\n",
958#ifdef CONFIG_MODULES
959 iter.module ? iter.module->name :
960#endif
961 "Core Kernel",
962 iter.marker->format,
963 _imv_read(iter.marker->state),
964 iter.marker->event_id,
965 iter.marker->call,
966 iter.marker->ptype ?
967 "multi" : "single", iter.marker->ptype ?
968 (void *)iter.marker->multi :
969 (void *)iter.marker->single.func);
970 if (len >= PAGE_SIZE)
971 break;
972 }
973 marker_iter_stop(&iter);
974
975out:
976 if (len >= PAGE_SIZE) {
977 len = PAGE_SIZE;
978 buf[PAGE_SIZE] = '\0';
979 }
980
981 len = simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
982 free_page((unsigned long)buf);
983
984 return len;
985}
986
987static const struct file_operations info_fops = {
988 .read = marker_info_read,
989};
990
991static int marker_mkdir(struct inode *dir, struct dentry *dentry, int mode)
992{
993 struct dentry *marker_d, *enable_d, *info_d, *channel_d;
994 int ret;
995
996 ret = 0;
997 channel_d = (struct dentry *)dir->i_private;
998 mutex_unlock(&dir->i_mutex);
999
1000 marker_d = debugfs_create_dir(dentry->d_name.name,
1001 channel_d);
1002 if (IS_ERR(marker_d)) {
1003 ret = PTR_ERR(marker_d);
1004 goto out;
1005 }
1006
1007 enable_d = debugfs_create_file("enable", 0644, marker_d,
1008 NULL, &enable_fops);
1009 if (IS_ERR(enable_d) || !enable_d) {
1010 printk(KERN_ERR
1011 "%s: create file of %s failed\n",
1012 __func__, "enable");
1013 ret = -ENOMEM;
1014 goto remove_marker_dir;
1015 }
1016
1017 info_d = debugfs_create_file("info", 0644, marker_d,
1018 NULL, &info_fops);
1019 if (IS_ERR(info_d) || !info_d) {
1020 printk(KERN_ERR
1021 "%s: create file of %s failed\n",
1022 __func__, "info");
1023 ret = -ENOMEM;
1024 goto remove_enable_dir;
1025 }
1026
1027 goto out;
1028
1029remove_enable_dir:
1030 debugfs_remove(enable_d);
1031remove_marker_dir:
1032 debugfs_remove(marker_d);
1033out:
1034 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
1035 return ret;
1036}
1037
1038static int marker_rmdir(struct inode *dir, struct dentry *dentry)
1039{
1040 struct dentry *marker_d, *channel_d;
1041 const char *channel, *name;
1042 int ret, enabled, present;
1043
1044 ret = 0;
1045
1046 channel_d = (struct dentry *)dir->i_private;
1047 channel = channel_d->d_name.name;
1048
1049 marker_d = dir_lookup(channel_d, dentry->d_name.name);
1050
1051 if (!marker_d) {
1052 ret = -ENOENT;
1053 goto out;
1054 }
1055
1056 name = marker_d->d_name.name;
1057
1058 enabled = is_marker_enabled(channel, name);
1059 present = is_marker_present(channel, name);
1060
1061 if (present || (!present && enabled)) {
1062 ret = -EPERM;
1063 goto out;
1064 }
1065
1066 mutex_unlock(&dir->i_mutex);
1067 mutex_unlock(&dentry->d_inode->i_mutex);
1068 debugfs_remove_recursive(marker_d);
1069 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
1070 mutex_lock(&dentry->d_inode->i_mutex);
1071out:
1072 return ret;
1073}
1074
1075const struct inode_operations channel_dir_opt = {
1076 .lookup = simple_lookup,
1077 .mkdir = marker_mkdir,
1078 .rmdir = marker_rmdir,
1079};
1080
1081static int channel_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1082{
1083 struct dentry *channel_d;
1084 int ret;
1085
1086 ret = 0;
1087 mutex_unlock(&dir->i_mutex);
1088
1089 channel_d = debugfs_create_dir(dentry->d_name.name,
1090 markers_control_dir);
1091 if (IS_ERR(channel_d)) {
1092 ret = PTR_ERR(channel_d);
1093 goto out;
1094 }
1095
1096 channel_d->d_inode->i_private = (void *)channel_d;
1097 init_marker_dir(channel_d, &channel_dir_opt);
1098out:
1099 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
1100 return ret;
1101}
1102
1103static int channel_rmdir(struct inode *dir, struct dentry *dentry)
1104{
1105 struct dentry *channel_d;
1106 int ret;
1107
1108 ret = 0;
1109
1110 channel_d = dir_lookup(markers_control_dir, dentry->d_name.name);
1111 if (!channel_d) {
1112 ret = -ENOENT;
1113 goto out;
1114 }
1115
1116 if (list_empty(&channel_d->d_subdirs)) {
1117 mutex_unlock(&dir->i_mutex);
1118 mutex_unlock(&dentry->d_inode->i_mutex);
1119 debugfs_remove(channel_d);
1120 mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
1121 mutex_lock(&dentry->d_inode->i_mutex);
1122 } else
1123 ret = -EPERM;
1124
1125out:
1126 return ret;
1127}
1128
1129const struct inode_operations root_dir_opt = {
1130 .lookup = simple_lookup,
1131 .mkdir = channel_mkdir,
1132 .rmdir = channel_rmdir
1133};
1134
1135static int build_marker_file(struct marker *marker)
1136{
1137 struct dentry *channel_d, *marker_d, *enable_d, *info_d;
1138 int err;
1139
1140 channel_d = dir_lookup(markers_control_dir, marker->channel);
1141 if (!channel_d) {
1142 channel_d = debugfs_create_dir(marker->channel,
1143 markers_control_dir);
1144 if (IS_ERR(channel_d) || !channel_d) {
1145 printk(KERN_ERR
1146 "%s: build channel dir of %s failed\n",
1147 __func__, marker->channel);
1148 err = -ENOMEM;
1149 goto err_build_fail;
1150 }
1151 channel_d->d_inode->i_private = (void *)channel_d;
1152 init_marker_dir(channel_d, &channel_dir_opt);
1153 }
1154
1155 marker_d = dir_lookup(channel_d, marker->name);
1156 if (!marker_d) {
1157 marker_d = debugfs_create_dir(marker->name, channel_d);
1158 if (IS_ERR(marker_d) || !marker_d) {
1159 printk(KERN_ERR
1160 "%s: marker dir of %s failed\n",
1161 __func__, marker->name);
1162 err = -ENOMEM;
1163 goto err_build_fail;
1164 }
1165 }
1166
1167 enable_d = dir_lookup(marker_d, "enable");
1168 if (!enable_d) {
1169 enable_d = debugfs_create_file("enable", 0644, marker_d,
1170 NULL, &enable_fops);
1171 if (IS_ERR(enable_d) || !enable_d) {
1172 printk(KERN_ERR
1173 "%s: create file of %s failed\n",
1174 __func__, "enable");
1175 err = -ENOMEM;
1176 goto err_build_fail;
1177 }
1178 }
1179
1180 info_d = dir_lookup(marker_d, "info");
1181 if (!info_d) {
1182 info_d = debugfs_create_file("info", 0444, marker_d,
1183 NULL, &info_fops);
1184 if (IS_ERR(info_d) || !info_d) {
1185 printk(KERN_ERR
1186 "%s: create file of %s failed\n",
1187 __func__, "enable");
1188 err = -ENOMEM;
1189 goto err_build_fail;
1190 }
1191 }
1192
1193 return 0;
1194
1195err_build_fail:
1196 return err;
1197}
1198
1199static int build_marker_control_files(void)
1200{
1201 struct marker_iter iter;
1202 int err;
1203
1204 err = 0;
1205 if (!markers_control_dir)
1206 return -EEXIST;
1207
1208 marker_iter_reset(&iter);
1209 marker_iter_start(&iter);
1210 for (; iter.marker != NULL; marker_iter_next(&iter)) {
1211 err = build_marker_file(iter.marker);
1212 if (err)
1213 goto out;
1214 }
1215 marker_iter_stop(&iter);
1216
1217out:
1218 return err;
1219}
1220
1221#ifdef CONFIG_MODULES
1222static int remove_marker_control_dir(struct module *mod, struct marker *marker)
1223{
1224 struct dentry *channel_d, *marker_d;
1225 const char *channel, *name;
1226 int count;
1227 struct marker_iter iter;
1228
1229 count = 0;
1230
1231 channel_d = dir_lookup(markers_control_dir, marker->channel);
1232 if (!channel_d)
1233 return -ENOENT;
1234 channel = channel_d->d_name.name;
1235
1236 marker_d = dir_lookup(channel_d, marker->name);
1237 if (!marker_d)
1238 return -ENOENT;
1239 name = marker_d->d_name.name;
1240
1241 marker_iter_reset(&iter);
1242 marker_iter_start(&iter);
1243 for (; iter.marker != NULL; marker_iter_next(&iter)) {
1244 if (!strcmp(iter.marker->channel, channel) &&
1245 !strcmp(iter.marker->name, name) && mod != iter.module)
1246 count++;
1247 }
1248
1249 if (count > 0)
1250 goto end;
1251
1252 debugfs_remove_recursive(marker_d);
1253 if (list_empty(&channel_d->d_subdirs))
1254 debugfs_remove(channel_d);
1255
1256end:
1257 marker_iter_stop(&iter);
1258 return 0;
1259}
1260
1261static void cleanup_control_dir(struct module *mod, struct marker *begin,
1262 struct marker *end)
1263{
1264 struct marker *iter;
1265
1266 if (!markers_control_dir)
1267 return;
1268
1269 for (iter = begin; iter < end; iter++)
1270 remove_marker_control_dir(mod, iter);
1271
1272 return;
1273}
1274
1275static void build_control_dir(struct module *mod, struct marker *begin,
1276 struct marker *end)
1277{
1278 struct marker *iter;
1279 int err;
1280
1281 err = 0;
1282 if (!markers_control_dir)
1283 return;
1284
1285 for (iter = begin; iter < end; iter++) {
1286 err = build_marker_file(iter);
1287 if (err)
1288 goto err_build_fail;
1289 }
1290
1291 return;
1292err_build_fail:
1293 cleanup_control_dir(mod, begin, end);
1294}
1295
1296static int module_notify(struct notifier_block *self,
1297 unsigned long val, void *data)
1298{
1299 struct module *mod = data;
1300
1301 switch (val) {
1302 case MODULE_STATE_COMING:
1303 build_control_dir(mod, mod->markers,
1304 mod->markers + mod->num_markers);
1305 break;
1306 case MODULE_STATE_GOING:
1307 cleanup_control_dir(mod, mod->markers,
1308 mod->markers + mod->num_markers);
1309 break;
1310 }
1311 return NOTIFY_DONE;
1312}
1313#else
1314static inline int module_notify(struct notifier_block *self,
1315 unsigned long val, void *data)
1316{
1317 return 0;
1318}
1319#endif
1320
1321static struct notifier_block module_nb = {
1322 .notifier_call = module_notify,
1323};
1324
1325static int __init ltt_trace_control_init(void)
1326{
1327 int err = 0;
1328 struct dentry *ltt_root_dentry;
1329
1330 ltt_root_dentry = get_ltt_root();
1331 if (!ltt_root_dentry) {
1332 err = -ENOENT;
1333 goto err_no_root;
1334 }
1335
1336 ltt_control_dir = debugfs_create_dir(LTT_CONTROL_DIR, ltt_root_dentry);
1337 if (IS_ERR(ltt_control_dir) || !ltt_control_dir) {
1338 printk(KERN_ERR
1339 "ltt_channel_control_init: create dir of %s failed\n",
1340 LTT_CONTROL_DIR);
1341 err = -ENOMEM;
1342 goto err_create_control_dir;
1343 }
1344
1345 ltt_setup_trace_file = debugfs_create_file(LTT_SETUP_TRACE_FILE,
1346 S_IWUSR, ltt_root_dentry,
1347 NULL,
1348 &ltt_setup_trace_operations);
1349 if (IS_ERR(ltt_setup_trace_file) || !ltt_setup_trace_file) {
1350 printk(KERN_ERR
1351 "ltt_channel_control_init: create file of %s failed\n",
1352 LTT_SETUP_TRACE_FILE);
1353 err = -ENOMEM;
1354 goto err_create_setup_trace_file;
1355 }
1356
1357 ltt_destroy_trace_file = debugfs_create_file(LTT_DESTROY_TRACE_FILE,
1358 S_IWUSR, ltt_root_dentry,
1359 NULL,
1360 &ltt_destroy_trace_operations);
1361 if (IS_ERR(ltt_destroy_trace_file) || !ltt_destroy_trace_file) {
1362 printk(KERN_ERR
1363 "ltt_channel_control_init: create file of %s failed\n",
1364 LTT_DESTROY_TRACE_FILE);
1365 err = -ENOMEM;
1366 goto err_create_destroy_trace_file;
1367 }
1368
1369 markers_control_dir = debugfs_create_dir(MARKERS_CONTROL_DIR,
1370 ltt_root_dentry);
1371 if (IS_ERR(markers_control_dir) || !markers_control_dir) {
1372 printk(KERN_ERR
1373 "ltt_channel_control_init: create dir of %s failed\n",
1374 MARKERS_CONTROL_DIR);
1375 err = -ENOMEM;
1376 goto err_create_marker_control_dir;
1377 }
1378
1379 init_marker_dir(markers_control_dir, &root_dir_opt);
1380
1381 if (build_marker_control_files())
1382 goto err_build_fail;
1383
1384 if (!register_module_notifier(&module_nb))
1385 return 0;
1386
1387err_build_fail:
1388 debugfs_remove_recursive(markers_control_dir);
1389 markers_control_dir = NULL;
1390err_create_marker_control_dir:
1391 debugfs_remove(ltt_destroy_trace_file);
1392err_create_destroy_trace_file:
1393 debugfs_remove(ltt_setup_trace_file);
1394err_create_setup_trace_file:
1395 debugfs_remove(ltt_control_dir);
1396err_create_control_dir:
1397err_no_root:
1398 return err;
1399}
1400
1401static void __exit ltt_trace_control_exit(void)
1402{
1403 struct dentry *trace_dir;
1404
1405 /* destory all traces */
1406 list_for_each_entry(trace_dir, &ltt_control_dir->d_subdirs,
1407 d_u.d_child) {
1408 ltt_trace_stop(trace_dir->d_name.name);
1409 ltt_trace_destroy(trace_dir->d_name.name);
1410 }
1411
1412 /* clean dirs in debugfs */
1413 debugfs_remove(ltt_setup_trace_file);
1414 debugfs_remove(ltt_destroy_trace_file);
1415 debugfs_remove_recursive(ltt_control_dir);
1416 debugfs_remove_recursive(markers_control_dir);
1417 unregister_module_notifier(&module_nb);
1418 put_ltt_root();
1419}
1420
1421module_init(ltt_trace_control_init);
1422module_exit(ltt_trace_control_exit);
1423
1424MODULE_LICENSE("GPL and additional rights");
1425MODULE_AUTHOR("Zhao Lei <zhaolei@cn.fujitsu.com>");
1426MODULE_DESCRIPTION("Linux Trace Toolkit Trace Controller");
This page took 0.11174 seconds and 4 git commands to generate.