aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/tracepoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/tracepoint.c')
-rw-r--r--kernel/tracepoint.c105
1 files changed, 63 insertions, 42 deletions
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index cc89be5bc0f8..e95ee7f31d43 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -25,6 +25,7 @@
25#include <linux/err.h> 25#include <linux/err.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/jump_label.h>
28 29
29extern struct tracepoint __start___tracepoints[]; 30extern struct tracepoint __start___tracepoints[];
30extern struct tracepoint __stop___tracepoints[]; 31extern struct tracepoint __stop___tracepoints[];
@@ -54,7 +55,7 @@ static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
54 */ 55 */
55struct tracepoint_entry { 56struct tracepoint_entry {
56 struct hlist_node hlist; 57 struct hlist_node hlist;
57 void **funcs; 58 struct tracepoint_func *funcs;
58 int refcount; /* Number of times armed. 0 if disarmed. */ 59 int refcount; /* Number of times armed. 0 if disarmed. */
59 char name[0]; 60 char name[0];
60}; 61};
@@ -64,12 +65,12 @@ struct tp_probes {
64 struct rcu_head rcu; 65 struct rcu_head rcu;
65 struct list_head list; 66 struct list_head list;
66 } u; 67 } u;
67 void *probes[0]; 68 struct tracepoint_func probes[0];
68}; 69};
69 70
70static inline void *allocate_probes(int count) 71static inline void *allocate_probes(int count)
71{ 72{
72 struct tp_probes *p = kmalloc(count * sizeof(void *) 73 struct tp_probes *p = kmalloc(count * sizeof(struct tracepoint_func)
73 + sizeof(struct tp_probes), GFP_KERNEL); 74 + sizeof(struct tp_probes), GFP_KERNEL);
74 return p == NULL ? NULL : p->probes; 75 return p == NULL ? NULL : p->probes;
75} 76}
@@ -79,7 +80,7 @@ static void rcu_free_old_probes(struct rcu_head *head)
79 kfree(container_of(head, struct tp_probes, u.rcu)); 80 kfree(container_of(head, struct tp_probes, u.rcu));
80} 81}
81 82
82static inline void release_probes(void *old) 83static inline void release_probes(struct tracepoint_func *old)
83{ 84{
84 if (old) { 85 if (old) {
85 struct tp_probes *tp_probes = container_of(old, 86 struct tp_probes *tp_probes = container_of(old,
@@ -95,15 +96,16 @@ static void debug_print_probes(struct tracepoint_entry *entry)
95 if (!tracepoint_debug || !entry->funcs) 96 if (!tracepoint_debug || !entry->funcs)
96 return; 97 return;
97 98
98 for (i = 0; entry->funcs[i]; i++) 99 for (i = 0; entry->funcs[i].func; i++)
99 printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]); 100 printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i].func);
100} 101}
101 102
102static void * 103static struct tracepoint_func *
103tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe) 104tracepoint_entry_add_probe(struct tracepoint_entry *entry,
105 void *probe, void *data)
104{ 106{
105 int nr_probes = 0; 107 int nr_probes = 0;
106 void **old, **new; 108 struct tracepoint_func *old, *new;
107 109
108 WARN_ON(!probe); 110 WARN_ON(!probe);
109 111
@@ -111,8 +113,9 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
111 old = entry->funcs; 113 old = entry->funcs;
112 if (old) { 114 if (old) {
113 /* (N -> N+1), (N != 0, 1) probes */ 115 /* (N -> N+1), (N != 0, 1) probes */
114 for (nr_probes = 0; old[nr_probes]; nr_probes++) 116 for (nr_probes = 0; old[nr_probes].func; nr_probes++)
115 if (old[nr_probes] == probe) 117 if (old[nr_probes].func == probe &&
118 old[nr_probes].data == data)
116 return ERR_PTR(-EEXIST); 119 return ERR_PTR(-EEXIST);
117 } 120 }
118 /* + 2 : one for new probe, one for NULL func */ 121 /* + 2 : one for new probe, one for NULL func */
@@ -120,9 +123,10 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
120 if (new == NULL) 123 if (new == NULL)
121 return ERR_PTR(-ENOMEM); 124 return ERR_PTR(-ENOMEM);
122 if (old) 125 if (old)
123 memcpy(new, old, nr_probes * sizeof(void *)); 126 memcpy(new, old, nr_probes * sizeof(struct tracepoint_func));
124 new[nr_probes] = probe; 127 new[nr_probes].func = probe;
125 new[nr_probes + 1] = NULL; 128 new[nr_probes].data = data;
129 new[nr_probes + 1].func = NULL;
126 entry->refcount = nr_probes + 1; 130 entry->refcount = nr_probes + 1;
127 entry->funcs = new; 131 entry->funcs = new;
128 debug_print_probes(entry); 132 debug_print_probes(entry);
@@ -130,10 +134,11 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe)
130} 134}
131 135
132static void * 136static void *
133tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe) 137tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
138 void *probe, void *data)
134{ 139{
135 int nr_probes = 0, nr_del = 0, i; 140 int nr_probes = 0, nr_del = 0, i;
136 void **old, **new; 141 struct tracepoint_func *old, *new;
137 142
138 old = entry->funcs; 143 old = entry->funcs;
139 144
@@ -142,8 +147,10 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
142 147
143 debug_print_probes(entry); 148 debug_print_probes(entry);
144 /* (N -> M), (N > 1, M >= 0) probes */ 149 /* (N -> M), (N > 1, M >= 0) probes */
145 for (nr_probes = 0; old[nr_probes]; nr_probes++) { 150 for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
146 if ((!probe || old[nr_probes] == probe)) 151 if (!probe ||
152 (old[nr_probes].func == probe &&
153 old[nr_probes].data == data))
147 nr_del++; 154 nr_del++;
148 } 155 }
149 156
@@ -160,10 +167,11 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe)
160 new = allocate_probes(nr_probes - nr_del + 1); 167 new = allocate_probes(nr_probes - nr_del + 1);
161 if (new == NULL) 168 if (new == NULL)
162 return ERR_PTR(-ENOMEM); 169 return ERR_PTR(-ENOMEM);
163 for (i = 0; old[i]; i++) 170 for (i = 0; old[i].func; i++)
164 if ((probe && old[i] != probe)) 171 if (probe &&
172 (old[i].func != probe || old[i].data != data))
165 new[j++] = old[i]; 173 new[j++] = old[i];
166 new[nr_probes - nr_del] = NULL; 174 new[nr_probes - nr_del].func = NULL;
167 entry->refcount = nr_probes - nr_del; 175 entry->refcount = nr_probes - nr_del;
168 entry->funcs = new; 176 entry->funcs = new;
169 } 177 }
@@ -256,7 +264,13 @@ static void set_tracepoint(struct tracepoint_entry **entry,
256 * is used. 264 * is used.
257 */ 265 */
258 rcu_assign_pointer(elem->funcs, (*entry)->funcs); 266 rcu_assign_pointer(elem->funcs, (*entry)->funcs);
259 elem->state = active; 267 if (!elem->state && active) {
268 jump_label_enable(&elem->state);
269 elem->state = active;
270 } else if (elem->state && !active) {
271 jump_label_disable(&elem->state);
272 elem->state = active;
273 }
260} 274}
261 275
262/* 276/*
@@ -270,7 +284,10 @@ static void disable_tracepoint(struct tracepoint *elem)
270 if (elem->unregfunc && elem->state) 284 if (elem->unregfunc && elem->state)
271 elem->unregfunc(); 285 elem->unregfunc();
272 286
273 elem->state = 0; 287 if (elem->state) {
288 jump_label_disable(&elem->state);
289 elem->state = 0;
290 }
274 rcu_assign_pointer(elem->funcs, NULL); 291 rcu_assign_pointer(elem->funcs, NULL);
275} 292}
276 293
@@ -315,18 +332,19 @@ static void tracepoint_update_probes(void)
315 module_update_tracepoints(); 332 module_update_tracepoints();
316} 333}
317 334
318static void *tracepoint_add_probe(const char *name, void *probe) 335static struct tracepoint_func *
336tracepoint_add_probe(const char *name, void *probe, void *data)
319{ 337{
320 struct tracepoint_entry *entry; 338 struct tracepoint_entry *entry;
321 void *old; 339 struct tracepoint_func *old;
322 340
323 entry = get_tracepoint(name); 341 entry = get_tracepoint(name);
324 if (!entry) { 342 if (!entry) {
325 entry = add_tracepoint(name); 343 entry = add_tracepoint(name);
326 if (IS_ERR(entry)) 344 if (IS_ERR(entry))
327 return entry; 345 return (struct tracepoint_func *)entry;
328 } 346 }
329 old = tracepoint_entry_add_probe(entry, probe); 347 old = tracepoint_entry_add_probe(entry, probe, data);
330 if (IS_ERR(old) && !entry->refcount) 348 if (IS_ERR(old) && !entry->refcount)
331 remove_tracepoint(entry); 349 remove_tracepoint(entry);
332 return old; 350 return old;
@@ -340,12 +358,12 @@ static void *tracepoint_add_probe(const char *name, void *probe)
340 * Returns 0 if ok, error value on error. 358 * Returns 0 if ok, error value on error.
341 * The probe address must at least be aligned on the architecture pointer size. 359 * The probe address must at least be aligned on the architecture pointer size.
342 */ 360 */
343int tracepoint_probe_register(const char *name, void *probe) 361int tracepoint_probe_register(const char *name, void *probe, void *data)
344{ 362{
345 void *old; 363 struct tracepoint_func *old;
346 364
347 mutex_lock(&tracepoints_mutex); 365 mutex_lock(&tracepoints_mutex);
348 old = tracepoint_add_probe(name, probe); 366 old = tracepoint_add_probe(name, probe, data);
349 mutex_unlock(&tracepoints_mutex); 367 mutex_unlock(&tracepoints_mutex);
350 if (IS_ERR(old)) 368 if (IS_ERR(old))
351 return PTR_ERR(old); 369 return PTR_ERR(old);
@@ -356,15 +374,16 @@ int tracepoint_probe_register(const char *name, void *probe)
356} 374}
357EXPORT_SYMBOL_GPL(tracepoint_probe_register); 375EXPORT_SYMBOL_GPL(tracepoint_probe_register);
358 376
359static void *tracepoint_remove_probe(const char *name, void *probe) 377static struct tracepoint_func *
378tracepoint_remove_probe(const char *name, void *probe, void *data)
360{ 379{
361 struct tracepoint_entry *entry; 380 struct tracepoint_entry *entry;
362 void *old; 381 struct tracepoint_func *old;
363 382
364 entry = get_tracepoint(name); 383 entry = get_tracepoint(name);
365 if (!entry) 384 if (!entry)
366 return ERR_PTR(-ENOENT); 385 return ERR_PTR(-ENOENT);
367 old = tracepoint_entry_remove_probe(entry, probe); 386 old = tracepoint_entry_remove_probe(entry, probe, data);
368 if (IS_ERR(old)) 387 if (IS_ERR(old))
369 return old; 388 return old;
370 if (!entry->refcount) 389 if (!entry->refcount)
@@ -382,12 +401,12 @@ static void *tracepoint_remove_probe(const char *name, void *probe)
382 * itself uses stop_machine(), which insures that every preempt disabled section 401 * itself uses stop_machine(), which insures that every preempt disabled section
383 * have finished. 402 * have finished.
384 */ 403 */
385int tracepoint_probe_unregister(const char *name, void *probe) 404int tracepoint_probe_unregister(const char *name, void *probe, void *data)
386{ 405{
387 void *old; 406 struct tracepoint_func *old;
388 407
389 mutex_lock(&tracepoints_mutex); 408 mutex_lock(&tracepoints_mutex);
390 old = tracepoint_remove_probe(name, probe); 409 old = tracepoint_remove_probe(name, probe, data);
391 mutex_unlock(&tracepoints_mutex); 410 mutex_unlock(&tracepoints_mutex);
392 if (IS_ERR(old)) 411 if (IS_ERR(old))
393 return PTR_ERR(old); 412 return PTR_ERR(old);
@@ -418,12 +437,13 @@ static void tracepoint_add_old_probes(void *old)
418 * 437 *
419 * caller must call tracepoint_probe_update_all() 438 * caller must call tracepoint_probe_update_all()
420 */ 439 */
421int tracepoint_probe_register_noupdate(const char *name, void *probe) 440int tracepoint_probe_register_noupdate(const char *name, void *probe,
441 void *data)
422{ 442{
423 void *old; 443 struct tracepoint_func *old;
424 444
425 mutex_lock(&tracepoints_mutex); 445 mutex_lock(&tracepoints_mutex);
426 old = tracepoint_add_probe(name, probe); 446 old = tracepoint_add_probe(name, probe, data);
427 if (IS_ERR(old)) { 447 if (IS_ERR(old)) {
428 mutex_unlock(&tracepoints_mutex); 448 mutex_unlock(&tracepoints_mutex);
429 return PTR_ERR(old); 449 return PTR_ERR(old);
@@ -441,12 +461,13 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate);
441 * 461 *
442 * caller must call tracepoint_probe_update_all() 462 * caller must call tracepoint_probe_update_all()
443 */ 463 */
444int tracepoint_probe_unregister_noupdate(const char *name, void *probe) 464int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
465 void *data)
445{ 466{
446 void *old; 467 struct tracepoint_func *old;
447 468
448 mutex_lock(&tracepoints_mutex); 469 mutex_lock(&tracepoints_mutex);
449 old = tracepoint_remove_probe(name, probe); 470 old = tracepoint_remove_probe(name, probe, data);
450 if (IS_ERR(old)) { 471 if (IS_ERR(old)) {
451 mutex_unlock(&tracepoints_mutex); 472 mutex_unlock(&tracepoints_mutex);
452 return PTR_ERR(old); 473 return PTR_ERR(old);