diff options
-rw-r--r-- | include/linux/module.h | 12 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 25 | ||||
-rw-r--r-- | kernel/module.c | 47 | ||||
-rw-r--r-- | kernel/tracepoint.c | 169 |
4 files changed, 158 insertions, 95 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 1c30087a2d81..863921637d9f 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -580,9 +580,6 @@ int unregister_module_notifier(struct notifier_block * nb); | |||
580 | 580 | ||
581 | extern void print_modules(void); | 581 | extern void print_modules(void); |
582 | 582 | ||
583 | extern void module_update_tracepoints(void); | ||
584 | extern int module_get_iter_tracepoints(struct tracepoint_iter *iter); | ||
585 | |||
586 | #else /* !CONFIG_MODULES... */ | 583 | #else /* !CONFIG_MODULES... */ |
587 | #define EXPORT_SYMBOL(sym) | 584 | #define EXPORT_SYMBOL(sym) |
588 | #define EXPORT_SYMBOL_GPL(sym) | 585 | #define EXPORT_SYMBOL_GPL(sym) |
@@ -698,15 +695,6 @@ static inline int unregister_module_notifier(struct notifier_block * nb) | |||
698 | static inline void print_modules(void) | 695 | static inline void print_modules(void) |
699 | { | 696 | { |
700 | } | 697 | } |
701 | |||
702 | static inline void module_update_tracepoints(void) | ||
703 | { | ||
704 | } | ||
705 | |||
706 | static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) | ||
707 | { | ||
708 | return 0; | ||
709 | } | ||
710 | #endif /* CONFIG_MODULES */ | 698 | #endif /* CONFIG_MODULES */ |
711 | 699 | ||
712 | #ifdef CONFIG_SYSFS | 700 | #ifdef CONFIG_SYSFS |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index d530a4460a0b..df0a779c1bbd 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -54,8 +54,18 @@ extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe, | |||
54 | void *data); | 54 | void *data); |
55 | extern void tracepoint_probe_update_all(void); | 55 | extern void tracepoint_probe_update_all(void); |
56 | 56 | ||
57 | #ifdef CONFIG_MODULES | ||
58 | struct tp_module { | ||
59 | struct list_head list; | ||
60 | unsigned int num_tracepoints; | ||
61 | struct tracepoint * const *tracepoints_ptrs; | ||
62 | }; | ||
63 | #endif /* CONFIG_MODULES */ | ||
64 | |||
57 | struct tracepoint_iter { | 65 | struct tracepoint_iter { |
58 | struct module *module; | 66 | #ifdef CONFIG_MODULES |
67 | struct tp_module *module; | ||
68 | #endif /* CONFIG_MODULES */ | ||
59 | struct tracepoint * const *tracepoint; | 69 | struct tracepoint * const *tracepoint; |
60 | }; | 70 | }; |
61 | 71 | ||
@@ -63,8 +73,6 @@ extern void tracepoint_iter_start(struct tracepoint_iter *iter); | |||
63 | extern void tracepoint_iter_next(struct tracepoint_iter *iter); | 73 | extern void tracepoint_iter_next(struct tracepoint_iter *iter); |
64 | extern void tracepoint_iter_stop(struct tracepoint_iter *iter); | 74 | extern void tracepoint_iter_stop(struct tracepoint_iter *iter); |
65 | extern void tracepoint_iter_reset(struct tracepoint_iter *iter); | 75 | extern void tracepoint_iter_reset(struct tracepoint_iter *iter); |
66 | extern int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, | ||
67 | struct tracepoint * const *begin, struct tracepoint * const *end); | ||
68 | 76 | ||
69 | /* | 77 | /* |
70 | * tracepoint_synchronize_unregister must be called between the last tracepoint | 78 | * tracepoint_synchronize_unregister must be called between the last tracepoint |
@@ -78,17 +86,6 @@ static inline void tracepoint_synchronize_unregister(void) | |||
78 | 86 | ||
79 | #define PARAMS(args...) args | 87 | #define PARAMS(args...) args |
80 | 88 | ||
81 | #ifdef CONFIG_TRACEPOINTS | ||
82 | extern | ||
83 | void tracepoint_update_probe_range(struct tracepoint * const *begin, | ||
84 | struct tracepoint * const *end); | ||
85 | #else | ||
86 | static inline | ||
87 | void tracepoint_update_probe_range(struct tracepoint * const *begin, | ||
88 | struct tracepoint * const *end) | ||
89 | { } | ||
90 | #endif /* CONFIG_TRACEPOINTS */ | ||
91 | |||
92 | #endif /* _LINUX_TRACEPOINT_H */ | 89 | #endif /* _LINUX_TRACEPOINT_H */ |
93 | 90 | ||
94 | /* | 91 | /* |
diff --git a/kernel/module.c b/kernel/module.c index 04379f92f843..93342d992f34 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -3487,50 +3487,3 @@ void module_layout(struct module *mod, | |||
3487 | } | 3487 | } |
3488 | EXPORT_SYMBOL(module_layout); | 3488 | EXPORT_SYMBOL(module_layout); |
3489 | #endif | 3489 | #endif |
3490 | |||
3491 | #ifdef CONFIG_TRACEPOINTS | ||
3492 | void module_update_tracepoints(void) | ||
3493 | { | ||
3494 | struct module *mod; | ||
3495 | |||
3496 | mutex_lock(&module_mutex); | ||
3497 | list_for_each_entry(mod, &modules, list) | ||
3498 | if (!mod->taints) | ||
3499 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | ||
3500 | mod->tracepoints_ptrs + mod->num_tracepoints); | ||
3501 | mutex_unlock(&module_mutex); | ||
3502 | } | ||
3503 | |||
3504 | /* | ||
3505 | * Returns 0 if current not found. | ||
3506 | * Returns 1 if current found. | ||
3507 | */ | ||
3508 | int module_get_iter_tracepoints(struct tracepoint_iter *iter) | ||
3509 | { | ||
3510 | struct module *iter_mod; | ||
3511 | int found = 0; | ||
3512 | |||
3513 | mutex_lock(&module_mutex); | ||
3514 | list_for_each_entry(iter_mod, &modules, list) { | ||
3515 | if (!iter_mod->taints) { | ||
3516 | /* | ||
3517 | * Sorted module list | ||
3518 | */ | ||
3519 | if (iter_mod < iter->module) | ||
3520 | continue; | ||
3521 | else if (iter_mod > iter->module) | ||
3522 | iter->tracepoint = NULL; | ||
3523 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
3524 | iter_mod->tracepoints_ptrs, | ||
3525 | iter_mod->tracepoints_ptrs | ||
3526 | + iter_mod->num_tracepoints); | ||
3527 | if (found) { | ||
3528 | iter->module = iter_mod; | ||
3529 | break; | ||
3530 | } | ||
3531 | } | ||
3532 | } | ||
3533 | mutex_unlock(&module_mutex); | ||
3534 | return found; | ||
3535 | } | ||
3536 | #endif | ||
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index b219f1449c54..db110b8ae030 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -34,11 +34,16 @@ extern struct tracepoint * const __stop___tracepoints_ptrs[]; | |||
34 | static const int tracepoint_debug; | 34 | static const int tracepoint_debug; |
35 | 35 | ||
36 | /* | 36 | /* |
37 | * tracepoints_mutex nests inside module_mutex. Tracepoints mutex protects the | 37 | * Tracepoints mutex protects the builtin and module tracepoints and the hash |
38 | * builtin and module tracepoints and the hash table. | 38 | * table, as well as the local module list. |
39 | */ | 39 | */ |
40 | static DEFINE_MUTEX(tracepoints_mutex); | 40 | static DEFINE_MUTEX(tracepoints_mutex); |
41 | 41 | ||
42 | #ifdef CONFIG_MODULES | ||
43 | /* Local list of struct module */ | ||
44 | static LIST_HEAD(tracepoint_module_list); | ||
45 | #endif /* CONFIG_MODULES */ | ||
46 | |||
42 | /* | 47 | /* |
43 | * Tracepoint hash table, containing the active tracepoints. | 48 | * Tracepoint hash table, containing the active tracepoints. |
44 | * Protected by tracepoints_mutex. | 49 | * Protected by tracepoints_mutex. |
@@ -292,9 +297,10 @@ static void disable_tracepoint(struct tracepoint *elem) | |||
292 | * @end: end of the range | 297 | * @end: end of the range |
293 | * | 298 | * |
294 | * Updates the probe callback corresponding to a range of tracepoints. | 299 | * Updates the probe callback corresponding to a range of tracepoints. |
300 | * Called with tracepoints_mutex held. | ||
295 | */ | 301 | */ |
296 | void tracepoint_update_probe_range(struct tracepoint * const *begin, | 302 | static void tracepoint_update_probe_range(struct tracepoint * const *begin, |
297 | struct tracepoint * const *end) | 303 | struct tracepoint * const *end) |
298 | { | 304 | { |
299 | struct tracepoint * const *iter; | 305 | struct tracepoint * const *iter; |
300 | struct tracepoint_entry *mark_entry; | 306 | struct tracepoint_entry *mark_entry; |
@@ -302,7 +308,6 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin, | |||
302 | if (!begin) | 308 | if (!begin) |
303 | return; | 309 | return; |
304 | 310 | ||
305 | mutex_lock(&tracepoints_mutex); | ||
306 | for (iter = begin; iter < end; iter++) { | 311 | for (iter = begin; iter < end; iter++) { |
307 | mark_entry = get_tracepoint((*iter)->name); | 312 | mark_entry = get_tracepoint((*iter)->name); |
308 | if (mark_entry) { | 313 | if (mark_entry) { |
@@ -312,11 +317,27 @@ void tracepoint_update_probe_range(struct tracepoint * const *begin, | |||
312 | disable_tracepoint(*iter); | 317 | disable_tracepoint(*iter); |
313 | } | 318 | } |
314 | } | 319 | } |
315 | mutex_unlock(&tracepoints_mutex); | ||
316 | } | 320 | } |
317 | 321 | ||
322 | #ifdef CONFIG_MODULES | ||
323 | void module_update_tracepoints(void) | ||
324 | { | ||
325 | struct tp_module *tp_mod; | ||
326 | |||
327 | list_for_each_entry(tp_mod, &tracepoint_module_list, list) | ||
328 | tracepoint_update_probe_range(tp_mod->tracepoints_ptrs, | ||
329 | tp_mod->tracepoints_ptrs + tp_mod->num_tracepoints); | ||
330 | } | ||
331 | #else /* CONFIG_MODULES */ | ||
332 | void module_update_tracepoints(void) | ||
333 | { | ||
334 | } | ||
335 | #endif /* CONFIG_MODULES */ | ||
336 | |||
337 | |||
318 | /* | 338 | /* |
319 | * Update probes, removing the faulty probes. | 339 | * Update probes, removing the faulty probes. |
340 | * Called with tracepoints_mutex held. | ||
320 | */ | 341 | */ |
321 | static void tracepoint_update_probes(void) | 342 | static void tracepoint_update_probes(void) |
322 | { | 343 | { |
@@ -359,11 +380,12 @@ int tracepoint_probe_register(const char *name, void *probe, void *data) | |||
359 | 380 | ||
360 | mutex_lock(&tracepoints_mutex); | 381 | mutex_lock(&tracepoints_mutex); |
361 | old = tracepoint_add_probe(name, probe, data); | 382 | old = tracepoint_add_probe(name, probe, data); |
362 | mutex_unlock(&tracepoints_mutex); | 383 | if (IS_ERR(old)) { |
363 | if (IS_ERR(old)) | 384 | mutex_unlock(&tracepoints_mutex); |
364 | return PTR_ERR(old); | 385 | return PTR_ERR(old); |
365 | 386 | } | |
366 | tracepoint_update_probes(); /* may update entry */ | 387 | tracepoint_update_probes(); /* may update entry */ |
388 | mutex_unlock(&tracepoints_mutex); | ||
367 | release_probes(old); | 389 | release_probes(old); |
368 | return 0; | 390 | return 0; |
369 | } | 391 | } |
@@ -402,11 +424,12 @@ int tracepoint_probe_unregister(const char *name, void *probe, void *data) | |||
402 | 424 | ||
403 | mutex_lock(&tracepoints_mutex); | 425 | mutex_lock(&tracepoints_mutex); |
404 | old = tracepoint_remove_probe(name, probe, data); | 426 | old = tracepoint_remove_probe(name, probe, data); |
405 | mutex_unlock(&tracepoints_mutex); | 427 | if (IS_ERR(old)) { |
406 | if (IS_ERR(old)) | 428 | mutex_unlock(&tracepoints_mutex); |
407 | return PTR_ERR(old); | 429 | return PTR_ERR(old); |
408 | 430 | } | |
409 | tracepoint_update_probes(); /* may update entry */ | 431 | tracepoint_update_probes(); /* may update entry */ |
432 | mutex_unlock(&tracepoints_mutex); | ||
410 | release_probes(old); | 433 | release_probes(old); |
411 | return 0; | 434 | return 0; |
412 | } | 435 | } |
@@ -489,9 +512,8 @@ void tracepoint_probe_update_all(void) | |||
489 | if (!list_empty(&old_probes)) | 512 | if (!list_empty(&old_probes)) |
490 | list_replace_init(&old_probes, &release_probes); | 513 | list_replace_init(&old_probes, &release_probes); |
491 | need_update = 0; | 514 | need_update = 0; |
492 | mutex_unlock(&tracepoints_mutex); | ||
493 | |||
494 | tracepoint_update_probes(); | 515 | tracepoint_update_probes(); |
516 | mutex_unlock(&tracepoints_mutex); | ||
495 | list_for_each_entry_safe(pos, next, &release_probes, u.list) { | 517 | list_for_each_entry_safe(pos, next, &release_probes, u.list) { |
496 | list_del(&pos->u.list); | 518 | list_del(&pos->u.list); |
497 | call_rcu_sched(&pos->u.rcu, rcu_free_old_probes); | 519 | call_rcu_sched(&pos->u.rcu, rcu_free_old_probes); |
@@ -509,7 +531,7 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_update_all); | |||
509 | * Will return the first tracepoint in the range if the input tracepoint is | 531 | * Will return the first tracepoint in the range if the input tracepoint is |
510 | * NULL. | 532 | * NULL. |
511 | */ | 533 | */ |
512 | int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, | 534 | static int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, |
513 | struct tracepoint * const *begin, struct tracepoint * const *end) | 535 | struct tracepoint * const *begin, struct tracepoint * const *end) |
514 | { | 536 | { |
515 | if (!*tracepoint && begin != end) { | 537 | if (!*tracepoint && begin != end) { |
@@ -520,11 +542,12 @@ int tracepoint_get_iter_range(struct tracepoint * const **tracepoint, | |||
520 | return 1; | 542 | return 1; |
521 | return 0; | 543 | return 0; |
522 | } | 544 | } |
523 | EXPORT_SYMBOL_GPL(tracepoint_get_iter_range); | ||
524 | 545 | ||
546 | #ifdef CONFIG_MODULES | ||
525 | static void tracepoint_get_iter(struct tracepoint_iter *iter) | 547 | static void tracepoint_get_iter(struct tracepoint_iter *iter) |
526 | { | 548 | { |
527 | int found = 0; | 549 | int found = 0; |
550 | struct tp_module *iter_mod; | ||
528 | 551 | ||
529 | /* Core kernel tracepoints */ | 552 | /* Core kernel tracepoints */ |
530 | if (!iter->module) { | 553 | if (!iter->module) { |
@@ -534,12 +557,43 @@ static void tracepoint_get_iter(struct tracepoint_iter *iter) | |||
534 | if (found) | 557 | if (found) |
535 | goto end; | 558 | goto end; |
536 | } | 559 | } |
537 | /* tracepoints in modules. */ | 560 | /* Tracepoints in modules */ |
538 | found = module_get_iter_tracepoints(iter); | 561 | mutex_lock(&tracepoints_mutex); |
562 | list_for_each_entry(iter_mod, &tracepoint_module_list, list) { | ||
563 | /* | ||
564 | * Sorted module list | ||
565 | */ | ||
566 | if (iter_mod < iter->module) | ||
567 | continue; | ||
568 | else if (iter_mod > iter->module) | ||
569 | iter->tracepoint = NULL; | ||
570 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
571 | iter_mod->tracepoints_ptrs, | ||
572 | iter_mod->tracepoints_ptrs | ||
573 | + iter_mod->num_tracepoints); | ||
574 | if (found) { | ||
575 | iter->module = iter_mod; | ||
576 | break; | ||
577 | } | ||
578 | } | ||
579 | mutex_unlock(&tracepoints_mutex); | ||
539 | end: | 580 | end: |
540 | if (!found) | 581 | if (!found) |
541 | tracepoint_iter_reset(iter); | 582 | tracepoint_iter_reset(iter); |
542 | } | 583 | } |
584 | #else /* CONFIG_MODULES */ | ||
585 | static void tracepoint_get_iter(struct tracepoint_iter *iter) | ||
586 | { | ||
587 | int found = 0; | ||
588 | |||
589 | /* Core kernel tracepoints */ | ||
590 | found = tracepoint_get_iter_range(&iter->tracepoint, | ||
591 | __start___tracepoints_ptrs, | ||
592 | __stop___tracepoints_ptrs); | ||
593 | if (!found) | ||
594 | tracepoint_iter_reset(iter); | ||
595 | } | ||
596 | #endif /* CONFIG_MODULES */ | ||
543 | 597 | ||
544 | void tracepoint_iter_start(struct tracepoint_iter *iter) | 598 | void tracepoint_iter_start(struct tracepoint_iter *iter) |
545 | { | 599 | { |
@@ -566,26 +620,98 @@ EXPORT_SYMBOL_GPL(tracepoint_iter_stop); | |||
566 | 620 | ||
567 | void tracepoint_iter_reset(struct tracepoint_iter *iter) | 621 | void tracepoint_iter_reset(struct tracepoint_iter *iter) |
568 | { | 622 | { |
623 | #ifdef CONFIG_MODULES | ||
569 | iter->module = NULL; | 624 | iter->module = NULL; |
625 | #endif /* CONFIG_MODULES */ | ||
570 | iter->tracepoint = NULL; | 626 | iter->tracepoint = NULL; |
571 | } | 627 | } |
572 | EXPORT_SYMBOL_GPL(tracepoint_iter_reset); | 628 | EXPORT_SYMBOL_GPL(tracepoint_iter_reset); |
573 | 629 | ||
574 | #ifdef CONFIG_MODULES | 630 | #ifdef CONFIG_MODULES |
631 | static int tracepoint_module_coming(struct module *mod) | ||
632 | { | ||
633 | struct tp_module *tp_mod, *iter; | ||
634 | int ret = 0; | ||
635 | |||
636 | /* | ||
637 | * We skip modules that tain the kernel, especially those with different | ||
638 | * module header (for forced load), to make sure we don't cause a crash. | ||
639 | */ | ||
640 | if (mod->taints) | ||
641 | return 0; | ||
642 | mutex_lock(&tracepoints_mutex); | ||
643 | tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL); | ||
644 | if (!tp_mod) { | ||
645 | ret = -ENOMEM; | ||
646 | goto end; | ||
647 | } | ||
648 | tp_mod->num_tracepoints = mod->num_tracepoints; | ||
649 | tp_mod->tracepoints_ptrs = mod->tracepoints_ptrs; | ||
650 | |||
651 | /* | ||
652 | * tracepoint_module_list is kept sorted by struct module pointer | ||
653 | * address for iteration on tracepoints from a seq_file that can release | ||
654 | * the mutex between calls. | ||
655 | */ | ||
656 | list_for_each_entry_reverse(iter, &tracepoint_module_list, list) { | ||
657 | BUG_ON(iter == tp_mod); /* Should never be in the list twice */ | ||
658 | if (iter < tp_mod) { | ||
659 | /* We belong to the location right after iter. */ | ||
660 | list_add(&tp_mod->list, &iter->list); | ||
661 | goto module_added; | ||
662 | } | ||
663 | } | ||
664 | /* We belong to the beginning of the list */ | ||
665 | list_add(&tp_mod->list, &tracepoint_module_list); | ||
666 | module_added: | ||
667 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | ||
668 | mod->tracepoints_ptrs + mod->num_tracepoints); | ||
669 | end: | ||
670 | mutex_unlock(&tracepoints_mutex); | ||
671 | return ret; | ||
672 | } | ||
673 | |||
674 | static int tracepoint_module_going(struct module *mod) | ||
675 | { | ||
676 | struct tp_module *pos; | ||
677 | |||
678 | mutex_lock(&tracepoints_mutex); | ||
679 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | ||
680 | mod->tracepoints_ptrs + mod->num_tracepoints); | ||
681 | list_for_each_entry(pos, &tracepoint_module_list, list) { | ||
682 | if (pos->tracepoints_ptrs == mod->tracepoints_ptrs) { | ||
683 | list_del(&pos->list); | ||
684 | kfree(pos); | ||
685 | break; | ||
686 | } | ||
687 | } | ||
688 | /* | ||
689 | * In the case of modules that were tainted at "coming", we'll simply | ||
690 | * walk through the list without finding it. We cannot use the "tainted" | ||
691 | * flag on "going", in case a module taints the kernel only after being | ||
692 | * loaded. | ||
693 | */ | ||
694 | mutex_unlock(&tracepoints_mutex); | ||
695 | return 0; | ||
696 | } | ||
575 | 697 | ||
576 | int tracepoint_module_notify(struct notifier_block *self, | 698 | int tracepoint_module_notify(struct notifier_block *self, |
577 | unsigned long val, void *data) | 699 | unsigned long val, void *data) |
578 | { | 700 | { |
579 | struct module *mod = data; | 701 | struct module *mod = data; |
702 | int ret = 0; | ||
580 | 703 | ||
581 | switch (val) { | 704 | switch (val) { |
582 | case MODULE_STATE_COMING: | 705 | case MODULE_STATE_COMING: |
706 | ret = tracepoint_module_coming(mod); | ||
707 | break; | ||
708 | case MODULE_STATE_LIVE: | ||
709 | break; | ||
583 | case MODULE_STATE_GOING: | 710 | case MODULE_STATE_GOING: |
584 | tracepoint_update_probe_range(mod->tracepoints_ptrs, | 711 | ret = tracepoint_module_going(mod); |
585 | mod->tracepoints_ptrs + mod->num_tracepoints); | ||
586 | break; | 712 | break; |
587 | } | 713 | } |
588 | return 0; | 714 | return ret; |
589 | } | 715 | } |
590 | 716 | ||
591 | struct notifier_block tracepoint_module_nb = { | 717 | struct notifier_block tracepoint_module_nb = { |
@@ -598,7 +724,6 @@ static int init_tracepoints(void) | |||
598 | return register_module_notifier(&tracepoint_module_nb); | 724 | return register_module_notifier(&tracepoint_module_nb); |
599 | } | 725 | } |
600 | __initcall(init_tracepoints); | 726 | __initcall(init_tracepoints); |
601 | |||
602 | #endif /* CONFIG_MODULES */ | 727 | #endif /* CONFIG_MODULES */ |
603 | 728 | ||
604 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | 729 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |