Blame view
kernel/tracepoint.c
15.6 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
97e1c18e8 tracing: Kernel T... |
2 |
/* |
de7b29739 tracepoint: Use s... |
3 |
* Copyright (C) 2008-2014 Mathieu Desnoyers |
97e1c18e8 tracing: Kernel T... |
4 5 6 7 8 9 10 11 12 13 |
*/ #include <linux/module.h> #include <linux/mutex.h> #include <linux/types.h> #include <linux/jhash.h> #include <linux/list.h> #include <linux/rcupdate.h> #include <linux/tracepoint.h> #include <linux/err.h> #include <linux/slab.h> |
3f07c0144 sched/headers: Pr... |
14 |
#include <linux/sched/signal.h> |
299300258 sched/headers: Pr... |
15 |
#include <linux/sched/task.h> |
c5905afb0 static keys: Intr... |
16 |
#include <linux/static_key.h> |
97e1c18e8 tracing: Kernel T... |
17 |
|
9c0be3f6b tracepoint: Fix t... |
18 19 |
extern tracepoint_ptr_t __start___tracepoints_ptrs[]; extern tracepoint_ptr_t __stop___tracepoints_ptrs[]; |
97e1c18e8 tracing: Kernel T... |
20 |
|
e6753f23d tracepoint: Make ... |
21 22 |
DEFINE_SRCU(tracepoint_srcu); EXPORT_SYMBOL_GPL(tracepoint_srcu); |
97e1c18e8 tracing: Kernel T... |
23 24 |
/* Set to 1 to enable tracepoint debug output */ static const int tracepoint_debug; |
de7b29739 tracepoint: Use s... |
25 |
#ifdef CONFIG_MODULES |
97e1c18e8 tracing: Kernel T... |
26 |
/* |
de7b29739 tracepoint: Use s... |
27 |
* Tracepoint module list mutex protects the local module list. |
97e1c18e8 tracing: Kernel T... |
28 |
*/ |
de7b29739 tracepoint: Use s... |
29 |
static DEFINE_MUTEX(tracepoint_module_list_mutex); |
97e1c18e8 tracing: Kernel T... |
30 |
|
de7b29739 tracepoint: Use s... |
31 |
/* Local list of struct tp_module */ |
b75ef8b44 Tracepoint: Disso... |
32 33 |
static LIST_HEAD(tracepoint_module_list); #endif /* CONFIG_MODULES */ |
97e1c18e8 tracing: Kernel T... |
34 |
/* |
de7b29739 tracepoint: Use s... |
35 36 |
* tracepoints_mutex protects the builtin and module tracepoints. * tracepoints_mutex nests inside tracepoint_module_list_mutex. |
97e1c18e8 tracing: Kernel T... |
37 |
*/ |
de7b29739 tracepoint: Use s... |
38 |
static DEFINE_MUTEX(tracepoints_mutex); |
97e1c18e8 tracing: Kernel T... |
39 |
|
f8a79d5c7 tracepoints: Free... |
40 41 |
static struct rcu_head *early_probes; static bool ok_to_free_tracepoints; |
97e1c18e8 tracing: Kernel T... |
42 43 |
/* * Note about RCU : |
fd589a8f0 trivial: fix typo... |
44 |
* It is used to delay the free of multiple probes array until a quiescent |
97e1c18e8 tracing: Kernel T... |
45 |
* state is reached. |
97e1c18e8 tracing: Kernel T... |
46 |
*/ |
19dba33c4 tracepoint: simpl... |
47 |
struct tp_probes { |
0dea6d526 tracepoint: Remov... |
48 |
struct rcu_head rcu; |
9d0a49c70 tracepoint: Repla... |
49 |
struct tracepoint_func probes[]; |
19dba33c4 tracepoint: simpl... |
50 |
}; |
97e1c18e8 tracing: Kernel T... |
51 |
|
19dba33c4 tracepoint: simpl... |
52 |
static inline void *allocate_probes(int count) |
97e1c18e8 tracing: Kernel T... |
53 |
{ |
f0553dcb9 tracepoint: Use s... |
54 55 |
struct tp_probes *p = kmalloc(struct_size(p, probes, count), GFP_KERNEL); |
19dba33c4 tracepoint: simpl... |
56 |
return p == NULL ? NULL : p->probes; |
97e1c18e8 tracing: Kernel T... |
57 |
} |
e6753f23d tracepoint: Make ... |
58 |
static void srcu_free_old_probes(struct rcu_head *head) |
97e1c18e8 tracing: Kernel T... |
59 |
{ |
0dea6d526 tracepoint: Remov... |
60 |
kfree(container_of(head, struct tp_probes, rcu)); |
19dba33c4 tracepoint: simpl... |
61 |
} |
e6753f23d tracepoint: Make ... |
62 63 64 65 |
static void rcu_free_old_probes(struct rcu_head *head) { call_srcu(&tracepoint_srcu, head, srcu_free_old_probes); } |
f8a79d5c7 tracepoints: Free... |
66 67 68 69 70 71 72 73 74 |
static __init int release_early_probes(void) { struct rcu_head *tmp; ok_to_free_tracepoints = true; while (early_probes) { tmp = early_probes; early_probes = tmp->next; |
744017297 tracing: Replace ... |
75 |
call_rcu(tmp, rcu_free_old_probes); |
f8a79d5c7 tracepoints: Free... |
76 77 78 79 80 81 82 |
} return 0; } /* SRCU is initialized at core_initcall */ postcore_initcall(release_early_probes); |
38516ab59 tracing: Let trac... |
83 |
static inline void release_probes(struct tracepoint_func *old) |
19dba33c4 tracepoint: simpl... |
84 85 86 87 |
{ if (old) { struct tp_probes *tp_probes = container_of(old, struct tp_probes, probes[0]); |
f8a79d5c7 tracepoints: Free... |
88 89 90 91 92 93 94 95 96 97 |
/* * We can't free probes if SRCU is not initialized yet. * Postpone the freeing till after SRCU is initialized. */ if (unlikely(!ok_to_free_tracepoints)) { tp_probes->rcu.next = early_probes; early_probes = &tp_probes->rcu; return; } |
e6753f23d tracepoint: Make ... |
98 99 100 101 102 103 |
/* * Tracepoint probes are protected by both sched RCU and SRCU, * by calling the SRCU callback in the sched RCU callback we * cover both cases. So let us chain the SRCU and sched RCU * callbacks to wait for both grace periods. */ |
744017297 tracing: Replace ... |
104 |
call_rcu(&tp_probes->rcu, rcu_free_old_probes); |
19dba33c4 tracepoint: simpl... |
105 |
} |
97e1c18e8 tracing: Kernel T... |
106 |
} |
de7b29739 tracepoint: Use s... |
107 |
static void debug_print_probes(struct tracepoint_func *funcs) |
97e1c18e8 tracing: Kernel T... |
108 109 |
{ int i; |
de7b29739 tracepoint: Use s... |
110 |
if (!tracepoint_debug || !funcs) |
97e1c18e8 tracing: Kernel T... |
111 |
return; |
de7b29739 tracepoint: Use s... |
112 113 114 |
for (i = 0; funcs[i].func; i++) printk(KERN_DEBUG "Probe %d : %p ", i, funcs[i].func); |
97e1c18e8 tracing: Kernel T... |
115 |
} |
7904b5c49 tracepoint: Give ... |
116 117 118 |
static struct tracepoint_func * func_add(struct tracepoint_func **funcs, struct tracepoint_func *tp_func, int prio) |
97e1c18e8 tracing: Kernel T... |
119 |
{ |
38516ab59 tracing: Let trac... |
120 |
struct tracepoint_func *old, *new; |
7904b5c49 tracepoint: Give ... |
121 122 |
int nr_probes = 0; int pos = -1; |
97e1c18e8 tracing: Kernel T... |
123 |
|
de7b29739 tracepoint: Use s... |
124 |
if (WARN_ON(!tp_func->func)) |
4c69e6ea4 tracepoints: Prev... |
125 |
return ERR_PTR(-EINVAL); |
97e1c18e8 tracing: Kernel T... |
126 |
|
de7b29739 tracepoint: Use s... |
127 128 |
debug_print_probes(*funcs); old = *funcs; |
97e1c18e8 tracing: Kernel T... |
129 130 |
if (old) { /* (N -> N+1), (N != 0, 1) probes */ |
7904b5c49 tracepoint: Give ... |
131 132 133 134 |
for (nr_probes = 0; old[nr_probes].func; nr_probes++) { /* Insert before probes of lower priority */ if (pos < 0 && old[nr_probes].prio < prio) pos = nr_probes; |
de7b29739 tracepoint: Use s... |
135 136 |
if (old[nr_probes].func == tp_func->func && old[nr_probes].data == tp_func->data) |
97e1c18e8 tracing: Kernel T... |
137 |
return ERR_PTR(-EEXIST); |
7904b5c49 tracepoint: Give ... |
138 |
} |
97e1c18e8 tracing: Kernel T... |
139 140 |
} /* + 2 : one for new probe, one for NULL func */ |
19dba33c4 tracepoint: simpl... |
141 |
new = allocate_probes(nr_probes + 2); |
97e1c18e8 tracing: Kernel T... |
142 143 |
if (new == NULL) return ERR_PTR(-ENOMEM); |
7904b5c49 tracepoint: Give ... |
144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
if (old) { if (pos < 0) { pos = nr_probes; memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); } else { /* Copy higher priority probes ahead of the new probe */ memcpy(new, old, pos * sizeof(struct tracepoint_func)); /* Copy the rest after it. */ memcpy(new + pos + 1, old + pos, (nr_probes - pos) * sizeof(struct tracepoint_func)); } } else pos = 0; new[pos] = *tp_func; |
38516ab59 tracing: Let trac... |
158 |
new[nr_probes + 1].func = NULL; |
de7b29739 tracepoint: Use s... |
159 160 |
*funcs = new; debug_print_probes(*funcs); |
97e1c18e8 tracing: Kernel T... |
161 162 |
return old; } |
de7b29739 tracepoint: Use s... |
163 164 |
static void *func_remove(struct tracepoint_func **funcs, struct tracepoint_func *tp_func) |
97e1c18e8 tracing: Kernel T... |
165 166 |
{ int nr_probes = 0, nr_del = 0, i; |
38516ab59 tracing: Let trac... |
167 |
struct tracepoint_func *old, *new; |
97e1c18e8 tracing: Kernel T... |
168 |
|
de7b29739 tracepoint: Use s... |
169 |
old = *funcs; |
97e1c18e8 tracing: Kernel T... |
170 |
|
f66af459a tracepoint: check... |
171 |
if (!old) |
19dba33c4 tracepoint: simpl... |
172 |
return ERR_PTR(-ENOENT); |
f66af459a tracepoint: check... |
173 |
|
de7b29739 tracepoint: Use s... |
174 |
debug_print_probes(*funcs); |
97e1c18e8 tracing: Kernel T... |
175 |
/* (N -> M), (N > 1, M >= 0) probes */ |
de7b29739 tracepoint: Use s... |
176 |
if (tp_func->func) { |
4c69e6ea4 tracepoints: Prev... |
177 |
for (nr_probes = 0; old[nr_probes].func; nr_probes++) { |
de7b29739 tracepoint: Use s... |
178 179 |
if (old[nr_probes].func == tp_func->func && old[nr_probes].data == tp_func->data) |
4c69e6ea4 tracepoints: Prev... |
180 181 |
nr_del++; } |
97e1c18e8 tracing: Kernel T... |
182 |
} |
4c69e6ea4 tracepoints: Prev... |
183 184 185 186 |
/* * If probe is NULL, then nr_probes = nr_del = 0, and then the * entire entry will be removed. */ |
97e1c18e8 tracing: Kernel T... |
187 188 |
if (nr_probes - nr_del == 0) { /* N -> 0, (N > 1) */ |
de7b29739 tracepoint: Use s... |
189 190 |
*funcs = NULL; debug_print_probes(*funcs); |
97e1c18e8 tracing: Kernel T... |
191 192 193 194 195 |
return old; } else { int j = 0; /* N -> M, (N > 1, M > 0) */ /* + 1 for NULL */ |
19dba33c4 tracepoint: simpl... |
196 |
new = allocate_probes(nr_probes - nr_del + 1); |
97e1c18e8 tracing: Kernel T... |
197 198 |
if (new == NULL) return ERR_PTR(-ENOMEM); |
38516ab59 tracing: Let trac... |
199 |
for (i = 0; old[i].func; i++) |
de7b29739 tracepoint: Use s... |
200 201 |
if (old[i].func != tp_func->func || old[i].data != tp_func->data) |
97e1c18e8 tracing: Kernel T... |
202 |
new[j++] = old[i]; |
38516ab59 tracing: Let trac... |
203 |
new[nr_probes - nr_del].func = NULL; |
de7b29739 tracepoint: Use s... |
204 |
*funcs = new; |
97e1c18e8 tracing: Kernel T... |
205 |
} |
de7b29739 tracepoint: Use s... |
206 |
debug_print_probes(*funcs); |
97e1c18e8 tracing: Kernel T... |
207 208 |
return old; } |
547305a64 tracepoint: Fix o... |
209 |
static void tracepoint_update_call(struct tracepoint *tp, struct tracepoint_func *tp_funcs, bool sync) |
d25e37d89 tracepoint: Optim... |
210 211 212 213 214 215 |
{ void *func = tp->iterator; /* Synthetic events do not have static call sites */ if (!tp->static_call_key) return; |
547305a64 tracepoint: Fix o... |
216 |
if (!tp_funcs[1].func) { |
d25e37d89 tracepoint: Optim... |
217 |
func = tp_funcs[0].func; |
547305a64 tracepoint: Fix o... |
218 219 220 221 222 223 224 225 226 |
/* * If going from the iterator back to a single caller, * we need to synchronize with __DO_TRACE to make sure * that the data passed to the callback is the one that * belongs to that callback. */ if (sync) tracepoint_synchronize_unregister(); } |
d25e37d89 tracepoint: Optim... |
227 228 229 |
__static_call_update(tp->static_call_key, tp->static_call_tramp, func); } |
97e1c18e8 tracing: Kernel T... |
230 |
/* |
de7b29739 tracepoint: Use s... |
231 |
* Add the probe function to a tracepoint. |
97e1c18e8 tracing: Kernel T... |
232 |
*/ |
de7b29739 tracepoint: Use s... |
233 |
static int tracepoint_add_func(struct tracepoint *tp, |
7904b5c49 tracepoint: Give ... |
234 |
struct tracepoint_func *func, int prio) |
97e1c18e8 tracing: Kernel T... |
235 |
{ |
de7b29739 tracepoint: Use s... |
236 |
struct tracepoint_func *old, *tp_funcs; |
8cf868aff tracing: Have the... |
237 |
int ret; |
97e1c18e8 tracing: Kernel T... |
238 |
|
8cf868aff tracing: Have the... |
239 240 241 242 243 |
if (tp->regfunc && !static_key_enabled(&tp->key)) { ret = tp->regfunc(); if (ret < 0) return ret; } |
97e1c18e8 tracing: Kernel T... |
244 |
|
b725dfea2 tracepoint: Fix s... |
245 246 |
tp_funcs = rcu_dereference_protected(tp->funcs, lockdep_is_held(&tracepoints_mutex)); |
7904b5c49 tracepoint: Give ... |
247 |
old = func_add(&tp_funcs, func, prio); |
de7b29739 tracepoint: Use s... |
248 |
if (IS_ERR(old)) { |
d66a270be tracepoint: Do no... |
249 |
WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); |
de7b29739 tracepoint: Use s... |
250 251 |
return PTR_ERR(old); } |
974198758 tracing: Move tra... |
252 |
|
97e1c18e8 tracing: Kernel T... |
253 |
/* |
243d1a797 tracepoint: Remov... |
254 255 256 257 |
* rcu_assign_pointer has as smp_store_release() which makes sure * that the new probe callbacks array is consistent before setting * a pointer to it. This array is referenced by __DO_TRACE from * include/linux/tracepoint.h using rcu_dereference_sched(). |
97e1c18e8 tracing: Kernel T... |
258 |
*/ |
de7b29739 tracepoint: Use s... |
259 |
rcu_assign_pointer(tp->funcs, tp_funcs); |
547305a64 tracepoint: Fix o... |
260 |
tracepoint_update_call(tp, tp_funcs, false); |
d25e37d89 tracepoint: Optim... |
261 |
static_key_enable(&tp->key); |
8058bd0fa tracepoint: Fix u... |
262 |
release_probes(old); |
de7b29739 tracepoint: Use s... |
263 |
return 0; |
97e1c18e8 tracing: Kernel T... |
264 265 266 |
} /* |
de7b29739 tracepoint: Use s... |
267 |
* Remove a probe function from a tracepoint. |
97e1c18e8 tracing: Kernel T... |
268 269 270 271 |
* Note: only waiting an RCU period after setting elem->call to the empty * function insures that the original callback is not used anymore. This insured * by preempt_disable around the call site. */ |
de7b29739 tracepoint: Use s... |
272 273 |
static int tracepoint_remove_func(struct tracepoint *tp, struct tracepoint_func *func) |
97e1c18e8 tracing: Kernel T... |
274 |
{ |
de7b29739 tracepoint: Use s... |
275 |
struct tracepoint_func *old, *tp_funcs; |
97e1c18e8 tracing: Kernel T... |
276 |
|
b725dfea2 tracepoint: Fix s... |
277 278 |
tp_funcs = rcu_dereference_protected(tp->funcs, lockdep_is_held(&tracepoints_mutex)); |
de7b29739 tracepoint: Use s... |
279 280 |
old = func_remove(&tp_funcs, func); if (IS_ERR(old)) { |
d66a270be tracepoint: Do no... |
281 |
WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); |
de7b29739 tracepoint: Use s... |
282 |
return PTR_ERR(old); |
97e1c18e8 tracing: Kernel T... |
283 |
} |
b75ef8b44 Tracepoint: Disso... |
284 |
|
de7b29739 tracepoint: Use s... |
285 286 287 288 |
if (!tp_funcs) { /* Removed last function */ if (tp->unregfunc && static_key_enabled(&tp->key)) tp->unregfunc(); |
b75ef8b44 Tracepoint: Disso... |
289 |
|
d25e37d89 tracepoint: Optim... |
290 |
static_key_disable(&tp->key); |
547305a64 tracepoint: Fix o... |
291 |
rcu_assign_pointer(tp->funcs, tp_funcs); |
d25e37d89 tracepoint: Optim... |
292 |
} else { |
547305a64 tracepoint: Fix o... |
293 294 295 |
rcu_assign_pointer(tp->funcs, tp_funcs); tracepoint_update_call(tp, tp_funcs, tp_funcs[0].func != old[0].func); |
127cafbb2 tracepoint: intro... |
296 |
} |
8058bd0fa tracepoint: Fix u... |
297 |
release_probes(old); |
de7b29739 tracepoint: Use s... |
298 |
return 0; |
127cafbb2 tracepoint: intro... |
299 |
} |
97e1c18e8 tracing: Kernel T... |
300 |
/** |
f39e23910 tracepoints: Fix ... |
301 |
* tracepoint_probe_register_prio - Connect a probe to a tracepoint with priority |
de7b29739 tracepoint: Use s... |
302 |
* @tp: tracepoint |
97e1c18e8 tracing: Kernel T... |
303 |
* @probe: probe handler |
cac92ba74 kernel/tracepoint... |
304 |
* @data: tracepoint data |
7904b5c49 tracepoint: Give ... |
305 |
* @prio: priority of this function over other registered functions |
97e1c18e8 tracing: Kernel T... |
306 |
* |
de7b29739 tracepoint: Use s... |
307 308 309 310 311 |
* Returns 0 if ok, error value on error. * Note: if @tp is within a module, the caller is responsible for * unregistering the probe before the module is gone. This can be * performed either with a tracepoint module going notifier, or from * within module exit functions. |
97e1c18e8 tracing: Kernel T... |
312 |
*/ |
7904b5c49 tracepoint: Give ... |
313 314 |
int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, int prio) |
97e1c18e8 tracing: Kernel T... |
315 |
{ |
de7b29739 tracepoint: Use s... |
316 317 |
struct tracepoint_func tp_func; int ret; |
97e1c18e8 tracing: Kernel T... |
318 319 |
mutex_lock(&tracepoints_mutex); |
de7b29739 tracepoint: Use s... |
320 321 |
tp_func.func = probe; tp_func.data = data; |
7904b5c49 tracepoint: Give ... |
322 323 |
tp_func.prio = prio; ret = tracepoint_add_func(tp, &tp_func, prio); |
b75ef8b44 Tracepoint: Disso... |
324 |
mutex_unlock(&tracepoints_mutex); |
b196e2b9e tracing: Warn if ... |
325 |
return ret; |
97e1c18e8 tracing: Kernel T... |
326 |
} |
7904b5c49 tracepoint: Give ... |
327 328 329 330 331 332 333 |
EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio); /** * tracepoint_probe_register - Connect a probe to a tracepoint * @tp: tracepoint * @probe: probe handler * @data: tracepoint data |
7904b5c49 tracepoint: Give ... |
334 335 336 337 338 339 340 341 342 343 344 |
* * Returns 0 if ok, error value on error. * Note: if @tp is within a module, the caller is responsible for * unregistering the probe before the module is gone. This can be * performed either with a tracepoint module going notifier, or from * within module exit functions. */ int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) { return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO); } |
97e1c18e8 tracing: Kernel T... |
345 346 347 348 |
EXPORT_SYMBOL_GPL(tracepoint_probe_register); /** * tracepoint_probe_unregister - Disconnect a probe from a tracepoint |
de7b29739 tracepoint: Use s... |
349 |
* @tp: tracepoint |
97e1c18e8 tracing: Kernel T... |
350 |
* @probe: probe function pointer |
cac92ba74 kernel/tracepoint... |
351 |
* @data: tracepoint data |
97e1c18e8 tracing: Kernel T... |
352 |
* |
de7b29739 tracepoint: Use s... |
353 |
* Returns 0 if ok, error value on error. |
97e1c18e8 tracing: Kernel T... |
354 |
*/ |
de7b29739 tracepoint: Use s... |
355 |
int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data) |
97e1c18e8 tracing: Kernel T... |
356 |
{ |
de7b29739 tracepoint: Use s... |
357 358 |
struct tracepoint_func tp_func; int ret; |
97e1c18e8 tracing: Kernel T... |
359 360 |
mutex_lock(&tracepoints_mutex); |
de7b29739 tracepoint: Use s... |
361 362 363 |
tp_func.func = probe; tp_func.data = data; ret = tracepoint_remove_func(tp, &tp_func); |
b75ef8b44 Tracepoint: Disso... |
364 |
mutex_unlock(&tracepoints_mutex); |
de7b29739 tracepoint: Use s... |
365 |
return ret; |
97e1c18e8 tracing: Kernel T... |
366 367 |
} EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); |
9c0be3f6b tracepoint: Fix t... |
368 369 |
static void for_each_tracepoint_range( tracepoint_ptr_t *begin, tracepoint_ptr_t *end, |
46e0c9be2 kernel: tracepoin... |
370 371 372 |
void (*fct)(struct tracepoint *tp, void *priv), void *priv) { |
9c0be3f6b tracepoint: Fix t... |
373 |
tracepoint_ptr_t *iter; |
46e0c9be2 kernel: tracepoin... |
374 375 |
if (!begin) return; |
9c0be3f6b tracepoint: Fix t... |
376 377 |
for (iter = begin; iter < end; iter++) fct(tracepoint_ptr_deref(iter), priv); |
46e0c9be2 kernel: tracepoin... |
378 |
} |
227a83756 markers/tracpoint... |
379 |
#ifdef CONFIG_MODULES |
45ab2813d tracing: Do not a... |
380 381 |
bool trace_module_has_bad_taint(struct module *mod) { |
66cc69e34 Fix: module signa... |
382 383 |
return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | (1 << TAINT_UNSIGNED_MODULE)); |
45ab2813d tracing: Do not a... |
384 |
} |
de7b29739 tracepoint: Use s... |
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); /** * register_tracepoint_notifier - register tracepoint coming/going notifier * @nb: notifier block * * Notifiers registered with this function are called on module * coming/going with the tracepoint_module_list_mutex held. * The notifier block callback should expect a "struct tp_module" data * pointer. */ int register_tracepoint_module_notifier(struct notifier_block *nb) { struct tp_module *tp_mod; int ret; mutex_lock(&tracepoint_module_list_mutex); ret = blocking_notifier_chain_register(&tracepoint_notify_list, nb); if (ret) goto end; list_for_each_entry(tp_mod, &tracepoint_module_list, list) (void) nb->notifier_call(nb, MODULE_STATE_COMING, tp_mod); end: mutex_unlock(&tracepoint_module_list_mutex); return ret; } EXPORT_SYMBOL_GPL(register_tracepoint_module_notifier); /** * unregister_tracepoint_notifier - unregister tracepoint coming/going notifier * @nb: notifier block * * The notifier block callback should expect a "struct tp_module" data * pointer. */ int unregister_tracepoint_module_notifier(struct notifier_block *nb) { struct tp_module *tp_mod; int ret; mutex_lock(&tracepoint_module_list_mutex); ret = blocking_notifier_chain_unregister(&tracepoint_notify_list, nb); if (ret) goto end; list_for_each_entry(tp_mod, &tracepoint_module_list, list) (void) nb->notifier_call(nb, MODULE_STATE_GOING, tp_mod); end: mutex_unlock(&tracepoint_module_list_mutex); return ret; } EXPORT_SYMBOL_GPL(unregister_tracepoint_module_notifier); /* * Ensure the tracer unregistered the module's probes before the module * teardown is performed. Prevents leaks of probe and data pointers. */ |
46e0c9be2 kernel: tracepoin... |
442 |
static void tp_module_going_check_quiescent(struct tracepoint *tp, void *priv) |
de7b29739 tracepoint: Use s... |
443 |
{ |
46e0c9be2 kernel: tracepoin... |
444 |
WARN_ON_ONCE(tp->funcs); |
de7b29739 tracepoint: Use s... |
445 |
} |
b75ef8b44 Tracepoint: Disso... |
446 447 |
static int tracepoint_module_coming(struct module *mod) { |
0dea6d526 tracepoint: Remov... |
448 |
struct tp_module *tp_mod; |
b75ef8b44 Tracepoint: Disso... |
449 |
int ret = 0; |
7dec935a3 tracepoint: Do no... |
450 451 |
if (!mod->num_tracepoints) return 0; |
b75ef8b44 Tracepoint: Disso... |
452 |
/* |
c10076c43 tracepoints/modul... |
453 454 |
* We skip modules that taint the kernel, especially those with different * module headers (for forced load), to make sure we don't cause a crash. |
66cc69e34 Fix: module signa... |
455 |
* Staging, out-of-tree, and unsigned GPL modules are fine. |
b75ef8b44 Tracepoint: Disso... |
456 |
*/ |
45ab2813d tracing: Do not a... |
457 |
if (trace_module_has_bad_taint(mod)) |
b75ef8b44 Tracepoint: Disso... |
458 |
return 0; |
de7b29739 tracepoint: Use s... |
459 |
mutex_lock(&tracepoint_module_list_mutex); |
b75ef8b44 Tracepoint: Disso... |
460 461 462 463 464 |
tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); if (!tp_mod) { ret = -ENOMEM; goto end; } |
eb7d035c5 tracepoint: Simpl... |
465 |
tp_mod->mod = mod; |
0dea6d526 tracepoint: Remov... |
466 |
list_add_tail(&tp_mod->list, &tracepoint_module_list); |
de7b29739 tracepoint: Use s... |
467 468 |
blocking_notifier_call_chain(&tracepoint_notify_list, MODULE_STATE_COMING, tp_mod); |
b75ef8b44 Tracepoint: Disso... |
469 |
end: |
de7b29739 tracepoint: Use s... |
470 |
mutex_unlock(&tracepoint_module_list_mutex); |
b75ef8b44 Tracepoint: Disso... |
471 472 |
return ret; } |
de7b29739 tracepoint: Use s... |
473 |
static void tracepoint_module_going(struct module *mod) |
b75ef8b44 Tracepoint: Disso... |
474 |
{ |
de7b29739 tracepoint: Use s... |
475 |
struct tp_module *tp_mod; |
b75ef8b44 Tracepoint: Disso... |
476 |
|
7dec935a3 tracepoint: Do no... |
477 |
if (!mod->num_tracepoints) |
de7b29739 tracepoint: Use s... |
478 |
return; |
7dec935a3 tracepoint: Do no... |
479 |
|
de7b29739 tracepoint: Use s... |
480 481 |
mutex_lock(&tracepoint_module_list_mutex); list_for_each_entry(tp_mod, &tracepoint_module_list, list) { |
eb7d035c5 tracepoint: Simpl... |
482 |
if (tp_mod->mod == mod) { |
de7b29739 tracepoint: Use s... |
483 484 485 486 487 488 489 490 |
blocking_notifier_call_chain(&tracepoint_notify_list, MODULE_STATE_GOING, tp_mod); list_del(&tp_mod->list); kfree(tp_mod); /* * Called the going notifier before checking for * quiescence. */ |
46e0c9be2 kernel: tracepoin... |
491 492 493 |
for_each_tracepoint_range(mod->tracepoints_ptrs, mod->tracepoints_ptrs + mod->num_tracepoints, tp_module_going_check_quiescent, NULL); |
b75ef8b44 Tracepoint: Disso... |
494 495 496 497 498 499 500 501 502 |
break; } } /* * In the case of modules that were tainted at "coming", we'll simply * walk through the list without finding it. We cannot use the "tainted" * flag on "going", in case a module taints the kernel only after being * loaded. */ |
de7b29739 tracepoint: Use s... |
503 |
mutex_unlock(&tracepoint_module_list_mutex); |
b75ef8b44 Tracepoint: Disso... |
504 |
} |
227a83756 markers/tracpoint... |
505 |
|
de7b29739 tracepoint: Use s... |
506 507 |
static int tracepoint_module_notify(struct notifier_block *self, unsigned long val, void *data) |
32f857427 tracepoints: use ... |
508 509 |
{ struct module *mod = data; |
b75ef8b44 Tracepoint: Disso... |
510 |
int ret = 0; |
32f857427 tracepoints: use ... |
511 512 513 |
switch (val) { case MODULE_STATE_COMING: |
b75ef8b44 Tracepoint: Disso... |
514 515 516 517 |
ret = tracepoint_module_coming(mod); break; case MODULE_STATE_LIVE: break; |
32f857427 tracepoints: use ... |
518 |
case MODULE_STATE_GOING: |
de7b29739 tracepoint: Use s... |
519 520 521 |
tracepoint_module_going(mod); break; case MODULE_STATE_UNFORMED: |
32f857427 tracepoints: use ... |
522 523 |
break; } |
0340a6b7f module: Fix up mo... |
524 |
return notifier_from_errno(ret); |
32f857427 tracepoints: use ... |
525 |
} |
de7b29739 tracepoint: Use s... |
526 |
static struct notifier_block tracepoint_module_nb = { |
32f857427 tracepoints: use ... |
527 528 529 |
.notifier_call = tracepoint_module_notify, .priority = 0, }; |
de7b29739 tracepoint: Use s... |
530 |
static __init int init_tracepoints(void) |
32f857427 tracepoints: use ... |
531 |
{ |
de7b29739 tracepoint: Use s... |
532 533 534 |
int ret; ret = register_module_notifier(&tracepoint_module_nb); |
eb7d035c5 tracepoint: Simpl... |
535 |
if (ret) |
a395d6a7e kernel/...: conve... |
536 537 |
pr_warn("Failed to register tracepoint module enter notifier "); |
eb7d035c5 tracepoint: Simpl... |
538 |
|
de7b29739 tracepoint: Use s... |
539 |
return ret; |
32f857427 tracepoints: use ... |
540 541 |
} __initcall(init_tracepoints); |
227a83756 markers/tracpoint... |
542 |
#endif /* CONFIG_MODULES */ |
a871bd33a tracing: Add sysc... |
543 |
|
de7b29739 tracepoint: Use s... |
544 545 546 547 548 549 550 551 552 553 554 555 |
/** * for_each_kernel_tracepoint - iteration on all kernel tracepoints * @fct: callback * @priv: private data */ void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), void *priv) { for_each_tracepoint_range(__start___tracepoints_ptrs, __stop___tracepoints_ptrs, fct, priv); } EXPORT_SYMBOL_GPL(for_each_kernel_tracepoint); |
3d27d8cb3 tracing: Make sys... |
556 |
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |
60d970c25 tracing: Fix sysc... |
557 |
|
974198758 tracing: Move tra... |
558 |
/* NB: reg/unreg are called while guarded with the tracepoints_mutex */ |
a871bd33a tracing: Add sysc... |
559 |
static int sys_tracepoint_refcount; |
8cf868aff tracing: Have the... |
560 |
int syscall_regfunc(void) |
a871bd33a tracing: Add sysc... |
561 |
{ |
8063e41d2 tracing: Change s... |
562 |
struct task_struct *p, *t; |
a871bd33a tracing: Add sysc... |
563 |
|
a871bd33a tracing: Add sysc... |
564 |
if (!sys_tracepoint_refcount) { |
8063e41d2 tracing: Change s... |
565 566 |
read_lock(&tasklist_lock); for_each_process_thread(p, t) { |
ea73c79e3 tracing: syscall_... |
567 |
set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); |
8063e41d2 tracing: Change s... |
568 569 |
} read_unlock(&tasklist_lock); |
a871bd33a tracing: Add sysc... |
570 571 |
} sys_tracepoint_refcount++; |
8cf868aff tracing: Have the... |
572 573 |
return 0; |
a871bd33a tracing: Add sysc... |
574 575 576 577 |
} void syscall_unregfunc(void) { |
8063e41d2 tracing: Change s... |
578 |
struct task_struct *p, *t; |
a871bd33a tracing: Add sysc... |
579 |
|
a871bd33a tracing: Add sysc... |
580 581 |
sys_tracepoint_refcount--; if (!sys_tracepoint_refcount) { |
8063e41d2 tracing: Change s... |
582 583 |
read_lock(&tasklist_lock); for_each_process_thread(p, t) { |
667000011 tracing: Rename F... |
584 |
clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); |
8063e41d2 tracing: Change s... |
585 586 |
} read_unlock(&tasklist_lock); |
a871bd33a tracing: Add sysc... |
587 |
} |
a871bd33a tracing: Add sysc... |
588 |
} |
60d970c25 tracing: Fix sysc... |
589 |
#endif |