LTTng modularization, import of lttng 0.226
[lttng-modules.git] / probes / jbd2-trace.c
CommitLineData
1c8284eb
MD
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
18static struct dentry *jbd2_filter_dentry, *jbd2_filter_dev_dentry;
19static DEFINE_MUTEX(jbd2_filter_mutex);
20/* Make sure we don't race between module exit and file write */
21static int module_exits;
22
23struct rcu_dev_filter {
24 struct rcu_head rcu;
25 char devname[NAME_MAX];
26};
27
28static struct rcu_dev_filter *dev_filter;
29
30/*
31 * Probes are executed in rcu_sched read-side critical section.
32 */
33static 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
43void 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
52void 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
62void 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
73static void free_dev_filter(struct rcu_head *head)
74{
75 kfree(container_of(head, struct rcu_dev_filter, rcu));
76}
77
78static 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
120error:
121 mutex_unlock(&jbd2_filter_mutex);
122 return err;
123}
124
125static 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
142static struct file_operations jbd2_file_operations = {
143 .write = filter_op_write,
144 .read = filter_op_read,
145};
146
147static 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
160static 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
189release_filter_dentry:
190 debugfs_remove(jbd2_filter_dentry);
191 release_filter_dev();
192end:
193 return err;
194}
195
196static 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
203module_init(filter_init);
204module_exit(filter_exit);
205
206MODULE_LICENSE("GPL and additional rights");
207MODULE_AUTHOR("Mathieu Desnoyers");
208MODULE_DESCRIPTION("JBD2 Tracepoint Probes");
This page took 0.033705 seconds and 4 git commands to generate.