diff options
Diffstat (limited to 'kernel/tracepoint.c')
-rw-r--r-- | kernel/tracepoint.c | 516 |
1 files changed, 223 insertions, 293 deletions
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index fb0a38a26555..ac5b23cf7212 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2008 Mathieu Desnoyers | 2 | * Copyright (C) 2008-2014 Mathieu Desnoyers |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
@@ -33,39 +33,27 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[]; | |||
33 | /* Set to 1 to enable tracepoint debug output */ | 33 | /* Set to 1 to enable tracepoint debug output */ |
34 | static const int tracepoint_debug; | 34 | static const int tracepoint_debug; |
35 | 35 | ||
36 | #ifdef CONFIG_MODULES | ||
36 | /* | 37 | /* |
37 | * Tracepoints mutex protects the builtin and module tracepoints and the hash | 38 | * Tracepoint module list mutex protects the local module list. |
38 | * table, as well as the local module list. | ||
39 | */ | 39 | */ |
40 | static DEFINE_MUTEX(tracepoints_mutex); | 40 | static DEFINE_MUTEX(tracepoint_module_list_mutex); |
41 | 41 | ||
42 | #ifdef CONFIG_MODULES | 42 | /* Local list of struct tp_module */ |
43 | /* Local list of struct module */ | ||
44 | static LIST_HEAD(tracepoint_module_list); | 43 | static LIST_HEAD(tracepoint_module_list); |
45 | #endif /* CONFIG_MODULES */ | 44 | #endif /* CONFIG_MODULES */ |
46 | 45 | ||
47 | /* | 46 | /* |
48 | * Tracepoint hash table, containing the active tracepoints. | 47 | * tracepoints_mutex protects the builtin and module tracepoints. |
49 | * Protected by tracepoints_mutex. | 48 | * tracepoints_mutex nests inside tracepoint_module_list_mutex. |
50 | */ | 49 | */ |
51 | #define TRACEPOINT_HASH_BITS 6 | 50 | static DEFINE_MUTEX(tracepoints_mutex); |
52 | #define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS) | ||
53 | static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE]; | ||
54 | 51 | ||
55 | /* | 52 | /* |
56 | * Note about RCU : | 53 | * Note about RCU : |
57 | * It is used to delay the free of multiple probes array until a quiescent | 54 | * It is used to delay the free of multiple probes array until a quiescent |
58 | * state is reached. | 55 | * state is reached. |
59 | * Tracepoint entries modifications are protected by the tracepoints_mutex. | ||
60 | */ | 56 | */ |
61 | struct tracepoint_entry { | ||
62 | struct hlist_node hlist; | ||
63 | struct tracepoint_func *funcs; | ||
64 | int refcount; /* Number of times armed. 0 if disarmed. */ | ||
65 | int enabled; /* Tracepoint enabled */ | ||
66 | char name[0]; | ||
67 | }; | ||
68 | |||
69 | struct tp_probes { | 57 | struct tp_probes { |
70 | struct rcu_head rcu; | 58 | struct rcu_head rcu; |
71 | struct tracepoint_func probes[0]; | 59 | struct tracepoint_func probes[0]; |
@@ -92,34 +80,33 @@ static inline void release_probes(struct tracepoint_func *old) | |||
92 | } | 80 | } |
93 | } | 81 | } |
94 | 82 | ||
95 | static void debug_print_probes(struct tracepoint_entry *entry) | 83 | static void debug_print_probes(struct tracepoint_func *funcs) |
96 | { | 84 | { |
97 | int i; | 85 | int i; |
98 | 86 | ||
99 | if (!tracepoint_debug || !entry->funcs) | 87 | if (!tracepoint_debug || !funcs) |
100 | return; | 88 | return; |
101 | 89 | ||
102 | for (i = 0; entry->funcs[i].func; i++) | 90 | for (i = 0; funcs[i].func; i++) |
103 | printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i].func); | 91 | printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func); |
104 | } | 92 | } |
105 | 93 | ||
106 | static struct tracepoint_func * | 94 | static struct tracepoint_func *func_add(struct tracepoint_func **funcs, |
107 | tracepoint_entry_add_probe(struct tracepoint_entry *entry, | 95 | struct tracepoint_func *tp_func) |
108 | void *probe, void *data) | ||
109 | { | 96 | { |
110 | int nr_probes = 0; | 97 | int nr_probes = 0; |
111 | struct tracepoint_func *old, *new; | 98 | struct tracepoint_func *old, *new; |
112 | 99 | ||
113 | if (WARN_ON(!probe)) | 100 | if (WARN_ON(!tp_func->func)) |
114 | return ERR_PTR(-EINVAL); | 101 | return ERR_PTR(-EINVAL); |
115 | 102 | ||
116 | debug_print_probes(entry); | 103 | debug_print_probes(*funcs); |
117 | old = entry->funcs; | 104 | old = *funcs; |
118 | if (old) { | 105 | if (old) { |
119 | /* (N -> N+1), (N != 0, 1) probes */ | 106 | /* (N -> N+1), (N != 0, 1) probes */ |
120 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) | 107 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) |
121 | if (old[nr_probes].func == probe && | 108 | if (old[nr_probes].func == tp_func->func && |
122 | old[nr_probes].data == data) | 109 | old[nr_probes].data == tp_func->data) |
123 | return ERR_PTR(-EEXIST); | 110 | return ERR_PTR(-EEXIST); |
124 | } | 111 | } |
125 | /* + 2 : one for new probe, one for NULL func */ | 112 | /* + 2 : one for new probe, one for NULL func */ |
@@ -128,33 +115,30 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, | |||
128 | return ERR_PTR(-ENOMEM); | 115 | return ERR_PTR(-ENOMEM); |
129 | if (old) | 116 | if (old) |
130 | memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); | 117 | memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); |
131 | new[nr_probes].func = probe; | 118 | new[nr_probes] = *tp_func; |
132 | new[nr_probes].data = data; | ||
133 | new[nr_probes + 1].func = NULL; | 119 | new[nr_probes + 1].func = NULL; |
134 | entry->refcount = nr_probes + 1; | 120 | *funcs = new; |
135 | entry->funcs = new; | 121 | debug_print_probes(*funcs); |
136 | debug_print_probes(entry); | ||
137 | return old; | 122 | return old; |
138 | } | 123 | } |
139 | 124 | ||
140 | static void * | 125 | static void *func_remove(struct tracepoint_func **funcs, |
141 | tracepoint_entry_remove_probe(struct tracepoint_entry *entry, | 126 | struct tracepoint_func *tp_func) |
142 | void *probe, void *data) | ||
143 | { | 127 | { |
144 | int nr_probes = 0, nr_del = 0, i; | 128 | int nr_probes = 0, nr_del = 0, i; |
145 | struct tracepoint_func *old, *new; | 129 | struct tracepoint_func *old, *new; |
146 | 130 | ||
147 | old = entry->funcs; | 131 | old = *funcs; |
148 | 132 | ||
149 | if (!old) | 133 | if (!old) |
150 | return ERR_PTR(-ENOENT); | 134 | return ERR_PTR(-ENOENT); |
151 | 135 | ||
152 | debug_print_probes(entry); | 136 | debug_print_probes(*funcs); |
153 | /* (N -> M), (N > 1, M >= 0) probes */ | 137 | /* (N -> M), (N > 1, M >= 0) probes */ |
154 | if (probe) { | 138 | if (tp_func->func) { |
155 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) { | 139 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) { |
156 | if (old[nr_probes].func == probe && | 140 | if (old[nr_probes].func == tp_func->func && |
157 | old[nr_probes].data == data) | 141 | old[nr_probes].data == tp_func->data) |
158 | nr_del++; | 142 | nr_del++; |
159 | } | 143 | } |
160 | } | 144 | } |
@@ -165,9 +149,8 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, | |||
165 | */ | 149 | */ |
166 | if (nr_probes - nr_del == 0) { | 150 | if (nr_probes - nr_del == 0) { |
167 | /* N -> 0, (N > 1) */ | 151 | /* N -> 0, (N > 1) */ |
168 | entry->funcs = NULL; | 152 | *funcs = NULL; |
169 | entry->refcount = 0; | 153 | debug_print_probes(*funcs); |
170 | debug_print_probes(entry); | ||
171 | return old; | 154 | return old; |
172 | } else { | 155 | } else { |
173 | int j = 0; | 156 | int j = 0; |
@@ -177,91 +160,35 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, | |||
177 | if (new == NULL) | 160 | if (new == NULL) |
178 | return ERR_PTR(-ENOMEM); | 161 | return ERR_PTR(-ENOMEM); |
179 | for (i = 0; old[i].func; i++) | 162 | for (i = 0; old[i].func; i++) |
180 | if (old[i].func != probe || old[i].data != data) | 163 | if (old[i].func != tp_func->func |
164 | || old[i].data != tp_func->data) | ||
181 | new[j++] = old[i]; | 165 | new[j++] = old[i]; |
182 | new[nr_probes - nr_del].func = NULL; | 166 | new[nr_probes - nr_del].func = NULL; |
183 | entry->refcount = nr_probes - nr_del; | 167 | *funcs = new; |
184 | entry->funcs = new; | ||
185 | } | 168 | } |
186 | debug_print_probes(entry); | 169 | debug_print_probes(*funcs); |
187 | return old; | 170 | return old; |
188 | } | 171 | } |
189 | 172 | ||
190 | /* | 173 | /* |
191 | * Get tracepoint if the tracepoint is present in the tracepoint hash table. | 174 | * Add the probe function to a tracepoint. |
192 | * Must be called with tracepoints_mutex held. | ||
193 | * Returns NULL if not present. | ||
194 | */ | 175 | */ |
195 | static struct tracepoint_entry *get_tracepoint(const char *name) | 176 | static int tracepoint_add_func(struct tracepoint *tp, |
177 | struct tracepoint_func *func) | ||
196 | { | 178 | { |
197 | struct hlist_head *head; | 179 | struct tracepoint_func *old, *tp_funcs; |
198 | struct tracepoint_entry *e; | ||
199 | u32 hash = jhash(name, strlen(name), 0); | ||
200 | |||
201 | head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; | ||
202 | hlist_for_each_entry(e, head, hlist) { | ||
203 | if (!strcmp(name, e->name)) | ||
204 | return e; | ||
205 | } | ||
206 | return NULL; | ||
207 | } | ||
208 | 180 | ||
209 | /* | 181 | if (tp->regfunc && !static_key_enabled(&tp->key)) |
210 | * Add the tracepoint to the tracepoint hash table. Must be called with | 182 | tp->regfunc(); |
211 | * tracepoints_mutex held. | ||
212 | */ | ||
213 | static struct tracepoint_entry *add_tracepoint(const char *name) | ||
214 | { | ||
215 | struct hlist_head *head; | ||
216 | struct tracepoint_entry *e; | ||
217 | size_t name_len = strlen(name) + 1; | ||
218 | u32 hash = jhash(name, name_len-1, 0); | ||
219 | |||
220 | head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)]; | ||
221 | hlist_for_each_entry(e, head, hlist) { | ||
222 | if (!strcmp(name, e->name)) { | ||
223 | printk(KERN_NOTICE | ||
224 | "tracepoint %s busy\n", name); | ||
225 | return ERR_PTR(-EEXIST); /* Already there */ | ||
226 | } | ||
227 | } | ||
228 | /* | ||
229 | * Using kmalloc here to allocate a variable length element. Could | ||
230 | * cause some memory fragmentation if overused. | ||
231 | */ | ||
232 | e = kmalloc(sizeof(struct tracepoint_entry) + name_len, GFP_KERNEL); | ||
233 | if (!e) | ||
234 | return ERR_PTR(-ENOMEM); | ||
235 | memcpy(&e->name[0], name, name_len); | ||
236 | e->funcs = NULL; | ||
237 | e->refcount = 0; | ||
238 | e->enabled = 0; | ||
239 | hlist_add_head(&e->hlist, head); | ||
240 | return e; | ||
241 | } | ||
242 | 183 | ||
243 | /* | 184 | tp_funcs = rcu_dereference_protected(tp->funcs, |
244 | * Remove the tracepoint from the tracepoint hash table. Must be called with | 185 | lockdep_is_held(&tracepoints_mutex)); |
245 | * mutex_lock held. | 186 | old = func_add(&tp_funcs, func); |
246 | */ | 187 | if (IS_ERR(old)) { |
247 | static inline void remove_tracepoint(struct tracepoint_entry *e) | 188 | WARN_ON_ONCE(1); |
248 | { | 189 | return PTR_ERR(old); |
249 | hlist_del(&e->hlist); | 190 | } |
250 | kfree(e); | 191 | release_probes(old); |
251 | } | ||
252 | |||
253 | /* | ||
254 | * Sets the probe callback corresponding to one tracepoint. | ||
255 | */ | ||
256 | static void set_tracepoint(struct tracepoint_entry **entry, | ||
257 | struct tracepoint *elem, int active) | ||
258 | { | ||
259 | WARN_ON(strcmp((*entry)->name, elem->name) != 0); | ||
260 | |||
261 | if (elem->regfunc && !static_key_enabled(&elem->key) && active) | ||
262 | elem->regfunc(); | ||
263 | else if (elem->unregfunc && static_key_enabled(&elem->key) && !active) | ||
264 | elem->unregfunc(); | ||
265 | 192 | ||
266 | /* | 193 | /* |
267 | * rcu_assign_pointer has a smp_wmb() which makes sure that the new | 194 | * rcu_assign_pointer has a smp_wmb() which makes sure that the new |
@@ -270,193 +197,90 @@ static void set_tracepoint(struct tracepoint_entry **entry, | |||
270 | * include/linux/tracepoints.h. A matching smp_read_barrier_depends() | 197 | * include/linux/tracepoints.h. A matching smp_read_barrier_depends() |
271 | * is used. | 198 | * is used. |
272 | */ | 199 | */ |
273 | rcu_assign_pointer(elem->funcs, (*entry)->funcs); | 200 | rcu_assign_pointer(tp->funcs, tp_funcs); |
274 | if (active && !static_key_enabled(&elem->key)) | 201 | if (!static_key_enabled(&tp->key)) |
275 | static_key_slow_inc(&elem->key); | 202 | static_key_slow_inc(&tp->key); |
276 | else if (!active && static_key_enabled(&elem->key)) | 203 | return 0; |
277 | static_key_slow_dec(&elem->key); | ||
278 | } | 204 | } |
279 | 205 | ||
280 | /* | 206 | /* |
281 | * Disable a tracepoint and its probe callback. | 207 | * Remove a probe function from a tracepoint. |
282 | * Note: only waiting an RCU period after setting elem->call to the empty | 208 | * Note: only waiting an RCU period after setting elem->call to the empty |
283 | * function insures that the original callback is not used anymore. This insured | 209 | * function insures that the original callback is not used anymore. This insured |
284 | * by preempt_disable around the call site. | 210 | * by preempt_disable around the call site. |
285 | */ | 211 | */ |
286 | static void disable_tracepoint(struct tracepoint *elem) | 212 | static int tracepoint_remove_func(struct tracepoint *tp, |
213 | struct tracepoint_func *func) | ||
287 | { | 214 | { |
288 | if (elem->unregfunc && static_key_enabled(&elem->key)) | 215 | struct tracepoint_func *old, *tp_funcs; |
289 | elem->unregfunc(); | ||
290 | |||
291 | if (static_key_enabled(&elem->key)) | ||
292 | static_key_slow_dec(&elem->key); | ||
293 | rcu_assign_pointer(elem->funcs, NULL); | ||
294 | } | ||
295 | 216 | ||
296 | /** | 217 | tp_funcs = rcu_dereference_protected(tp->funcs, |
297 | * tracepoint_update_probe_range - Update a probe range | 218 | lockdep_is_held(&tracepoints_mutex)); |
298 | * @begin: beginning of the range | 219 | old = func_remove(&tp_funcs, func); |
299 | * @end: end of the range | 220 | if (IS_ERR(old)) { |
300 | * | 221 | WARN_ON_ONCE(1); |
301 | * Updates the probe callback corresponding to a range of tracepoints. | 222 | return PTR_ERR(old); |
302 | * Called with tracepoints_mutex held. | ||
303 | */ | ||
304 | static void tracepoint_update_probe_range(struct tracepoint * const *begin, | ||
305 | struct tracepoint * const *end) | ||
306 | { | ||
307 | struct tracepoint * const *iter; | ||
308 | struct tracepoint_entry *mark_entry; | ||
309 | |||
310 | if (!begin) | ||
311 | return; | ||
312 | |||
313 | for (iter = begin; iter < end; iter++) { | ||
314 | mark_entry = get_tracepoint((*iter)->name); | ||
315 | if (mark_entry) { | ||
316 | set_tracepoint(&mark_entry, *iter, | ||
317 | !!mark_entry->refcount); | ||
318 | mark_entry->enabled = !!mark_entry->refcount; | ||
319 | } else { | ||
320 | disable_tracepoint(*iter); | ||
321 | } | ||
322 | } | 223 | } |
323 | } | 224 | release_probes(old); |
324 | |||
325 | #ifdef CONFIG_MODULES | ||
326 | void module_update_tracepoints(void) | ||
327 | { | ||
328 | struct tp_module *tp_mod; | ||
329 | |||
330 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | ||
331 | tracepoint_update_probe_range(tp_mod->tracepoints_ptrs, | ||
332 | tp_mod->tracepoints_ptrs + tp_mod->num_tracepoints); | ||
333 | } | ||
334 | #else /* CONFIG_MODULES */ | ||
335 | void module_update_tracepoints(void) | ||
336 | { | ||
337 | } | ||
338 | #endif /* CONFIG_MODULES */ | ||
339 | 225 | ||
226 | if (!tp_funcs) { | ||
227 | /* Removed last function */ | ||
228 | if (tp->unregfunc && static_key_enabled(&tp->key)) | ||
229 | tp->unregfunc(); | ||
340 | 230 | ||
341 | /* | 231 | if (static_key_enabled(&tp->key)) |
342 | * Update probes, removing the faulty probes. | 232 | static_key_slow_dec(&tp->key); |
343 | * Called with tracepoints_mutex held. | ||
344 | */ | ||
345 | static void tracepoint_update_probes(void) | ||
346 | { | ||
347 | /* Core kernel tracepoints */ | ||
348 | tracepoint_update_probe_range(__start___tracepoints_ptrs, | ||
349 | __stop___tracepoints_ptrs); | ||
350 | /* tracepoints in modules. */ | ||
351 | module_update_tracepoints(); | ||
352 | } | ||
353 | |||
354 | static struct tracepoint_func * | ||
355 | tracepoint_add_probe(const char *name, void *probe, void *data) | ||
356 | { | ||
357 | struct tracepoint_entry *entry; | ||
358 | struct tracepoint_func *old; | ||
359 | |||
360 | entry = get_tracepoint(name); | ||
361 | if (!entry) { | ||
362 | entry = add_tracepoint(name); | ||
363 | if (IS_ERR(entry)) | ||
364 | return (struct tracepoint_func *)entry; | ||
365 | } | 233 | } |
366 | old = tracepoint_entry_add_probe(entry, probe, data); | 234 | rcu_assign_pointer(tp->funcs, tp_funcs); |
367 | if (IS_ERR(old) && !entry->refcount) | 235 | return 0; |
368 | remove_tracepoint(entry); | ||
369 | return old; | ||
370 | } | 236 | } |
371 | 237 | ||
372 | /** | 238 | /** |
373 | * tracepoint_probe_register - Connect a probe to a tracepoint | 239 | * tracepoint_probe_register - Connect a probe to a tracepoint |
374 | * @name: tracepoint name | 240 | * @tp: tracepoint |
375 | * @probe: probe handler | 241 | * @probe: probe handler |
376 | * @data: probe private data | ||
377 | * | ||
378 | * Returns: | ||
379 | * - 0 if the probe was successfully registered, and tracepoint | ||
380 | * callsites are currently loaded for that probe, | ||
381 | * - -ENODEV if the probe was successfully registered, but no tracepoint | ||
382 | * callsite is currently loaded for that probe, | ||
383 | * - other negative error value on error. | ||
384 | * | ||
385 | * When tracepoint_probe_register() returns either 0 or -ENODEV, | ||
386 | * parameters @name, @probe, and @data may be used by the tracepoint | ||
387 | * infrastructure until the probe is unregistered. | ||
388 | * | 242 | * |
389 | * The probe address must at least be aligned on the architecture pointer size. | 243 | * Returns 0 if ok, error value on error. |
244 | * Note: if @tp is within a module, the caller is responsible for | ||
245 | * unregistering the probe before the module is gone. This can be | ||
246 | * performed either with a tracepoint module going notifier, or from | ||
247 | * within module exit functions. | ||
390 | */ | 248 | */ |
391 | int tracepoint_probe_register(const char *name, void *probe, void *data) | 249 | int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) |
392 | { | 250 | { |
393 | struct tracepoint_func *old; | 251 | struct tracepoint_func tp_func; |
394 | struct tracepoint_entry *entry; | 252 | int ret; |
395 | int ret = 0; | ||
396 | 253 | ||
397 | mutex_lock(&tracepoints_mutex); | 254 | mutex_lock(&tracepoints_mutex); |
398 | old = tracepoint_add_probe(name, probe, data); | 255 | tp_func.func = probe; |
399 | if (IS_ERR(old)) { | 256 | tp_func.data = data; |
400 | mutex_unlock(&tracepoints_mutex); | 257 | ret = tracepoint_add_func(tp, &tp_func); |
401 | return PTR_ERR(old); | ||
402 | } | ||
403 | tracepoint_update_probes(); /* may update entry */ | ||
404 | entry = get_tracepoint(name); | ||
405 | /* Make sure the entry was enabled */ | ||
406 | if (!entry || !entry->enabled) | ||
407 | ret = -ENODEV; | ||
408 | mutex_unlock(&tracepoints_mutex); | 258 | mutex_unlock(&tracepoints_mutex); |
409 | release_probes(old); | ||
410 | return ret; | 259 | return ret; |
411 | } | 260 | } |
412 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); | 261 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); |
413 | 262 | ||
414 | static struct tracepoint_func * | ||
415 | tracepoint_remove_probe(const char *name, void *probe, void *data) | ||
416 | { | ||
417 | struct tracepoint_entry *entry; | ||
418 | struct tracepoint_func *old; | ||
419 | |||
420 | entry = get_tracepoint(name); | ||
421 | if (!entry) | ||
422 | return ERR_PTR(-ENOENT); | ||
423 | old = tracepoint_entry_remove_probe(entry, probe, data); | ||
424 | if (IS_ERR(old)) | ||
425 | return old; | ||
426 | if (!entry->refcount) | ||
427 | remove_tracepoint(entry); | ||
428 | return old; | ||
429 | } | ||
430 | |||
431 | /** | 263 | /** |
432 | * tracepoint_probe_unregister - Disconnect a probe from a tracepoint | 264 | * tracepoint_probe_unregister - Disconnect a probe from a tracepoint |
433 | * @name: tracepoint name | 265 | * @tp: tracepoint |
434 | * @probe: probe function pointer | 266 | * @probe: probe function pointer |
435 | * @data: probe private data | ||
436 | * | 267 | * |
437 | * We do not need to call a synchronize_sched to make sure the probes have | 268 | * Returns 0 if ok, error value on error. |
438 | * finished running before doing a module unload, because the module unload | ||
439 | * itself uses stop_machine(), which insures that every preempt disabled section | ||
440 | * have finished. | ||
441 | */ | 269 | */ |
442 | int tracepoint_probe_unregister(const char *name, void *probe, void *data) | 270 | int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data) |
443 | { | 271 | { |
444 | struct tracepoint_func *old; | 272 | struct tracepoint_func tp_func; |
273 | int ret; | ||
445 | 274 | ||
446 | mutex_lock(&tracepoints_mutex); | 275 | mutex_lock(&tracepoints_mutex); |
447 | old = tracepoint_remove_probe(name, probe, data); | 276 | tp_func.func = probe; |
448 | if (IS_ERR(old)) { | 277 | tp_func.data = data; |
449 | mutex_unlock(&tracepoints_mutex); | 278 | ret = tracepoint_remove_func(tp, &tp_func); |
450 | return PTR_ERR(old); | ||
451 | } | ||
452 | tracepoint_update_probes(); /* may update entry */ | ||
453 | mutex_unlock(&tracepoints_mutex); | 279 | mutex_unlock(&tracepoints_mutex); |
454 | release_probes(old); | 280 | return ret; |
455 | return 0; | ||
456 | } | 281 | } |
457 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); | 282 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); |
458 | 283 | ||
459 | |||
460 | #ifdef CONFIG_MODULES | 284 | #ifdef CONFIG_MODULES |
461 | bool trace_module_has_bad_taint(struct module *mod) | 285 | bool trace_module_has_bad_taint(struct module *mod) |
462 | { | 286 | { |
@@ -464,6 +288,74 @@ bool trace_module_has_bad_taint(struct module *mod) | |||
464 | (1 << TAINT_UNSIGNED_MODULE)); | 288 | (1 << TAINT_UNSIGNED_MODULE)); |
465 | } | 289 | } |
466 | 290 | ||
291 | static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); | ||
292 | |||
293 | /** | ||
294 | * register_tracepoint_notifier - register tracepoint coming/going notifier | ||
295 | * @nb: notifier block | ||
296 | * | ||
297 | * Notifiers registered with this function are called on module | ||
298 | * coming/going with the tracepoint_module_list_mutex held. | ||
299 | * The notifier block callback should expect a "struct tp_module" data | ||
300 | * pointer. | ||
301 | */ | ||
302 | int register_tracepoint_module_notifier(struct notifier_block *nb) | ||
303 | { | ||
304 | struct tp_module *tp_mod; | ||
305 | int ret; | ||
306 | |||
307 | mutex_lock(&tracepoint_module_list_mutex); | ||
308 | ret = blocking_notifier_chain_register(&tracepoint_notify_list, nb); | ||
309 | if (ret) | ||
310 | goto end; | ||
311 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | ||
312 | (void) nb->notifier_call(nb, MODULE_STATE_COMING, tp_mod); | ||
313 | end: | ||
314 | mutex_unlock(&tracepoint_module_list_mutex); | ||
315 | return ret; | ||
316 | } | ||
317 | EXPORT_SYMBOL_GPL(register_tracepoint_module_notifier); | ||
318 | |||
319 | /** | ||
320 | * unregister_tracepoint_notifier - unregister tracepoint coming/going notifier | ||
321 | * @nb: notifier block | ||
322 | * | ||
323 | * The notifier block callback should expect a "struct tp_module" data | ||
324 | * pointer. | ||
325 | */ | ||
326 | int unregister_tracepoint_module_notifier(struct notifier_block *nb) | ||
327 | { | ||
328 | struct tp_module *tp_mod; | ||
329 | int ret; | ||
330 | |||
331 | mutex_lock(&tracepoint_module_list_mutex); | ||
332 | ret = blocking_notifier_chain_unregister(&tracepoint_notify_list, nb); | ||
333 | if (ret) | ||
334 | goto end; | ||
335 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | ||
336 | (void) nb->notifier_call(nb, MODULE_STATE_GOING, tp_mod); | ||
337 | end: | ||
338 | mutex_unlock(&tracepoint_module_list_mutex); | ||
339 | return ret; | ||
340 | |||
341 | } | ||
342 | EXPORT_SYMBOL_GPL(unregister_tracepoint_module_notifier); | ||
343 | |||
344 | /* | ||
345 | * Ensure the tracer unregistered the module's probes before the module | ||
346 | * teardown is performed. Prevents leaks of probe and data pointers. | ||
347 | */ | ||
348 | static void tp_module_going_check_quiescent(struct tracepoint * const *begin, | ||
349 | struct tracepoint * const *end) | ||
350 | { | ||
351 | struct tracepoint * const *iter; | ||
352 | |||
353 | if (!begin) | ||
354 | return; | ||
355 | for (iter = begin; iter < end; iter++) | ||
356 | WARN_ON_ONCE((*iter)->funcs); | ||
357 | } | ||
358 | |||
467 | static int tracepoint_module_coming(struct module *mod) | 359 | static int tracepoint_module_coming(struct module *mod) |
468 | { | 360 | { |
469 | struct tp_module *tp_mod; | 361 | struct tp_module *tp_mod; |
@@ -479,36 +371,41 @@ static int tracepoint_module_coming(struct module *mod) | |||
479 | */ | 371 | */ |
480 | if (trace_module_has_bad_taint(mod)) | 372 | if (trace_module_has_bad_taint(mod)) |
481 | return 0; | 373 | return 0; |
482 | mutex_lock(&tracepoints_mutex); | 374 | mutex_lock(&tracepoint_module_list_mutex); |
483 | tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); | 375 | tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); |
484 | if (!tp_mod) { | 376 | if (!tp_mod) { |
485 | ret = -ENOMEM; | 377 | ret = -ENOMEM; |
486 | goto end; | 378 | goto end; |
487 | } | 379 | } |
488 | tp_mod->num_tracepoints = mod->num_tracepoints; | 380 | tp_mod->mod = mod; |
489 | tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs; | ||
490 | list_add_tail(&tp_mod->list, &tracepoint_module_list); | 381 | list_add_tail(&tp_mod->list, &tracepoint_module_list); |
491 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | 382 | blocking_notifier_call_chain(&tracepoint_notify_list, |
492 | mod->tracepoints_ptrs + mod->num_tracepoints); | 383 | MODULE_STATE_COMING, tp_mod); |
493 | end: | 384 | end: |
494 | mutex_unlock(&tracepoints_mutex); | 385 | mutex_unlock(&tracepoint_module_list_mutex); |
495 | return ret; | 386 | return ret; |
496 | } | 387 | } |
497 | 388 | ||
498 | static int tracepoint_module_going(struct module *mod) | 389 | static void tracepoint_module_going(struct module *mod) |
499 | { | 390 | { |
500 | struct tp_module *pos; | 391 | struct tp_module *tp_mod; |
501 | 392 | ||
502 | if (!mod->num_tracepoints) | 393 | if (!mod->num_tracepoints) |
503 | return 0; | 394 | return; |
504 | 395 | ||
505 | mutex_lock(&tracepoints_mutex); | 396 | mutex_lock(&tracepoint_module_list_mutex); |
506 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | 397 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) { |
507 | mod->tracepoints_ptrs + mod->num_tracepoints); | 398 | if (tp_mod->mod == mod) { |
508 | list_for_each_entry(pos, &tracepoint_module_list, list) { | 399 | blocking_notifier_call_chain(&tracepoint_notify_list, |
509 | if (pos->tracepoints_ptrs == mod->tracepoints_ptrs) { | 400 | MODULE_STATE_GOING, tp_mod); |
510 | list_del(&pos->list); | 401 | list_del(&tp_mod->list); |
511 | kfree(pos); | 402 | kfree(tp_mod); |
403 | /* | ||
404 | * Called the going notifier before checking for | ||
405 | * quiescence. | ||
406 | */ | ||
407 | tp_module_going_check_quiescent(mod->tracepoints_ptrs, | ||
408 | mod->tracepoints_ptrs + mod->num_tracepoints); | ||
512 | break; | 409 | break; |
513 | } | 410 | } |
514 | } | 411 | } |
@@ -518,12 +415,11 @@ static int tracepoint_module_going(struct module *mod) | |||
518 | * flag on "going", in case a module taints the kernel only after being | 415 | * flag on "going", in case a module taints the kernel only after being |
519 | * loaded. | 416 | * loaded. |
520 | */ | 417 | */ |
521 | mutex_unlock(&tracepoints_mutex); | 418 | mutex_unlock(&tracepoint_module_list_mutex); |
522 | return 0; | ||
523 | } | 419 | } |
524 | 420 | ||
525 | int tracepoint_module_notify(struct notifier_block *self, | 421 | static int tracepoint_module_notify(struct notifier_block *self, |
526 | unsigned long val, void *data) | 422 | unsigned long val, void *data) |
527 | { | 423 | { |
528 | struct module *mod = data; | 424 | struct module *mod = data; |
529 | int ret = 0; | 425 | int ret = 0; |
@@ -535,24 +431,58 @@ int tracepoint_module_notify(struct notifier_block *self, | |||
535 | case MODULE_STATE_LIVE: | 431 | case MODULE_STATE_LIVE: |
536 | break; | 432 | break; |
537 | case MODULE_STATE_GOING: | 433 | case MODULE_STATE_GOING: |
538 | ret = tracepoint_module_going(mod); | 434 | tracepoint_module_going(mod); |
435 | break; | ||
436 | case MODULE_STATE_UNFORMED: | ||
539 | break; | 437 | break; |
540 | } | 438 | } |
541 | return ret; | 439 | return ret; |
542 | } | 440 | } |
543 | 441 | ||
544 | struct notifier_block tracepoint_module_nb = { | 442 | static struct notifier_block tracepoint_module_nb = { |
545 | .notifier_call = tracepoint_module_notify, | 443 | .notifier_call = tracepoint_module_notify, |
546 | .priority = 0, | 444 | .priority = 0, |
547 | }; | 445 | }; |
548 | 446 | ||
549 | static int init_tracepoints(void) | 447 | static __init int init_tracepoints(void) |
550 | { | 448 | { |
551 | return register_module_notifier(&tracepoint_module_nb); | 449 | int ret; |
450 | |||
451 | ret = register_module_notifier(&tracepoint_module_nb); | ||
452 | if (ret) | ||
453 | pr_warning("Failed to register tracepoint module enter notifier\n"); | ||
454 | |||
455 | return ret; | ||
552 | } | 456 | } |
553 | __initcall(init_tracepoints); | 457 | __initcall(init_tracepoints); |
554 | #endif /* CONFIG_MODULES */ | 458 | #endif /* CONFIG_MODULES */ |
555 | 459 | ||
460 | static void for_each_tracepoint_range(struct tracepoint * const *begin, | ||
461 | struct tracepoint * const *end, | ||
462 | void (*fct)(struct tracepoint *tp, void *priv), | ||
463 | void *priv) | ||
464 | { | ||
465 | struct tracepoint * const *iter; | ||
466 | |||
467 | if (!begin) | ||
468 | return; | ||
469 | for (iter = begin; iter < end; iter++) | ||
470 | fct(*iter, priv); | ||
471 | } | ||
472 | |||
473 | /** | ||
474 | * for_each_kernel_tracepoint - iteration on all kernel tracepoints | ||
475 | * @fct: callback | ||
476 | * @priv: private data | ||
477 | */ | ||
478 | void for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), | ||
479 | void *priv) | ||
480 | { | ||
481 | for_each_tracepoint_range(__start___tracepoints_ptrs, | ||
482 | __stop___tracepoints_ptrs, fct, priv); | ||
483 | } | ||
484 | EXPORT_SYMBOL_GPL(for_each_kernel_tracepoint); | ||
485 | |||
556 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | 486 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |
557 | 487 | ||
558 | /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ | 488 | /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ |