Version 2.9.15
[lttng-modules.git] / lttng-tracepoint.c
1 /*
2 * lttng-tracepoint.c
3 *
4 * LTTng adaptation layer for Linux kernel 3.15+ tracepoints.
5 *
6 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/mutex.h>
24 #include <linux/err.h>
25 #include <linux/notifier.h>
26 #include <linux/tracepoint.h>
27 #include <linux/slab.h>
28 #include <linux/jhash.h>
29 #include <linux/module.h>
30
31 #include <lttng-tracepoint.h>
32 #include <wrapper/list.h>
33 #include <wrapper/tracepoint.h>
34
35 /*
36 * Protect the tracepoint table. lttng_tracepoint_mutex nests within
37 * kernel/tracepoint.c tp_modlist_mutex. kernel/tracepoint.c
38 * tracepoint_mutex nests within lttng_tracepoint_mutex.
39 */
40 static
41 DEFINE_MUTEX(lttng_tracepoint_mutex);
42
43 #define TRACEPOINT_HASH_BITS 6
44 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
45 static
46 struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
47
48 /*
49 * The tracepoint entry is the node contained within the hash table. It
50 * is a mapping from the "string" key to the struct tracepoint pointer.
51 */
52 struct tracepoint_entry {
53 struct hlist_node hlist;
54 struct tracepoint *tp;
55 int refcount;
56 struct list_head probes;
57 char name[0];
58 };
59
60 struct lttng_tp_probe {
61 struct tracepoint_func tp_func;
62 struct list_head list;
63 };
64
65 static
66 int add_probe(struct tracepoint_entry *e, void *probe, void *data)
67 {
68 struct lttng_tp_probe *p;
69 int found = 0;
70
71 list_for_each_entry(p, &e->probes, list) {
72 if (p->tp_func.func == probe && p->tp_func.data == data) {
73 found = 1;
74 break;
75 }
76 }
77 if (found)
78 return -EEXIST;
79 p = kmalloc(sizeof(struct lttng_tp_probe), GFP_KERNEL);
80 if (!p)
81 return -ENOMEM;
82 p->tp_func.func = probe;
83 p->tp_func.data = data;
84 list_add(&p->list, &e->probes);
85 return 0;
86 }
87
88 static
89 int remove_probe(struct tracepoint_entry *e, void *probe, void *data)
90 {
91 struct lttng_tp_probe *p;
92 int found = 0;
93
94 list_for_each_entry(p, &e->probes, list) {
95 if (p->tp_func.func == probe && p->tp_func.data == data) {
96 found = 1;
97 break;
98 }
99 }
100 if (found) {
101 list_del(&p->list);
102 kfree(p);
103 return 0;
104 } else {
105 WARN_ON(1);
106 return -ENOENT;
107 }
108 }
109
110 /*
111 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
112 * Must be called with lttng_tracepoint_mutex held.
113 * Returns NULL if not present.
114 */
115 static
116 struct tracepoint_entry *get_tracepoint(const char *name)
117 {
118 struct hlist_head *head;
119 struct tracepoint_entry *e;
120 u32 hash = jhash(name, strlen(name), 0);
121
122 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
123 lttng_hlist_for_each_entry(e, head, hlist) {
124 if (!strcmp(name, e->name))
125 return e;
126 }
127 return NULL;
128 }
129
130 /*
131 * Add the tracepoint to the tracepoint hash table. Must be called with
132 * lttng_tracepoint_mutex held.
133 */
134 static
135 struct tracepoint_entry *add_tracepoint(const char *name)
136 {
137 struct hlist_head *head;
138 struct tracepoint_entry *e;
139 size_t name_len = strlen(name) + 1;
140 u32 hash = jhash(name, name_len - 1, 0);
141
142 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
143 lttng_hlist_for_each_entry(e, head, hlist) {
144 if (!strcmp(name, e->name)) {
145 printk(KERN_NOTICE
146 "tracepoint %s busy\n", name);
147 return ERR_PTR(-EEXIST); /* Already there */
148 }
149 }
150 /*
151 * Using kmalloc here to allocate a variable length element. Could
152 * cause some memory fragmentation if overused.
153 */
154 e = kmalloc(sizeof(struct tracepoint_entry) + name_len, GFP_KERNEL);
155 if (!e)
156 return ERR_PTR(-ENOMEM);
157 memcpy(&e->name[0], name, name_len);
158 e->tp = NULL;
159 e->refcount = 0;
160 INIT_LIST_HEAD(&e->probes);
161 hlist_add_head(&e->hlist, head);
162 return e;
163 }
164
165 /*
166 * Remove the tracepoint from the tracepoint hash table. Must be called
167 * with lttng_tracepoint_mutex held.
168 */
169 static
170 void remove_tracepoint(struct tracepoint_entry *e)
171 {
172 hlist_del(&e->hlist);
173 kfree(e);
174 }
175
176 int lttng_tracepoint_probe_register(const char *name, void *probe, void *data)
177 {
178 struct tracepoint_entry *e;
179 int ret = 0;
180
181 mutex_lock(&lttng_tracepoint_mutex);
182 e = get_tracepoint(name);
183 if (!e) {
184 e = add_tracepoint(name);
185 if (IS_ERR(e)) {
186 ret = PTR_ERR(e);
187 goto end;
188 }
189 }
190 /* add (probe, data) to entry */
191 ret = add_probe(e, probe, data);
192 if (ret)
193 goto end;
194 e->refcount++;
195 if (e->tp) {
196 ret = tracepoint_probe_register(e->tp, probe, data);
197 WARN_ON_ONCE(ret);
198 ret = 0;
199 }
200 end:
201 mutex_unlock(&lttng_tracepoint_mutex);
202 return ret;
203 }
204
205 int lttng_tracepoint_probe_unregister(const char *name, void *probe, void *data)
206 {
207 struct tracepoint_entry *e;
208 int ret = 0;
209
210 mutex_lock(&lttng_tracepoint_mutex);
211 e = get_tracepoint(name);
212 if (!e) {
213 ret = -ENOENT;
214 goto end;
215 }
216 /* remove (probe, data) from entry */
217 ret = remove_probe(e, probe, data);
218 if (ret)
219 goto end;
220 if (e->tp) {
221 ret = tracepoint_probe_unregister(e->tp, probe, data);
222 WARN_ON_ONCE(ret);
223 ret = 0;
224 }
225 if (!--e->refcount)
226 remove_tracepoint(e);
227 end:
228 mutex_unlock(&lttng_tracepoint_mutex);
229 return ret;
230 }
231
232 #ifdef CONFIG_MODULES
233
234 static
235 int lttng_tracepoint_coming(struct tp_module *tp_mod)
236 {
237 int i;
238
239 mutex_lock(&lttng_tracepoint_mutex);
240 for (i = 0; i < tp_mod->mod->num_tracepoints; i++) {
241 struct tracepoint *tp;
242 struct tracepoint_entry *e;
243 struct lttng_tp_probe *p;
244
245 tp = lttng_tracepoint_ptr_deref(&tp_mod->mod->tracepoints_ptrs[i]);
246 e = get_tracepoint(tp->name);
247 if (!e) {
248 e = add_tracepoint(tp->name);
249 if (IS_ERR(e)) {
250 pr_warn("LTTng: error (%ld) adding tracepoint\n",
251 PTR_ERR(e));
252 continue;
253 }
254 }
255 /* If already enabled, just check consistency */
256 if (e->tp) {
257 WARN_ON(e->tp != tp);
258 continue;
259 }
260 e->tp = tp;
261 e->refcount++;
262 /* register each (probe, data) */
263 list_for_each_entry(p, &e->probes, list) {
264 int ret;
265
266 ret = tracepoint_probe_register(e->tp,
267 p->tp_func.func, p->tp_func.data);
268 WARN_ON_ONCE(ret);
269 }
270 }
271 mutex_unlock(&lttng_tracepoint_mutex);
272 return NOTIFY_OK;
273 }
274
275 static
276 int lttng_tracepoint_going(struct tp_module *tp_mod)
277 {
278 int i;
279
280 mutex_lock(&lttng_tracepoint_mutex);
281 for (i = 0; i < tp_mod->mod->num_tracepoints; i++) {
282 struct tracepoint *tp;
283 struct tracepoint_entry *e;
284 struct lttng_tp_probe *p;
285
286 tp = lttng_tracepoint_ptr_deref(&tp_mod->mod->tracepoints_ptrs[i]);
287 e = get_tracepoint(tp->name);
288 if (!e || !e->tp)
289 continue;
290 /* unregister each (probe, data) */
291 list_for_each_entry(p, &e->probes, list) {
292 int ret;
293
294 ret = tracepoint_probe_unregister(e->tp,
295 p->tp_func.func, p->tp_func.data);
296 WARN_ON_ONCE(ret);
297 }
298 e->tp = NULL;
299 if (!--e->refcount)
300 remove_tracepoint(e);
301 }
302 mutex_unlock(&lttng_tracepoint_mutex);
303 return 0;
304 }
305
306 static
307 int lttng_tracepoint_notify(struct notifier_block *self,
308 unsigned long val, void *data)
309 {
310 struct tp_module *tp_mod = data;
311 int ret = 0;
312
313 switch (val) {
314 case MODULE_STATE_COMING:
315 ret = lttng_tracepoint_coming(tp_mod);
316 break;
317 case MODULE_STATE_GOING:
318 ret = lttng_tracepoint_going(tp_mod);
319 break;
320 default:
321 break;
322 }
323 return ret;
324 }
325
326 static
327 struct notifier_block lttng_tracepoint_notifier = {
328 .notifier_call = lttng_tracepoint_notify,
329 .priority = 0,
330 };
331
332 static
333 int lttng_tracepoint_module_init(void)
334 {
335 return register_tracepoint_module_notifier(&lttng_tracepoint_notifier);
336 }
337
338 static
339 void lttng_tracepoint_module_exit(void)
340 {
341 WARN_ON(unregister_tracepoint_module_notifier(&lttng_tracepoint_notifier));
342 }
343
344 #else /* #ifdef CONFIG_MODULES */
345
346 static
347 int lttng_tracepoint_module_init(void)
348 {
349 return 0;
350 }
351
352 static
353 void lttng_tracepoint_module_exit(void)
354 {
355 }
356
357 #endif /* #else #ifdef CONFIG_MODULES */
358
359 static
360 void lttng_kernel_tracepoint_add(struct tracepoint *tp, void *priv)
361 {
362 struct tracepoint_entry *e;
363 struct lttng_tp_probe *p;
364 int *ret = priv;
365
366 mutex_lock(&lttng_tracepoint_mutex);
367 e = get_tracepoint(tp->name);
368 if (!e) {
369 e = add_tracepoint(tp->name);
370 if (IS_ERR(e)) {
371 pr_warn("LTTng: error (%ld) adding tracepoint\n",
372 PTR_ERR(e));
373 *ret = (int) PTR_ERR(e);
374 goto end;
375 }
376 }
377 /* If already enabled, just check consistency */
378 if (e->tp) {
379 WARN_ON(e->tp != tp);
380 goto end;
381 }
382 e->tp = tp;
383 e->refcount++;
384 /* register each (probe, data) */
385 list_for_each_entry(p, &e->probes, list) {
386 int ret;
387
388 ret = tracepoint_probe_register(e->tp,
389 p->tp_func.func, p->tp_func.data);
390 WARN_ON_ONCE(ret);
391 }
392 end:
393 mutex_unlock(&lttng_tracepoint_mutex);
394 }
395
396 static
397 void lttng_kernel_tracepoint_remove(struct tracepoint *tp, void *priv)
398 {
399 struct tracepoint_entry *e;
400 int *ret = priv;
401
402 mutex_lock(&lttng_tracepoint_mutex);
403 e = get_tracepoint(tp->name);
404 if (!e || e->refcount != 1 || !list_empty(&e->probes)) {
405 *ret = -EINVAL;
406 goto end;
407 }
408 remove_tracepoint(e);
409 end:
410 mutex_unlock(&lttng_tracepoint_mutex);
411 }
412
413 int __init lttng_tracepoint_init(void)
414 {
415 int ret = 0;
416
417 for_each_kernel_tracepoint(lttng_kernel_tracepoint_add, &ret);
418 if (ret)
419 goto error;
420 ret = lttng_tracepoint_module_init();
421 if (ret)
422 goto error_module;
423 return 0;
424
425 error_module:
426 {
427 int error_ret = 0;
428
429 for_each_kernel_tracepoint(lttng_kernel_tracepoint_remove,
430 &error_ret);
431 WARN_ON(error_ret);
432 }
433 error:
434 return ret;
435 }
436
437 void lttng_tracepoint_exit(void)
438 {
439 int i, ret = 0;
440
441 lttng_tracepoint_module_exit();
442 for_each_kernel_tracepoint(lttng_kernel_tracepoint_remove, &ret);
443 WARN_ON(ret);
444 mutex_lock(&lttng_tracepoint_mutex);
445 for (i = 0; i < TRACEPOINT_TABLE_SIZE; i++) {
446 struct hlist_head *head = &tracepoint_table[i];
447
448 /* All tracepoints should be removed */
449 WARN_ON(!hlist_empty(head));
450 }
451 mutex_unlock(&lttng_tracepoint_mutex);
452 }
This page took 0.037517 seconds and 4 git commands to generate.