]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
97e1c18e | 2 | /* |
de7b2973 | 3 | * Copyright (C) 2008-2014 Mathieu Desnoyers |
97e1c18e MD |
4 | */ |
5 | #include <linux/module.h> | |
6 | #include <linux/mutex.h> | |
7 | #include <linux/types.h> | |
8 | #include <linux/jhash.h> | |
9 | #include <linux/list.h> | |
10 | #include <linux/rcupdate.h> | |
11 | #include <linux/tracepoint.h> | |
12 | #include <linux/err.h> | |
13 | #include <linux/slab.h> | |
3f07c014 | 14 | #include <linux/sched/signal.h> |
29930025 | 15 | #include <linux/sched/task.h> |
c5905afb | 16 | #include <linux/static_key.h> |
97e1c18e | 17 | |
231264d6 MD |
18 | enum tp_func_state { |
19 | TP_FUNC_0, | |
20 | TP_FUNC_1, | |
21 | TP_FUNC_2, | |
22 | TP_FUNC_N, | |
23 | }; | |
24 | ||
9c0be3f6 MD |
25 | extern tracepoint_ptr_t __start___tracepoints_ptrs[]; |
26 | extern tracepoint_ptr_t __stop___tracepoints_ptrs[]; | |
97e1c18e | 27 | |
e6753f23 JFG |
28 | DEFINE_SRCU(tracepoint_srcu); |
29 | EXPORT_SYMBOL_GPL(tracepoint_srcu); | |
30 | ||
7b40066c MD |
31 | enum tp_transition_sync { |
32 | TP_TRANSITION_SYNC_1_0_1, | |
33 | TP_TRANSITION_SYNC_N_2_1, | |
34 | ||
35 | _NR_TP_TRANSITION_SYNC, | |
36 | }; | |
37 | ||
38 | struct tp_transition_snapshot { | |
39 | unsigned long rcu; | |
40 | unsigned long srcu; | |
41 | bool ongoing; | |
42 | }; | |
43 | ||
44 | /* Protected by tracepoints_mutex */ | |
45 | static struct tp_transition_snapshot tp_transition_snapshot[_NR_TP_TRANSITION_SYNC]; | |
46 | ||
47 | static void tp_rcu_get_state(enum tp_transition_sync sync) | |
48 | { | |
49 | struct tp_transition_snapshot *snapshot = &tp_transition_snapshot[sync]; | |
50 | ||
51 | /* Keep the latest get_state snapshot. */ | |
52 | snapshot->rcu = get_state_synchronize_rcu(); | |
53 | snapshot->srcu = start_poll_synchronize_srcu(&tracepoint_srcu); | |
54 | snapshot->ongoing = true; | |
55 | } | |
56 | ||
57 | static void tp_rcu_cond_sync(enum tp_transition_sync sync) | |
58 | { | |
59 | struct tp_transition_snapshot *snapshot = &tp_transition_snapshot[sync]; | |
60 | ||
61 | if (!snapshot->ongoing) | |
62 | return; | |
63 | cond_synchronize_rcu(snapshot->rcu); | |
64 | if (!poll_state_synchronize_srcu(&tracepoint_srcu, snapshot->srcu)) | |
65 | synchronize_srcu(&tracepoint_srcu); | |
66 | snapshot->ongoing = false; | |
67 | } | |
68 | ||
97e1c18e MD |
69 | /* Set to 1 to enable tracepoint debug output */ |
70 | static const int tracepoint_debug; | |
71 | ||
de7b2973 | 72 | #ifdef CONFIG_MODULES |
97e1c18e | 73 | /* |
de7b2973 | 74 | * Tracepoint module list mutex protects the local module list. |
97e1c18e | 75 | */ |
de7b2973 | 76 | static DEFINE_MUTEX(tracepoint_module_list_mutex); |
97e1c18e | 77 | |
de7b2973 | 78 | /* Local list of struct tp_module */ |
b75ef8b4 MD |
79 | static LIST_HEAD(tracepoint_module_list); |
80 | #endif /* CONFIG_MODULES */ | |
81 | ||
97e1c18e | 82 | /* |
de7b2973 MD |
83 | * tracepoints_mutex protects the builtin and module tracepoints. |
84 | * tracepoints_mutex nests inside tracepoint_module_list_mutex. | |
97e1c18e | 85 | */ |
de7b2973 | 86 | static DEFINE_MUTEX(tracepoints_mutex); |
97e1c18e | 87 | |
f8a79d5c SRV |
88 | static struct rcu_head *early_probes; |
89 | static bool ok_to_free_tracepoints; | |
90 | ||
97e1c18e MD |
91 | /* |
92 | * Note about RCU : | |
fd589a8f | 93 | * It is used to delay the free of multiple probes array until a quiescent |
97e1c18e | 94 | * state is reached. |
97e1c18e | 95 | */ |
19dba33c | 96 | struct tp_probes { |
0dea6d52 | 97 | struct rcu_head rcu; |
9d0a49c7 | 98 | struct tracepoint_func probes[]; |
19dba33c | 99 | }; |
97e1c18e | 100 | |
befe6d94 SRV |
101 | /* Called in removal of a func but failed to allocate a new tp_funcs */ |
102 | static void tp_stub_func(void) | |
103 | { | |
104 | return; | |
105 | } | |
106 | ||
19dba33c | 107 | static inline void *allocate_probes(int count) |
97e1c18e | 108 | { |
f0553dcb GS |
109 | struct tp_probes *p = kmalloc(struct_size(p, probes, count), |
110 | GFP_KERNEL); | |
19dba33c | 111 | return p == NULL ? NULL : p->probes; |
97e1c18e MD |
112 | } |
113 | ||
e6753f23 | 114 | static void srcu_free_old_probes(struct rcu_head *head) |
97e1c18e | 115 | { |
0dea6d52 | 116 | kfree(container_of(head, struct tp_probes, rcu)); |
19dba33c LJ |
117 | } |
118 | ||
e6753f23 JFG |
119 | static void rcu_free_old_probes(struct rcu_head *head) |
120 | { | |
121 | call_srcu(&tracepoint_srcu, head, srcu_free_old_probes); | |
122 | } | |
123 | ||
f8a79d5c SRV |
124 | static __init int release_early_probes(void) |
125 | { | |
126 | struct rcu_head *tmp; | |
127 | ||
128 | ok_to_free_tracepoints = true; | |
129 | ||
130 | while (early_probes) { | |
131 | tmp = early_probes; | |
132 | early_probes = tmp->next; | |
74401729 | 133 | call_rcu(tmp, rcu_free_old_probes); |
f8a79d5c SRV |
134 | } |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | /* SRCU is initialized at core_initcall */ | |
140 | postcore_initcall(release_early_probes); | |
141 | ||
38516ab5 | 142 | static inline void release_probes(struct tracepoint_func *old) |
19dba33c LJ |
143 | { |
144 | if (old) { | |
145 | struct tp_probes *tp_probes = container_of(old, | |
146 | struct tp_probes, probes[0]); | |
f8a79d5c SRV |
147 | |
148 | /* | |
149 | * We can't free probes if SRCU is not initialized yet. | |
150 | * Postpone the freeing till after SRCU is initialized. | |
151 | */ | |
152 | if (unlikely(!ok_to_free_tracepoints)) { | |
153 | tp_probes->rcu.next = early_probes; | |
154 | early_probes = &tp_probes->rcu; | |
155 | return; | |
156 | } | |
157 | ||
e6753f23 JFG |
158 | /* |
159 | * Tracepoint probes are protected by both sched RCU and SRCU, | |
160 | * by calling the SRCU callback in the sched RCU callback we | |
161 | * cover both cases. So let us chain the SRCU and sched RCU | |
162 | * callbacks to wait for both grace periods. | |
163 | */ | |
74401729 | 164 | call_rcu(&tp_probes->rcu, rcu_free_old_probes); |
19dba33c | 165 | } |
97e1c18e MD |
166 | } |
167 | ||
de7b2973 | 168 | static void debug_print_probes(struct tracepoint_func *funcs) |
97e1c18e MD |
169 | { |
170 | int i; | |
171 | ||
de7b2973 | 172 | if (!tracepoint_debug || !funcs) |
97e1c18e MD |
173 | return; |
174 | ||
de7b2973 MD |
175 | for (i = 0; funcs[i].func; i++) |
176 | printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func); | |
97e1c18e MD |
177 | } |
178 | ||
7904b5c4 SRRH |
179 | static struct tracepoint_func * |
180 | func_add(struct tracepoint_func **funcs, struct tracepoint_func *tp_func, | |
181 | int prio) | |
97e1c18e | 182 | { |
38516ab5 | 183 | struct tracepoint_func *old, *new; |
7211f0a2 SRV |
184 | int iter_probes; /* Iterate over old probe array. */ |
185 | int nr_probes = 0; /* Counter for probes */ | |
186 | int pos = -1; /* Insertion position into new array */ | |
97e1c18e | 187 | |
de7b2973 | 188 | if (WARN_ON(!tp_func->func)) |
4c69e6ea | 189 | return ERR_PTR(-EINVAL); |
97e1c18e | 190 | |
de7b2973 MD |
191 | debug_print_probes(*funcs); |
192 | old = *funcs; | |
97e1c18e MD |
193 | if (old) { |
194 | /* (N -> N+1), (N != 0, 1) probes */ | |
7211f0a2 SRV |
195 | for (iter_probes = 0; old[iter_probes].func; iter_probes++) { |
196 | if (old[iter_probes].func == tp_stub_func) | |
197 | continue; /* Skip stub functions. */ | |
198 | if (old[iter_probes].func == tp_func->func && | |
199 | old[iter_probes].data == tp_func->data) | |
97e1c18e | 200 | return ERR_PTR(-EEXIST); |
7211f0a2 | 201 | nr_probes++; |
7904b5c4 | 202 | } |
97e1c18e | 203 | } |
7211f0a2 SRV |
204 | /* + 2 : one for new probe, one for NULL func */ |
205 | new = allocate_probes(nr_probes + 2); | |
97e1c18e MD |
206 | if (new == NULL) |
207 | return ERR_PTR(-ENOMEM); | |
7904b5c4 | 208 | if (old) { |
7211f0a2 SRV |
209 | nr_probes = 0; |
210 | for (iter_probes = 0; old[iter_probes].func; iter_probes++) { | |
211 | if (old[iter_probes].func == tp_stub_func) | |
212 | continue; | |
213 | /* Insert before probes of lower priority */ | |
214 | if (pos < 0 && old[iter_probes].prio < prio) | |
215 | pos = nr_probes++; | |
216 | new[nr_probes++] = old[iter_probes]; | |
7904b5c4 | 217 | } |
7211f0a2 SRV |
218 | if (pos < 0) |
219 | pos = nr_probes++; | |
220 | /* nr_probes now points to the end of the new array */ | |
221 | } else { | |
7904b5c4 | 222 | pos = 0; |
7211f0a2 SRV |
223 | nr_probes = 1; /* must point at end of array */ |
224 | } | |
7904b5c4 | 225 | new[pos] = *tp_func; |
7211f0a2 | 226 | new[nr_probes].func = NULL; |
de7b2973 MD |
227 | *funcs = new; |
228 | debug_print_probes(*funcs); | |
97e1c18e MD |
229 | return old; |
230 | } | |
231 | ||
de7b2973 MD |
232 | static void *func_remove(struct tracepoint_func **funcs, |
233 | struct tracepoint_func *tp_func) | |
97e1c18e MD |
234 | { |
235 | int nr_probes = 0, nr_del = 0, i; | |
38516ab5 | 236 | struct tracepoint_func *old, *new; |
97e1c18e | 237 | |
de7b2973 | 238 | old = *funcs; |
97e1c18e | 239 | |
f66af459 | 240 | if (!old) |
19dba33c | 241 | return ERR_PTR(-ENOENT); |
f66af459 | 242 | |
de7b2973 | 243 | debug_print_probes(*funcs); |
97e1c18e | 244 | /* (N -> M), (N > 1, M >= 0) probes */ |
de7b2973 | 245 | if (tp_func->func) { |
4c69e6ea | 246 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) { |
befe6d94 SRV |
247 | if ((old[nr_probes].func == tp_func->func && |
248 | old[nr_probes].data == tp_func->data) || | |
249 | old[nr_probes].func == tp_stub_func) | |
4c69e6ea S |
250 | nr_del++; |
251 | } | |
97e1c18e MD |
252 | } |
253 | ||
4c69e6ea S |
254 | /* |
255 | * If probe is NULL, then nr_probes = nr_del = 0, and then the | |
256 | * entire entry will be removed. | |
257 | */ | |
97e1c18e MD |
258 | if (nr_probes - nr_del == 0) { |
259 | /* N -> 0, (N > 1) */ | |
de7b2973 MD |
260 | *funcs = NULL; |
261 | debug_print_probes(*funcs); | |
97e1c18e MD |
262 | return old; |
263 | } else { | |
264 | int j = 0; | |
265 | /* N -> M, (N > 1, M > 0) */ | |
266 | /* + 1 for NULL */ | |
19dba33c | 267 | new = allocate_probes(nr_probes - nr_del + 1); |
befe6d94 | 268 | if (new) { |
7211f0a2 SRV |
269 | for (i = 0; old[i].func; i++) { |
270 | if ((old[i].func != tp_func->func || | |
271 | old[i].data != tp_func->data) && | |
272 | old[i].func != tp_stub_func) | |
befe6d94 | 273 | new[j++] = old[i]; |
7211f0a2 | 274 | } |
befe6d94 SRV |
275 | new[nr_probes - nr_del].func = NULL; |
276 | *funcs = new; | |
277 | } else { | |
278 | /* | |
279 | * Failed to allocate, replace the old function | |
280 | * with calls to tp_stub_func. | |
281 | */ | |
7211f0a2 | 282 | for (i = 0; old[i].func; i++) { |
befe6d94 | 283 | if (old[i].func == tp_func->func && |
7211f0a2 SRV |
284 | old[i].data == tp_func->data) |
285 | WRITE_ONCE(old[i].func, tp_stub_func); | |
286 | } | |
befe6d94 SRV |
287 | *funcs = old; |
288 | } | |
97e1c18e | 289 | } |
de7b2973 | 290 | debug_print_probes(*funcs); |
97e1c18e MD |
291 | return old; |
292 | } | |
293 | ||
231264d6 MD |
294 | /* |
295 | * Count the number of functions (enum tp_func_state) in a tp_funcs array. | |
296 | */ | |
297 | static enum tp_func_state nr_func_state(const struct tracepoint_func *tp_funcs) | |
298 | { | |
299 | if (!tp_funcs) | |
300 | return TP_FUNC_0; | |
301 | if (!tp_funcs[1].func) | |
302 | return TP_FUNC_1; | |
303 | if (!tp_funcs[2].func) | |
304 | return TP_FUNC_2; | |
305 | return TP_FUNC_N; /* 3 or more */ | |
306 | } | |
307 | ||
308 | static void tracepoint_update_call(struct tracepoint *tp, struct tracepoint_func *tp_funcs) | |
d25e37d8 SRV |
309 | { |
310 | void *func = tp->iterator; | |
311 | ||
312 | /* Synthetic events do not have static call sites */ | |
313 | if (!tp->static_call_key) | |
314 | return; | |
231264d6 | 315 | if (nr_func_state(tp_funcs) == TP_FUNC_1) |
d25e37d8 | 316 | func = tp_funcs[0].func; |
d25e37d8 SRV |
317 | __static_call_update(tp->static_call_key, tp->static_call_tramp, func); |
318 | } | |
319 | ||
97e1c18e | 320 | /* |
de7b2973 | 321 | * Add the probe function to a tracepoint. |
97e1c18e | 322 | */ |
de7b2973 | 323 | static int tracepoint_add_func(struct tracepoint *tp, |
9913d574 SRV |
324 | struct tracepoint_func *func, int prio, |
325 | bool warn) | |
97e1c18e | 326 | { |
de7b2973 | 327 | struct tracepoint_func *old, *tp_funcs; |
8cf868af | 328 | int ret; |
97e1c18e | 329 | |
8cf868af SRRH |
330 | if (tp->regfunc && !static_key_enabled(&tp->key)) { |
331 | ret = tp->regfunc(); | |
332 | if (ret < 0) | |
333 | return ret; | |
334 | } | |
97e1c18e | 335 | |
b725dfea MD |
336 | tp_funcs = rcu_dereference_protected(tp->funcs, |
337 | lockdep_is_held(&tracepoints_mutex)); | |
7904b5c4 | 338 | old = func_add(&tp_funcs, func, prio); |
de7b2973 | 339 | if (IS_ERR(old)) { |
9913d574 | 340 | WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM); |
de7b2973 MD |
341 | return PTR_ERR(old); |
342 | } | |
97419875 | 343 | |
97e1c18e | 344 | /* |
243d1a79 PM |
345 | * rcu_assign_pointer has as smp_store_release() which makes sure |
346 | * that the new probe callbacks array is consistent before setting | |
347 | * a pointer to it. This array is referenced by __DO_TRACE from | |
348 | * include/linux/tracepoint.h using rcu_dereference_sched(). | |
97e1c18e | 349 | */ |
231264d6 MD |
350 | switch (nr_func_state(tp_funcs)) { |
351 | case TP_FUNC_1: /* 0->1 */ | |
7b40066c MD |
352 | /* |
353 | * Make sure new static func never uses old data after a | |
354 | * 1->0->1 transition sequence. | |
355 | */ | |
356 | tp_rcu_cond_sync(TP_TRANSITION_SYNC_1_0_1); | |
231264d6 MD |
357 | /* Set static call to first function */ |
358 | tracepoint_update_call(tp, tp_funcs); | |
359 | /* Both iterator and static call handle NULL tp->funcs */ | |
360 | rcu_assign_pointer(tp->funcs, tp_funcs); | |
361 | static_key_enable(&tp->key); | |
362 | break; | |
363 | case TP_FUNC_2: /* 1->2 */ | |
364 | /* Set iterator static call */ | |
365 | tracepoint_update_call(tp, tp_funcs); | |
366 | /* | |
367 | * Iterator callback installed before updating tp->funcs. | |
368 | * Requires ordering between RCU assign/dereference and | |
369 | * static call update/call. | |
370 | */ | |
7b40066c | 371 | fallthrough; |
231264d6 MD |
372 | case TP_FUNC_N: /* N->N+1 (N>1) */ |
373 | rcu_assign_pointer(tp->funcs, tp_funcs); | |
7b40066c MD |
374 | /* |
375 | * Make sure static func never uses incorrect data after a | |
376 | * N->...->2->1 (N>1) transition sequence. | |
377 | */ | |
378 | if (tp_funcs[0].data != old[0].data) | |
379 | tp_rcu_get_state(TP_TRANSITION_SYNC_N_2_1); | |
231264d6 MD |
380 | break; |
381 | default: | |
382 | WARN_ON_ONCE(1); | |
383 | break; | |
384 | } | |
d25e37d8 | 385 | |
8058bd0f | 386 | release_probes(old); |
de7b2973 | 387 | return 0; |
97e1c18e MD |
388 | } |
389 | ||
390 | /* | |
de7b2973 | 391 | * Remove a probe function from a tracepoint. |
97e1c18e MD |
392 | * Note: only waiting an RCU period after setting elem->call to the empty |
393 | * function insures that the original callback is not used anymore. This insured | |
394 | * by preempt_disable around the call site. | |
395 | */ | |
de7b2973 MD |
396 | static int tracepoint_remove_func(struct tracepoint *tp, |
397 | struct tracepoint_func *func) | |
97e1c18e | 398 | { |
de7b2973 | 399 | struct tracepoint_func *old, *tp_funcs; |
97e1c18e | 400 | |
b725dfea MD |
401 | tp_funcs = rcu_dereference_protected(tp->funcs, |
402 | lockdep_is_held(&tracepoints_mutex)); | |
de7b2973 | 403 | old = func_remove(&tp_funcs, func); |
befe6d94 | 404 | if (WARN_ON_ONCE(IS_ERR(old))) |
de7b2973 | 405 | return PTR_ERR(old); |
befe6d94 SRV |
406 | |
407 | if (tp_funcs == old) | |
408 | /* Failed allocating new tp_funcs, replaced func with stub */ | |
409 | return 0; | |
b75ef8b4 | 410 | |
231264d6 MD |
411 | switch (nr_func_state(tp_funcs)) { |
412 | case TP_FUNC_0: /* 1->0 */ | |
de7b2973 MD |
413 | /* Removed last function */ |
414 | if (tp->unregfunc && static_key_enabled(&tp->key)) | |
415 | tp->unregfunc(); | |
b75ef8b4 | 416 | |
d25e37d8 | 417 | static_key_disable(&tp->key); |
231264d6 MD |
418 | /* Set iterator static call */ |
419 | tracepoint_update_call(tp, tp_funcs); | |
420 | /* Both iterator and static call handle NULL tp->funcs */ | |
421 | rcu_assign_pointer(tp->funcs, NULL); | |
422 | /* | |
7b40066c MD |
423 | * Make sure new static func never uses old data after a |
424 | * 1->0->1 transition sequence. | |
231264d6 | 425 | */ |
7b40066c | 426 | tp_rcu_get_state(TP_TRANSITION_SYNC_1_0_1); |
231264d6 MD |
427 | break; |
428 | case TP_FUNC_1: /* 2->1 */ | |
547305a6 | 429 | rcu_assign_pointer(tp->funcs, tp_funcs); |
231264d6 | 430 | /* |
7b40066c MD |
431 | * Make sure static func never uses incorrect data after a |
432 | * N->...->2->1 (N>2) transition sequence. If the first | |
433 | * element's data has changed, then force the synchronization | |
434 | * to prevent current readers that have loaded the old data | |
435 | * from calling the new function. | |
231264d6 | 436 | */ |
7b40066c MD |
437 | if (tp_funcs[0].data != old[0].data) |
438 | tp_rcu_get_state(TP_TRANSITION_SYNC_N_2_1); | |
439 | tp_rcu_cond_sync(TP_TRANSITION_SYNC_N_2_1); | |
231264d6 MD |
440 | /* Set static call to first function */ |
441 | tracepoint_update_call(tp, tp_funcs); | |
442 | break; | |
443 | case TP_FUNC_2: /* N->N-1 (N>2) */ | |
444 | fallthrough; | |
445 | case TP_FUNC_N: | |
547305a6 | 446 | rcu_assign_pointer(tp->funcs, tp_funcs); |
7b40066c MD |
447 | /* |
448 | * Make sure static func never uses incorrect data after a | |
449 | * N->...->2->1 (N>2) transition sequence. | |
450 | */ | |
451 | if (tp_funcs[0].data != old[0].data) | |
452 | tp_rcu_get_state(TP_TRANSITION_SYNC_N_2_1); | |
231264d6 MD |
453 | break; |
454 | default: | |
455 | WARN_ON_ONCE(1); | |
456 | break; | |
127cafbb | 457 | } |
8058bd0f | 458 | release_probes(old); |
de7b2973 | 459 | return 0; |
127cafbb LJ |
460 | } |
461 | ||
9913d574 SRV |
462 | /** |
463 | * tracepoint_probe_register_prio_may_exist - Connect a probe to a tracepoint with priority | |
464 | * @tp: tracepoint | |
465 | * @probe: probe handler | |
466 | * @data: tracepoint data | |
467 | * @prio: priority of this function over other registered functions | |
468 | * | |
469 | * Same as tracepoint_probe_register_prio() except that it will not warn | |
470 | * if the tracepoint is already registered. | |
471 | */ | |
472 | int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, | |
473 | void *data, int prio) | |
474 | { | |
475 | struct tracepoint_func tp_func; | |
476 | int ret; | |
477 | ||
478 | mutex_lock(&tracepoints_mutex); | |
479 | tp_func.func = probe; | |
480 | tp_func.data = data; | |
481 | tp_func.prio = prio; | |
482 | ret = tracepoint_add_func(tp, &tp_func, prio, false); | |
483 | mutex_unlock(&tracepoints_mutex); | |
484 | return ret; | |
485 | } | |
486 | EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist); | |
487 | ||
97e1c18e | 488 | /** |
f39e2391 | 489 | * tracepoint_probe_register_prio - Connect a probe to a tracepoint with priority |
de7b2973 | 490 | * @tp: tracepoint |
97e1c18e | 491 | * @probe: probe handler |
cac92ba7 | 492 | * @data: tracepoint data |
7904b5c4 | 493 | * @prio: priority of this function over other registered functions |
97e1c18e | 494 | * |
de7b2973 MD |
495 | * Returns 0 if ok, error value on error. |
496 | * Note: if @tp is within a module, the caller is responsible for | |
497 | * unregistering the probe before the module is gone. This can be | |
498 | * performed either with a tracepoint module going notifier, or from | |
499 | * within module exit functions. | |
97e1c18e | 500 | */ |
7904b5c4 SRRH |
501 | int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, |
502 | void *data, int prio) | |
97e1c18e | 503 | { |
de7b2973 MD |
504 | struct tracepoint_func tp_func; |
505 | int ret; | |
97e1c18e MD |
506 | |
507 | mutex_lock(&tracepoints_mutex); | |
de7b2973 MD |
508 | tp_func.func = probe; |
509 | tp_func.data = data; | |
7904b5c4 | 510 | tp_func.prio = prio; |
9913d574 | 511 | ret = tracepoint_add_func(tp, &tp_func, prio, true); |
b75ef8b4 | 512 | mutex_unlock(&tracepoints_mutex); |
b196e2b9 | 513 | return ret; |
97e1c18e | 514 | } |
7904b5c4 SRRH |
515 | EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio); |
516 | ||
517 | /** | |
518 | * tracepoint_probe_register - Connect a probe to a tracepoint | |
519 | * @tp: tracepoint | |
520 | * @probe: probe handler | |
521 | * @data: tracepoint data | |
7904b5c4 SRRH |
522 | * |
523 | * Returns 0 if ok, error value on error. | |
524 | * Note: if @tp is within a module, the caller is responsible for | |
525 | * unregistering the probe before the module is gone. This can be | |
526 | * performed either with a tracepoint module going notifier, or from | |
527 | * within module exit functions. | |
528 | */ | |
529 | int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) | |
530 | { | |
531 | return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO); | |
532 | } | |
97e1c18e MD |
533 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); |
534 | ||
535 | /** | |
536 | * tracepoint_probe_unregister - Disconnect a probe from a tracepoint | |
de7b2973 | 537 | * @tp: tracepoint |
97e1c18e | 538 | * @probe: probe function pointer |
cac92ba7 | 539 | * @data: tracepoint data |
97e1c18e | 540 | * |
de7b2973 | 541 | * Returns 0 if ok, error value on error. |
97e1c18e | 542 | */ |
de7b2973 | 543 | int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data) |
97e1c18e | 544 | { |
de7b2973 MD |
545 | struct tracepoint_func tp_func; |
546 | int ret; | |
97e1c18e MD |
547 | |
548 | mutex_lock(&tracepoints_mutex); | |
de7b2973 MD |
549 | tp_func.func = probe; |
550 | tp_func.data = data; | |
551 | ret = tracepoint_remove_func(tp, &tp_func); | |
b75ef8b4 | 552 | mutex_unlock(&tracepoints_mutex); |
de7b2973 | 553 | return ret; |
97e1c18e MD |
554 | } |
555 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); | |
556 | ||
9c0be3f6 MD |
557 | static void for_each_tracepoint_range( |
558 | tracepoint_ptr_t *begin, tracepoint_ptr_t *end, | |
46e0c9be AB |
559 | void (*fct)(struct tracepoint *tp, void *priv), |
560 | void *priv) | |
561 | { | |
9c0be3f6 MD |
562 | tracepoint_ptr_t *iter; |
563 | ||
46e0c9be AB |
564 | if (!begin) |
565 | return; | |
9c0be3f6 MD |
566 | for (iter = begin; iter < end; iter++) |
567 | fct(tracepoint_ptr_deref(iter), priv); | |
46e0c9be AB |
568 | } |
569 | ||
227a8375 | 570 | #ifdef CONFIG_MODULES |
45ab2813 SRRH |
571 | bool trace_module_has_bad_taint(struct module *mod) |
572 | { | |
66cc69e3 | 573 | return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | |
e7bb66f7 JL |
574 | (1 << TAINT_UNSIGNED_MODULE) | (1 << TAINT_TEST) | |
575 | (1 << TAINT_LIVEPATCH)); | |
45ab2813 SRRH |
576 | } |
577 | ||
de7b2973 MD |
578 | static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); |
579 | ||
580 | /** | |
bd740953 | 581 | * register_tracepoint_module_notifier - register tracepoint coming/going notifier |
de7b2973 MD |
582 | * @nb: notifier block |
583 | * | |
584 | * Notifiers registered with this function are called on module | |
585 | * coming/going with the tracepoint_module_list_mutex held. | |
586 | * The notifier block callback should expect a "struct tp_module" data | |
587 | * pointer. | |
588 | */ | |
589 | int register_tracepoint_module_notifier(struct notifier_block *nb) | |
590 | { | |
591 | struct tp_module *tp_mod; | |
592 | int ret; | |
593 | ||
594 | mutex_lock(&tracepoint_module_list_mutex); | |
595 | ret = blocking_notifier_chain_register(&tracepoint_notify_list, nb); | |
596 | if (ret) | |
597 | goto end; | |
598 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | |
599 | (void) nb->notifier_call(nb, MODULE_STATE_COMING, tp_mod); | |
600 | end: | |
601 | mutex_unlock(&tracepoint_module_list_mutex); | |
602 | return ret; | |
603 | } | |
604 | EXPORT_SYMBOL_GPL(register_tracepoint_module_notifier); | |
605 | ||
606 | /** | |
bd740953 | 607 | * unregister_tracepoint_module_notifier - unregister tracepoint coming/going notifier |
de7b2973 MD |
608 | * @nb: notifier block |
609 | * | |
610 | * The notifier block callback should expect a "struct tp_module" data | |
611 | * pointer. | |
612 | */ | |
613 | int unregister_tracepoint_module_notifier(struct notifier_block *nb) | |
614 | { | |
615 | struct tp_module *tp_mod; | |
616 | int ret; | |
617 | ||
618 | mutex_lock(&tracepoint_module_list_mutex); | |
619 | ret = blocking_notifier_chain_unregister(&tracepoint_notify_list, nb); | |
620 | if (ret) | |
621 | goto end; | |
622 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | |
623 | (void) nb->notifier_call(nb, MODULE_STATE_GOING, tp_mod); | |
624 | end: | |
625 | mutex_unlock(&tracepoint_module_list_mutex); | |
626 | return ret; | |
627 | ||
628 | } | |
629 | EXPORT_SYMBOL_GPL(unregister_tracepoint_module_notifier); | |
630 | ||
631 | /* | |
632 | * Ensure the tracer unregistered the module's probes before the module | |
633 | * teardown is performed. Prevents leaks of probe and data pointers. | |
634 | */ | |
46e0c9be | 635 | static void tp_module_going_check_quiescent(struct tracepoint *tp, void *priv) |
de7b2973 | 636 | { |
46e0c9be | 637 | WARN_ON_ONCE(tp->funcs); |
de7b2973 MD |
638 | } |
639 | ||
b75ef8b4 MD |
640 | static int tracepoint_module_coming(struct module *mod) |
641 | { | |
0dea6d52 | 642 | struct tp_module *tp_mod; |
b75ef8b4 | 643 | |
7dec935a SRRH |
644 | if (!mod->num_tracepoints) |
645 | return 0; | |
646 | ||
b75ef8b4 | 647 | /* |
c10076c4 SR |
648 | * We skip modules that taint the kernel, especially those with different |
649 | * module headers (for forced load), to make sure we don't cause a crash. | |
54be5509 | 650 | * Staging, out-of-tree, unsigned GPL, and test modules are fine. |
b75ef8b4 | 651 | */ |
45ab2813 | 652 | if (trace_module_has_bad_taint(mod)) |
b75ef8b4 | 653 | return 0; |
51714678 | 654 | |
b75ef8b4 | 655 | tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); |
51714678 ZL |
656 | if (!tp_mod) |
657 | return -ENOMEM; | |
eb7d035c | 658 | tp_mod->mod = mod; |
51714678 ZL |
659 | |
660 | mutex_lock(&tracepoint_module_list_mutex); | |
0dea6d52 | 661 | list_add_tail(&tp_mod->list, &tracepoint_module_list); |
de7b2973 MD |
662 | blocking_notifier_call_chain(&tracepoint_notify_list, |
663 | MODULE_STATE_COMING, tp_mod); | |
de7b2973 | 664 | mutex_unlock(&tracepoint_module_list_mutex); |
51714678 | 665 | return 0; |
b75ef8b4 MD |
666 | } |
667 | ||
de7b2973 | 668 | static void tracepoint_module_going(struct module *mod) |
b75ef8b4 | 669 | { |
de7b2973 | 670 | struct tp_module *tp_mod; |
b75ef8b4 | 671 | |
7dec935a | 672 | if (!mod->num_tracepoints) |
de7b2973 | 673 | return; |
7dec935a | 674 | |
de7b2973 MD |
675 | mutex_lock(&tracepoint_module_list_mutex); |
676 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) { | |
eb7d035c | 677 | if (tp_mod->mod == mod) { |
de7b2973 MD |
678 | blocking_notifier_call_chain(&tracepoint_notify_list, |
679 | MODULE_STATE_GOING, tp_mod); | |
680 | list_del(&tp_mod->list); | |
681 | kfree(tp_mod); | |
682 | /* | |
683 | * Called the going notifier before checking for | |
684 | * quiescence. | |
685 | */ | |
46e0c9be AB |
686 | for_each_tracepoint_range(mod->tracepoints_ptrs, |
687 | mod->tracepoints_ptrs + mod->num_tracepoints, | |
688 | tp_module_going_check_quiescent, NULL); | |
b75ef8b4 MD |
689 | break; |
690 | } | |
691 | } | |
692 | /* | |
693 | * In the case of modules that were tainted at "coming", we'll simply | |
694 | * walk through the list without finding it. We cannot use the "tainted" | |
695 | * flag on "going", in case a module taints the kernel only after being | |
696 | * loaded. | |
697 | */ | |
de7b2973 | 698 | mutex_unlock(&tracepoint_module_list_mutex); |
b75ef8b4 | 699 | } |
227a8375 | 700 | |
de7b2973 MD |
701 | static int tracepoint_module_notify(struct notifier_block *self, |
702 | unsigned long val, void *data) | |
32f85742 MD |
703 | { |
704 | struct module *mod = data; | |
b75ef8b4 | 705 | int ret = 0; |
32f85742 MD |
706 | |
707 | switch (val) { | |
708 | case MODULE_STATE_COMING: | |
b75ef8b4 MD |
709 | ret = tracepoint_module_coming(mod); |
710 | break; | |
711 | case MODULE_STATE_LIVE: | |
712 | break; | |
32f85742 | 713 | case MODULE_STATE_GOING: |
de7b2973 MD |
714 | tracepoint_module_going(mod); |
715 | break; | |
716 | case MODULE_STATE_UNFORMED: | |
32f85742 MD |
717 | break; |
718 | } | |
0340a6b7 | 719 | return notifier_from_errno(ret); |
32f85742 MD |
720 | } |
721 | ||
de7b2973 | 722 | static struct notifier_block tracepoint_module_nb = { |
32f85742 MD |
723 | .notifier_call = tracepoint_module_notify, |
724 | .priority = 0, | |
725 | }; | |
726 | ||
de7b2973 | 727 | static __init int init_tracepoints(void) |
32f85742 | 728 | { |
de7b2973 MD |
729 | int ret; |
730 | ||
731 | ret = register_module_notifier(&tracepoint_module_nb); | |
eb7d035c | 732 | if (ret) |
a395d6a7 | 733 | pr_warn("Failed to register tracepoint module enter notifier\n"); |
eb7d035c | 734 | |
de7b2973 | 735 | return ret; |
32f85742 MD |
736 | } |
737 | __initcall(init_tracepoints); | |
227a8375 | 738 | #endif /* CONFIG_MODULES */ |
a871bd33 | 739 | |
de7b2973 MD |
740 | /** |
741 | * for_each_kernel_tracepoint - iteration on all kernel tracepoints | |
742 | * @fct: callback | |
743 | * @priv: private data | |
744 | */ | |
745 | void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), | |
746 | void *priv) | |
747 | { | |
748 | for_each_tracepoint_range(__start___tracepoints_ptrs, | |
749 | __stop___tracepoints_ptrs, fct, priv); | |
750 | } | |
751 | EXPORT_SYMBOL_GPL(for_each_kernel_tracepoint); | |
752 | ||
3d27d8cb | 753 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |
60d970c2 | 754 | |
97419875 | 755 | /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ |
a871bd33 JB |
756 | static int sys_tracepoint_refcount; |
757 | ||
8cf868af | 758 | int syscall_regfunc(void) |
a871bd33 | 759 | { |
8063e41d | 760 | struct task_struct *p, *t; |
a871bd33 | 761 | |
a871bd33 | 762 | if (!sys_tracepoint_refcount) { |
8063e41d ON |
763 | read_lock(&tasklist_lock); |
764 | for_each_process_thread(p, t) { | |
524666cb | 765 | set_task_syscall_work(t, SYSCALL_TRACEPOINT); |
8063e41d ON |
766 | } |
767 | read_unlock(&tasklist_lock); | |
a871bd33 JB |
768 | } |
769 | sys_tracepoint_refcount++; | |
8cf868af SRRH |
770 | |
771 | return 0; | |
a871bd33 JB |
772 | } |
773 | ||
774 | void syscall_unregfunc(void) | |
775 | { | |
8063e41d | 776 | struct task_struct *p, *t; |
a871bd33 | 777 | |
a871bd33 JB |
778 | sys_tracepoint_refcount--; |
779 | if (!sys_tracepoint_refcount) { | |
8063e41d ON |
780 | read_lock(&tasklist_lock); |
781 | for_each_process_thread(p, t) { | |
524666cb | 782 | clear_task_syscall_work(t, SYSCALL_TRACEPOINT); |
8063e41d ON |
783 | } |
784 | read_unlock(&tasklist_lock); | |
a871bd33 | 785 | } |
a871bd33 | 786 | } |
60d970c2 | 787 | #endif |