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