LTTng modularization, import of lttng 0.226
[lttng-modules.git] / probes / jbd2-trace.c
1 /*
2 * ltt/probes/jbd2-trace.c
3 *
4 * JBD2 tracepoint probes.
5 *
6 * (C) Copyright 2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
7 * Dual LGPL v2.1/GPL v2 license.
8 */
9
10 #include <linux/module.h>
11 #include <linux/debugfs.h>
12 #include <linux/mutex.h>
13 #include <linux/rcupdate.h>
14 #include <trace/events/jbd2.h>
15
16 #include "../ltt-tracer.h"
17
18 static struct dentry *jbd2_filter_dentry, *jbd2_filter_dev_dentry;
19 static DEFINE_MUTEX(jbd2_filter_mutex);
20 /* Make sure we don't race between module exit and file write */
21 static int module_exits;
22
23 struct rcu_dev_filter {
24 struct rcu_head rcu;
25 char devname[NAME_MAX];
26 };
27
28 static struct rcu_dev_filter *dev_filter;
29
30 /*
31 * Probes are executed in rcu_sched read-side critical section.
32 */
33 static int do_filter(const char *dev)
34 {
35 struct rcu_dev_filter *ldev_filter = rcu_dereference(dev_filter);
36
37 if (unlikely(ldev_filter))
38 if (unlikely(strcmp(ldev_filter->devname, dev)))
39 return 0;
40 return 1;
41 }
42
43 void probe_jbd2_checkpoint(void *data, journal_t *journal, int result)
44 {
45 if (unlikely(!do_filter(journal->j_devname)))
46 return;
47 trace_mark_tp(jbd2, checkpoint, jbd2_checkpoint,
48 probe_jbd2_checkpoint, "dev %s need_checkpoint %d",
49 journal->j_devname, result);
50 }
51
52 void probe_jbd2_start_commit(void *data, journal_t *journal,
53 transaction_t *commit_transaction)
54 {
55 if (unlikely(!do_filter(journal->j_devname)))
56 return;
57 trace_mark_tp(jbd2, start_commit, jbd2_start_commit,
58 probe_jbd2_start_commit, "dev %s transaction %d",
59 journal->j_devname, commit_transaction->t_tid);
60 }
61
62 void probe_jbd2_end_commit(void *data, journal_t *journal,
63 transaction_t *commit_transaction)
64 {
65 if (unlikely(!do_filter(journal->j_devname)))
66 return;
67 trace_mark_tp(jbd2, end_commit, jbd2_end_commit,
68 probe_jbd2_end_commit, "dev %s transaction %d head %d",
69 journal->j_devname, commit_transaction->t_tid,
70 journal->j_tail_sequence);
71 }
72
73 static void free_dev_filter(struct rcu_head *head)
74 {
75 kfree(container_of(head, struct rcu_dev_filter, rcu));
76 }
77
78 static ssize_t filter_op_write(struct file *file,
79 const char __user *user_buf, size_t count, loff_t *ppos)
80 {
81 int err = 0;
82 char buf[NAME_MAX];
83 int buf_size;
84 char name[NAME_MAX];
85 struct rcu_dev_filter *new, *old;
86
87 mutex_lock(&jbd2_filter_mutex);
88 if (module_exits) {
89 err = -EPERM;
90 goto error;
91 }
92 buf_size = min(count, sizeof(buf) - 1);
93 err = copy_from_user(buf, user_buf, buf_size);
94 if (err)
95 goto error;
96 buf[buf_size] = 0;
97
98 if (sscanf(buf, "%s", name) != 1) {
99 err = -EPERM;
100 goto error;
101 }
102
103 old = dev_filter;
104
105 /* Empty string or * means all active */
106 if (name[0] == '\0' || (name[0] == '*' && name[1] == '\0')) {
107 new = NULL;
108 } else {
109 new = kmalloc(sizeof(*new), GFP_KERNEL);
110 strcpy(new->devname, name);
111 }
112
113 rcu_assign_pointer(dev_filter, new);
114 if (old)
115 call_rcu_sched(&old->rcu, free_dev_filter);
116
117 mutex_unlock(&jbd2_filter_mutex);
118 return count;
119
120 error:
121 mutex_unlock(&jbd2_filter_mutex);
122 return err;
123 }
124
125 static ssize_t filter_op_read(struct file *filp, char __user *buffer,
126 size_t count, loff_t *ppos)
127 {
128 ssize_t bcount;
129 const char *devname;
130
131 mutex_lock(&jbd2_filter_mutex);
132 if (!dev_filter)
133 devname = "*";
134 else
135 devname = dev_filter->devname;
136 bcount = simple_read_from_buffer(buffer, count, ppos,
137 devname, strlen(devname));
138 mutex_unlock(&jbd2_filter_mutex);
139 return bcount;
140 }
141
142 static struct file_operations jbd2_file_operations = {
143 .write = filter_op_write,
144 .read = filter_op_read,
145 };
146
147 static void release_filter_dev(void)
148 {
149 struct rcu_dev_filter *old;
150
151 mutex_lock(&jbd2_filter_mutex);
152 module_exits = 1;
153 old = dev_filter;
154 rcu_assign_pointer(dev_filter, NULL);
155 if (old)
156 call_rcu_sched(&old->rcu, free_dev_filter);
157 mutex_unlock(&jbd2_filter_mutex);
158 }
159
160 static int __init filter_init(void)
161 {
162 struct dentry *filter_root_dentry;
163 int err = 0;
164
165 filter_root_dentry = get_filter_root();
166 if (!filter_root_dentry) {
167 err = -ENOENT;
168 goto end;
169 }
170
171 jbd2_filter_dentry = debugfs_create_dir("jbd2", filter_root_dentry);
172
173 if (IS_ERR(jbd2_filter_dentry) || !jbd2_filter_dentry) {
174 printk(KERN_ERR "Failed to create jbd2 filter file\n");
175 err = -ENOMEM;
176 goto end;
177 }
178
179 jbd2_filter_dev_dentry = debugfs_create_file("dev", S_IWUSR,
180 jbd2_filter_dentry, NULL, &jbd2_file_operations);
181 if (IS_ERR(jbd2_filter_dentry) || !jbd2_filter_dentry) {
182 printk(KERN_ERR "Failed to create jbd2 filter file\n");
183 err = -ENOMEM;
184 goto release_filter_dentry;
185 }
186
187 goto end;
188
189 release_filter_dentry:
190 debugfs_remove(jbd2_filter_dentry);
191 release_filter_dev();
192 end:
193 return err;
194 }
195
196 static void __exit filter_exit(void)
197 {
198 debugfs_remove(jbd2_filter_dev_dentry);
199 debugfs_remove(jbd2_filter_dentry);
200 release_filter_dev();
201 }
202
203 module_init(filter_init);
204 module_exit(filter_exit);
205
206 MODULE_LICENSE("GPL and additional rights");
207 MODULE_AUTHOR("Mathieu Desnoyers");
208 MODULE_DESCRIPTION("JBD2 Tracepoint Probes");
This page took 0.033475 seconds and 4 git commands to generate.