1 /* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1)
5 * LTTng adaptation layer for Linux kernel 3.15+ tracepoints.
7 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
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>
18 #include <lttng-tracepoint.h>
19 #include <wrapper/list.h>
22 * Protect the tracepoint table. lttng_tracepoint_mutex nests within
23 * kernel/tracepoint.c tp_modlist_mutex. kernel/tracepoint.c
24 * tracepoint_mutex nests within lttng_tracepoint_mutex.
27 DEFINE_MUTEX(lttng_tracepoint_mutex
);
29 #define TRACEPOINT_HASH_BITS 6
30 #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
32 struct hlist_head tracepoint_table
[TRACEPOINT_TABLE_SIZE
];
35 * The tracepoint entry is the node contained within the hash table. It
36 * is a mapping from the "string" key to the struct tracepoint pointer.
38 struct tracepoint_entry
{
39 struct hlist_node hlist
;
40 struct tracepoint
*tp
;
42 struct list_head probes
;
46 struct lttng_tp_probe
{
47 struct tracepoint_func tp_func
;
48 struct list_head list
;
52 int add_probe(struct tracepoint_entry
*e
, void *probe
, void *data
)
54 struct lttng_tp_probe
*p
;
57 list_for_each_entry(p
, &e
->probes
, list
) {
58 if (p
->tp_func
.func
== probe
&& p
->tp_func
.data
== data
) {
65 p
= kmalloc(sizeof(struct lttng_tp_probe
), GFP_KERNEL
);
68 p
->tp_func
.func
= probe
;
69 p
->tp_func
.data
= data
;
70 list_add(&p
->list
, &e
->probes
);
75 int remove_probe(struct tracepoint_entry
*e
, void *probe
, void *data
)
77 struct lttng_tp_probe
*p
;
80 list_for_each_entry(p
, &e
->probes
, list
) {
81 if (p
->tp_func
.func
== probe
&& p
->tp_func
.data
== data
) {
97 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
98 * Must be called with lttng_tracepoint_mutex held.
99 * Returns NULL if not present.
102 struct tracepoint_entry
*get_tracepoint(const char *name
)
104 struct hlist_head
*head
;
105 struct tracepoint_entry
*e
;
106 u32 hash
= jhash(name
, strlen(name
), 0);
108 head
= &tracepoint_table
[hash
& (TRACEPOINT_TABLE_SIZE
- 1)];
109 lttng_hlist_for_each_entry(e
, head
, hlist
) {
110 if (!strcmp(name
, e
->name
))
117 * Add the tracepoint to the tracepoint hash table. Must be called with
118 * lttng_tracepoint_mutex held.
121 struct tracepoint_entry
*add_tracepoint(const char *name
)
123 struct hlist_head
*head
;
124 struct tracepoint_entry
*e
;
125 size_t name_len
= strlen(name
) + 1;
126 u32 hash
= jhash(name
, name_len
- 1, 0);
128 head
= &tracepoint_table
[hash
& (TRACEPOINT_TABLE_SIZE
- 1)];
129 lttng_hlist_for_each_entry(e
, head
, hlist
) {
130 if (!strcmp(name
, e
->name
)) {
132 "tracepoint %s busy\n", name
);
133 return ERR_PTR(-EEXIST
); /* Already there */
137 * Using kmalloc here to allocate a variable length element. Could
138 * cause some memory fragmentation if overused.
140 e
= kmalloc(sizeof(struct tracepoint_entry
) + name_len
, GFP_KERNEL
);
142 return ERR_PTR(-ENOMEM
);
143 memcpy(&e
->name
[0], name
, name_len
);
146 INIT_LIST_HEAD(&e
->probes
);
147 hlist_add_head(&e
->hlist
, head
);
152 * Remove the tracepoint from the tracepoint hash table. Must be called
153 * with lttng_tracepoint_mutex held.
156 void remove_tracepoint(struct tracepoint_entry
*e
)
158 hlist_del(&e
->hlist
);
162 int lttng_tracepoint_probe_register(const char *name
, void *probe
, void *data
)
164 struct tracepoint_entry
*e
;
167 mutex_lock(<tng_tracepoint_mutex
);
168 e
= get_tracepoint(name
);
170 e
= add_tracepoint(name
);
176 /* add (probe, data) to entry */
177 ret
= add_probe(e
, probe
, data
);
182 ret
= tracepoint_probe_register(e
->tp
, probe
, data
);
187 mutex_unlock(<tng_tracepoint_mutex
);
191 int lttng_tracepoint_probe_unregister(const char *name
, void *probe
, void *data
)
193 struct tracepoint_entry
*e
;
196 mutex_lock(<tng_tracepoint_mutex
);
197 e
= get_tracepoint(name
);
202 /* remove (probe, data) from entry */
203 ret
= remove_probe(e
, probe
, data
);
207 ret
= tracepoint_probe_unregister(e
->tp
, probe
, data
);
212 remove_tracepoint(e
);
214 mutex_unlock(<tng_tracepoint_mutex
);
218 #ifdef CONFIG_MODULES
221 int lttng_tracepoint_coming(struct tp_module
*tp_mod
)
225 mutex_lock(<tng_tracepoint_mutex
);
226 for (i
= 0; i
< tp_mod
->mod
->num_tracepoints
; i
++) {
227 struct tracepoint
*tp
;
228 struct tracepoint_entry
*e
;
229 struct lttng_tp_probe
*p
;
231 tp
= tp_mod
->mod
->tracepoints_ptrs
[i
];
232 e
= get_tracepoint(tp
->name
);
234 e
= add_tracepoint(tp
->name
);
236 pr_warn("LTTng: error (%ld) adding tracepoint\n",
241 /* If already enabled, just check consistency */
243 WARN_ON(e
->tp
!= tp
);
248 /* register each (probe, data) */
249 list_for_each_entry(p
, &e
->probes
, list
) {
252 ret
= tracepoint_probe_register(e
->tp
,
253 p
->tp_func
.func
, p
->tp_func
.data
);
257 mutex_unlock(<tng_tracepoint_mutex
);
262 int lttng_tracepoint_going(struct tp_module
*tp_mod
)
266 mutex_lock(<tng_tracepoint_mutex
);
267 for (i
= 0; i
< tp_mod
->mod
->num_tracepoints
; i
++) {
268 struct tracepoint
*tp
;
269 struct tracepoint_entry
*e
;
270 struct lttng_tp_probe
*p
;
272 tp
= tp_mod
->mod
->tracepoints_ptrs
[i
];
273 e
= get_tracepoint(tp
->name
);
276 /* unregister each (probe, data) */
277 list_for_each_entry(p
, &e
->probes
, list
) {
280 ret
= tracepoint_probe_unregister(e
->tp
,
281 p
->tp_func
.func
, p
->tp_func
.data
);
286 remove_tracepoint(e
);
288 mutex_unlock(<tng_tracepoint_mutex
);
293 int lttng_tracepoint_notify(struct notifier_block
*self
,
294 unsigned long val
, void *data
)
296 struct tp_module
*tp_mod
= data
;
300 case MODULE_STATE_COMING
:
301 ret
= lttng_tracepoint_coming(tp_mod
);
303 case MODULE_STATE_GOING
:
304 ret
= lttng_tracepoint_going(tp_mod
);
313 struct notifier_block lttng_tracepoint_notifier
= {
314 .notifier_call
= lttng_tracepoint_notify
,
319 int lttng_tracepoint_module_init(void)
321 return register_tracepoint_module_notifier(<tng_tracepoint_notifier
);
325 void lttng_tracepoint_module_exit(void)
327 WARN_ON(unregister_tracepoint_module_notifier(<tng_tracepoint_notifier
));
330 #else /* #ifdef CONFIG_MODULES */
333 int lttng_tracepoint_module_init(void)
339 void lttng_tracepoint_module_exit(void)
343 #endif /* #else #ifdef CONFIG_MODULES */
346 void lttng_kernel_tracepoint_add(struct tracepoint
*tp
, void *priv
)
348 struct tracepoint_entry
*e
;
349 struct lttng_tp_probe
*p
;
352 mutex_lock(<tng_tracepoint_mutex
);
353 e
= get_tracepoint(tp
->name
);
355 e
= add_tracepoint(tp
->name
);
357 pr_warn("LTTng: error (%ld) adding tracepoint\n",
359 *ret
= (int) PTR_ERR(e
);
363 /* If already enabled, just check consistency */
365 WARN_ON(e
->tp
!= tp
);
370 /* register each (probe, data) */
371 list_for_each_entry(p
, &e
->probes
, list
) {
374 ret
= tracepoint_probe_register(e
->tp
,
375 p
->tp_func
.func
, p
->tp_func
.data
);
379 mutex_unlock(<tng_tracepoint_mutex
);
383 void lttng_kernel_tracepoint_remove(struct tracepoint
*tp
, void *priv
)
385 struct tracepoint_entry
*e
;
388 mutex_lock(<tng_tracepoint_mutex
);
389 e
= get_tracepoint(tp
->name
);
390 if (!e
|| e
->refcount
!= 1 || !list_empty(&e
->probes
)) {
394 remove_tracepoint(e
);
396 mutex_unlock(<tng_tracepoint_mutex
);
399 int __init
lttng_tracepoint_init(void)
403 for_each_kernel_tracepoint(lttng_kernel_tracepoint_add
, &ret
);
406 ret
= lttng_tracepoint_module_init();
415 for_each_kernel_tracepoint(lttng_kernel_tracepoint_remove
,
423 void lttng_tracepoint_exit(void)
427 lttng_tracepoint_module_exit();
428 for_each_kernel_tracepoint(lttng_kernel_tracepoint_remove
, &ret
);
430 mutex_lock(<tng_tracepoint_mutex
);
431 for (i
= 0; i
< TRACEPOINT_TABLE_SIZE
; i
++) {
432 struct hlist_head
*head
= &tracepoint_table
[i
];
434 /* All tracepoints should be removed */
435 WARN_ON(!hlist_empty(head
));
437 mutex_unlock(<tng_tracepoint_mutex
);