diff options
Diffstat (limited to 'kernel/tracepoint.c')
-rw-r--r-- | kernel/tracepoint.c | 251 |
1 files changed, 34 insertions, 217 deletions
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 031cc5655a51..50f8329c2042 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -62,14 +62,12 @@ struct tracepoint_entry { | |||
62 | struct hlist_node hlist; | 62 | struct hlist_node hlist; |
63 | struct tracepoint_func *funcs; | 63 | struct tracepoint_func *funcs; |
64 | int refcount; /* Number of times armed. 0 if disarmed. */ | 64 | int refcount; /* Number of times armed. 0 if disarmed. */ |
65 | int enabled; /* Tracepoint enabled */ | ||
65 | char name[0]; | 66 | char name[0]; |
66 | }; | 67 | }; |
67 | 68 | ||
68 | struct tp_probes { | 69 | struct tp_probes { |
69 | union { | 70 | struct rcu_head rcu; |
70 | struct rcu_head rcu; | ||
71 | struct list_head list; | ||
72 | } u; | ||
73 | struct tracepoint_func probes[0]; | 71 | struct tracepoint_func probes[0]; |
74 | }; | 72 | }; |
75 | 73 | ||
@@ -82,7 +80,7 @@ static inline void *allocate_probes(int count) | |||
82 | 80 | ||
83 | static void rcu_free_old_probes(struct rcu_head *head) | 81 | static void rcu_free_old_probes(struct rcu_head *head) |
84 | { | 82 | { |
85 | kfree(container_of(head, struct tp_probes, u.rcu)); | 83 | kfree(container_of(head, struct tp_probes, rcu)); |
86 | } | 84 | } |
87 | 85 | ||
88 | static inline void release_probes(struct tracepoint_func *old) | 86 | static inline void release_probes(struct tracepoint_func *old) |
@@ -90,7 +88,7 @@ static inline void release_probes(struct tracepoint_func *old) | |||
90 | if (old) { | 88 | if (old) { |
91 | struct tp_probes *tp_probes = container_of(old, | 89 | struct tp_probes *tp_probes = container_of(old, |
92 | struct tp_probes, probes[0]); | 90 | struct tp_probes, probes[0]); |
93 | call_rcu_sched(&tp_probes->u.rcu, rcu_free_old_probes); | 91 | call_rcu_sched(&tp_probes->rcu, rcu_free_old_probes); |
94 | } | 92 | } |
95 | } | 93 | } |
96 | 94 | ||
@@ -237,6 +235,7 @@ static struct tracepoint_entry *add_tracepoint(const char *name) | |||
237 | memcpy(&e->name[0], name, name_len); | 235 | memcpy(&e->name[0], name, name_len); |
238 | e->funcs = NULL; | 236 | e->funcs = NULL; |
239 | e->refcount = 0; | 237 | e->refcount = 0; |
238 | e->enabled = 0; | ||
240 | hlist_add_head(&e->hlist, head); | 239 | hlist_add_head(&e->hlist, head); |
241 | return e; | 240 | return e; |
242 | } | 241 | } |
@@ -316,6 +315,7 @@ static void tracepoint_update_probe_range(struct tracepoint * const *begin, | |||
316 | if (mark_entry) { | 315 | if (mark_entry) { |
317 | set_tracepoint(&mark_entry, *iter, | 316 | set_tracepoint(&mark_entry, *iter, |
318 | !!mark_entry->refcount); | 317 | !!mark_entry->refcount); |
318 | mark_entry->enabled = !!mark_entry->refcount; | ||
319 | } else { | 319 | } else { |
320 | disable_tracepoint(*iter); | 320 | disable_tracepoint(*iter); |
321 | } | 321 | } |
@@ -373,13 +373,26 @@ tracepoint_add_probe(const char *name, void *probe, void *data) | |||
373 | * tracepoint_probe_register - Connect a probe to a tracepoint | 373 | * tracepoint_probe_register - Connect a probe to a tracepoint |
374 | * @name: tracepoint name | 374 | * @name: tracepoint name |
375 | * @probe: probe handler | 375 | * @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. | ||
376 | * | 388 | * |
377 | * Returns 0 if ok, error value on error. | ||
378 | * The probe address must at least be aligned on the architecture pointer size. | 389 | * The probe address must at least be aligned on the architecture pointer size. |
379 | */ | 390 | */ |
380 | int tracepoint_probe_register(const char *name, void *probe, void *data) | 391 | int tracepoint_probe_register(const char *name, void *probe, void *data) |
381 | { | 392 | { |
382 | struct tracepoint_func *old; | 393 | struct tracepoint_func *old; |
394 | struct tracepoint_entry *entry; | ||
395 | int ret = 0; | ||
383 | 396 | ||
384 | mutex_lock(&tracepoints_mutex); | 397 | mutex_lock(&tracepoints_mutex); |
385 | old = tracepoint_add_probe(name, probe, data); | 398 | old = tracepoint_add_probe(name, probe, data); |
@@ -388,9 +401,13 @@ int tracepoint_probe_register(const char *name, void *probe, void *data) | |||
388 | return PTR_ERR(old); | 401 | return PTR_ERR(old); |
389 | } | 402 | } |
390 | tracepoint_update_probes(); /* may update entry */ | 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; | ||
391 | mutex_unlock(&tracepoints_mutex); | 408 | mutex_unlock(&tracepoints_mutex); |
392 | release_probes(old); | 409 | release_probes(old); |
393 | return 0; | 410 | return ret; |
394 | } | 411 | } |
395 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); | 412 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); |
396 | 413 | ||
@@ -415,6 +432,7 @@ tracepoint_remove_probe(const char *name, void *probe, void *data) | |||
415 | * tracepoint_probe_unregister - Disconnect a probe from a tracepoint | 432 | * tracepoint_probe_unregister - Disconnect a probe from a tracepoint |
416 | * @name: tracepoint name | 433 | * @name: tracepoint name |
417 | * @probe: probe function pointer | 434 | * @probe: probe function pointer |
435 | * @data: probe private data | ||
418 | * | 436 | * |
419 | * We do not need to call a synchronize_sched to make sure the probes have | 437 | * We do not need to call a synchronize_sched to make sure the probes have |
420 | * finished running before doing a module unload, because the module unload | 438 | * finished running before doing a module unload, because the module unload |
@@ -438,197 +456,6 @@ int tracepoint_probe_unregister(const char *name, void *probe, void *data) | |||
438 | } | 456 | } |
439 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); | 457 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); |
440 | 458 | ||
441 | static LIST_HEAD(old_probes); | ||
442 | static int need_update; | ||
443 | |||
444 | static void tracepoint_add_old_probes(void *old) | ||
445 | { | ||
446 | need_update = 1; | ||
447 | if (old) { | ||
448 | struct tp_probes *tp_probes = container_of(old, | ||
449 | struct tp_probes, probes[0]); | ||
450 | list_add(&tp_probes->u.list, &old_probes); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * tracepoint_probe_register_noupdate - register a probe but not connect | ||
456 | * @name: tracepoint name | ||
457 | * @probe: probe handler | ||
458 | * | ||
459 | * caller must call tracepoint_probe_update_all() | ||
460 | */ | ||
461 | int tracepoint_probe_register_noupdate(const char *name, void *probe, | ||
462 | void *data) | ||
463 | { | ||
464 | struct tracepoint_func *old; | ||
465 | |||
466 | mutex_lock(&tracepoints_mutex); | ||
467 | old = tracepoint_add_probe(name, probe, data); | ||
468 | if (IS_ERR(old)) { | ||
469 | mutex_unlock(&tracepoints_mutex); | ||
470 | return PTR_ERR(old); | ||
471 | } | ||
472 | tracepoint_add_old_probes(old); | ||
473 | mutex_unlock(&tracepoints_mutex); | ||
474 | return 0; | ||
475 | } | ||
476 | EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate); | ||
477 | |||
478 | /** | ||
479 | * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect | ||
480 | * @name: tracepoint name | ||
481 | * @probe: probe function pointer | ||
482 | * | ||
483 | * caller must call tracepoint_probe_update_all() | ||
484 | */ | ||
485 | int tracepoint_probe_unregister_noupdate(const char *name, void *probe, | ||
486 | void *data) | ||
487 | { | ||
488 | struct tracepoint_func *old; | ||
489 | |||
490 | mutex_lock(&tracepoints_mutex); | ||
491 | old = tracepoint_remove_probe(name, probe, data); | ||
492 | if (IS_ERR(old)) { | ||
493 | mutex_unlock(&tracepoints_mutex); | ||
494 | return PTR_ERR(old); | ||
495 | } | ||
496 | tracepoint_add_old_probes(old); | ||
497 | mutex_unlock(&tracepoints_mutex); | ||
498 | return 0; | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate); | ||
501 | |||
502 | /** | ||
503 | * tracepoint_probe_update_all - update tracepoints | ||
504 | */ | ||
505 | void tracepoint_probe_update_all(void) | ||
506 | { | ||
507 | LIST_HEAD(release_probes); | ||
508 | struct tp_probes *pos, *next; | ||
509 | |||
510 | mutex_lock(&tracepoints_mutex); | ||
511 | if (!need_update) { | ||
512 | mutex_unlock(&tracepoints_mutex); | ||
513 | return; | ||
514 | } | ||
515 | if (!list_empty(&old_probes)) | ||
516 | list_replace_init(&old_probes, &release_probes); | ||
517 | need_update = 0; | ||
518 | tracepoint_update_probes(); | ||
519 | mutex_unlock(&tracepoints_mutex); | ||
520 | list_for_each_entry_safe(pos, next, &release_probes, u.list) { | ||
521 | list_del(&pos->u.list); | ||
522 | call_rcu_sched(&pos->u.rcu, rcu_free_old_probes); | ||
523 | } | ||
524 | } | ||
525 | EXPORT_SYMBOL_GPL(tracepoint_probe_update_all); | ||
526 | |||
527 | /** | ||
528 | * tracepoint_get_iter_range - Get a next tracepoint iterator given a range. | ||
529 | * @tracepoint: current tracepoints (in), next tracepoint (out) | ||
530 | * @begin: beginning of the range | ||
531 | * @end: end of the range | ||
532 | * | ||
533 | * Returns whether a next tracepoint has been found (1) or not (0). | ||
534 | * Will return the first tracepoint in the range if the input tracepoint is | ||
535 | * NULL. | ||
536 | */ | ||
537 | static int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, | ||
538 | struct tracepoint * const *begin, struct tracepoint * const *end) | ||
539 | { | ||
540 | if (!*tracepoint && begin != end) { | ||
541 | *tracepoint = begin; | ||
542 | return 1; | ||
543 | } | ||
544 | if (*tracepoint >= begin && *tracepoint < end) | ||
545 | return 1; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | #ifdef CONFIG_MODULES | ||
550 | static void tracepoint_get_iter(struct tracepoint_iter *iter) | ||
551 | { | ||
552 | int found = 0; | ||
553 | struct tp_module *iter_mod; | ||
554 | |||
555 | /* Core kernel tracepoints */ | ||
556 | if (!iter->module) { | ||
557 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
558 | __start___tracepoints_ptrs, | ||
559 | __stop___tracepoints_ptrs); | ||
560 | if (found) | ||
561 | goto end; | ||
562 | } | ||
563 | /* Tracepoints in modules */ | ||
564 | mutex_lock(&tracepoints_mutex); | ||
565 | list_for_each_entry(iter_mod, &tracepoint_module_list, list) { | ||
566 | /* | ||
567 | * Sorted module list | ||
568 | */ | ||
569 | if (iter_mod < iter->module) | ||
570 | continue; | ||
571 | else if (iter_mod > iter->module) | ||
572 | iter->tracepoint = NULL; | ||
573 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
574 | iter_mod->tracepoints_ptrs, | ||
575 | iter_mod->tracepoints_ptrs | ||
576 | + iter_mod->num_tracepoints); | ||
577 | if (found) { | ||
578 | iter->module = iter_mod; | ||
579 | break; | ||
580 | } | ||
581 | } | ||
582 | mutex_unlock(&tracepoints_mutex); | ||
583 | end: | ||
584 | if (!found) | ||
585 | tracepoint_iter_reset(iter); | ||
586 | } | ||
587 | #else /* CONFIG_MODULES */ | ||
588 | static void tracepoint_get_iter(struct tracepoint_iter *iter) | ||
589 | { | ||
590 | int found = 0; | ||
591 | |||
592 | /* Core kernel tracepoints */ | ||
593 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
594 | __start___tracepoints_ptrs, | ||
595 | __stop___tracepoints_ptrs); | ||
596 | if (!found) | ||
597 | tracepoint_iter_reset(iter); | ||
598 | } | ||
599 | #endif /* CONFIG_MODULES */ | ||
600 | |||
601 | void tracepoint_iter_start(struct tracepoint_iter *iter) | ||
602 | { | ||
603 | tracepoint_get_iter(iter); | ||
604 | } | ||
605 | EXPORT_SYMBOL_GPL(tracepoint_iter_start); | ||
606 | |||
607 | void tracepoint_iter_next(struct tracepoint_iter *iter) | ||
608 | { | ||
609 | iter->tracepoint++; | ||
610 | /* | ||
611 | * iter->tracepoint may be invalid because we blindly incremented it. | ||
612 | * Make sure it is valid by marshalling on the tracepoints, getting the | ||
613 | * tracepoints from following modules if necessary. | ||
614 | */ | ||
615 | tracepoint_get_iter(iter); | ||
616 | } | ||
617 | EXPORT_SYMBOL_GPL(tracepoint_iter_next); | ||
618 | |||
619 | void tracepoint_iter_stop(struct tracepoint_iter *iter) | ||
620 | { | ||
621 | } | ||
622 | EXPORT_SYMBOL_GPL(tracepoint_iter_stop); | ||
623 | |||
624 | void tracepoint_iter_reset(struct tracepoint_iter *iter) | ||
625 | { | ||
626 | #ifdef CONFIG_MODULES | ||
627 | iter->module = NULL; | ||
628 | #endif /* CONFIG_MODULES */ | ||
629 | iter->tracepoint = NULL; | ||
630 | } | ||
631 | EXPORT_SYMBOL_GPL(tracepoint_iter_reset); | ||
632 | 459 | ||
633 | #ifdef CONFIG_MODULES | 460 | #ifdef CONFIG_MODULES |
634 | bool trace_module_has_bad_taint(struct module *mod) | 461 | bool trace_module_has_bad_taint(struct module *mod) |
@@ -638,9 +465,12 @@ bool trace_module_has_bad_taint(struct module *mod) | |||
638 | 465 | ||
639 | static int tracepoint_module_coming(struct module *mod) | 466 | static int tracepoint_module_coming(struct module *mod) |
640 | { | 467 | { |
641 | struct tp_module *tp_mod, *iter; | 468 | struct tp_module *tp_mod; |
642 | int ret = 0; | 469 | int ret = 0; |
643 | 470 | ||
471 | if (!mod->num_tracepoints) | ||
472 | return 0; | ||
473 | |||
644 | /* | 474 | /* |
645 | * We skip modules that taint the kernel, especially those with different | 475 | * We skip modules that taint the kernel, especially those with different |
646 | * module headers (for forced load), to make sure we don't cause a crash. | 476 | * module headers (for forced load), to make sure we don't cause a crash. |
@@ -656,23 +486,7 @@ static int tracepoint_module_coming(struct module *mod) | |||
656 | } | 486 | } |
657 | tp_mod->num_tracepoints = mod->num_tracepoints; | 487 | tp_mod->num_tracepoints = mod->num_tracepoints; |
658 | tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs; | 488 | tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs; |
659 | 489 | list_add_tail(&tp_mod->list, &tracepoint_module_list); | |
660 | /* | ||
661 | * tracepoint_module_list is kept sorted by struct module pointer | ||
662 | * address for iteration on tracepoints from a seq_file that can release | ||
663 | * the mutex between calls. | ||
664 | */ | ||
665 | list_for_each_entry_reverse(iter, &tracepoint_module_list, list) { | ||
666 | BUG_ON(iter == tp_mod); /* Should never be in the list twice */ | ||
667 | if (iter < tp_mod) { | ||
668 | /* We belong to the location right after iter. */ | ||
669 | list_add(&tp_mod->list, &iter->list); | ||
670 | goto module_added; | ||
671 | } | ||
672 | } | ||
673 | /* We belong to the beginning of the list */ | ||
674 | list_add(&tp_mod->list, &tracepoint_module_list); | ||
675 | module_added: | ||
676 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | 490 | tracepoint_update_probe_range(mod->tracepoints_ptrs, |
677 | mod->tracepoints_ptrs + mod->num_tracepoints); | 491 | mod->tracepoints_ptrs + mod->num_tracepoints); |
678 | end: | 492 | end: |
@@ -684,6 +498,9 @@ static int tracepoint_module_going(struct module *mod) | |||
684 | { | 498 | { |
685 | struct tp_module *pos; | 499 | struct tp_module *pos; |
686 | 500 | ||
501 | if (!mod->num_tracepoints) | ||
502 | return 0; | ||
503 | |||
687 | mutex_lock(&tracepoints_mutex); | 504 | mutex_lock(&tracepoints_mutex); |
688 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | 505 | tracepoint_update_probe_range(mod->tracepoints_ptrs, |
689 | mod->tracepoints_ptrs + mod->num_tracepoints); | 506 | mod->tracepoints_ptrs + mod->num_tracepoints); |