diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 90 |
1 files changed, 64 insertions, 26 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a23488988581..5b606f45b6c4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -916,30 +916,6 @@ static void ftrace_free_rec(struct dyn_ftrace *rec) | |||
916 | rec->flags |= FTRACE_FL_FREE; | 916 | rec->flags |= FTRACE_FL_FREE; |
917 | } | 917 | } |
918 | 918 | ||
919 | void ftrace_release(void *start, unsigned long size) | ||
920 | { | ||
921 | struct dyn_ftrace *rec; | ||
922 | struct ftrace_page *pg; | ||
923 | unsigned long s = (unsigned long)start; | ||
924 | unsigned long e = s + size; | ||
925 | |||
926 | if (ftrace_disabled || !start) | ||
927 | return; | ||
928 | |||
929 | mutex_lock(&ftrace_lock); | ||
930 | do_for_each_ftrace_rec(pg, rec) { | ||
931 | if ((rec->ip >= s) && (rec->ip < e)) { | ||
932 | /* | ||
933 | * rec->ip is changed in ftrace_free_rec() | ||
934 | * It should not between s and e if record was freed. | ||
935 | */ | ||
936 | FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); | ||
937 | ftrace_free_rec(rec); | ||
938 | } | ||
939 | } while_for_each_ftrace_rec(); | ||
940 | mutex_unlock(&ftrace_lock); | ||
941 | } | ||
942 | |||
943 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) | 919 | static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) |
944 | { | 920 | { |
945 | struct dyn_ftrace *rec; | 921 | struct dyn_ftrace *rec; |
@@ -2752,14 +2728,72 @@ static int ftrace_convert_nops(struct module *mod, | |||
2752 | return 0; | 2728 | return 0; |
2753 | } | 2729 | } |
2754 | 2730 | ||
2755 | void ftrace_init_module(struct module *mod, | 2731 | #ifdef CONFIG_MODULES |
2756 | unsigned long *start, unsigned long *end) | 2732 | void ftrace_release(void *start, void *end) |
2733 | { | ||
2734 | struct dyn_ftrace *rec; | ||
2735 | struct ftrace_page *pg; | ||
2736 | unsigned long s = (unsigned long)start; | ||
2737 | unsigned long e = (unsigned long)end; | ||
2738 | |||
2739 | if (ftrace_disabled || !start || start == end) | ||
2740 | return; | ||
2741 | |||
2742 | mutex_lock(&ftrace_lock); | ||
2743 | do_for_each_ftrace_rec(pg, rec) { | ||
2744 | if ((rec->ip >= s) && (rec->ip < e)) { | ||
2745 | /* | ||
2746 | * rec->ip is changed in ftrace_free_rec() | ||
2747 | * It should not between s and e if record was freed. | ||
2748 | */ | ||
2749 | FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); | ||
2750 | ftrace_free_rec(rec); | ||
2751 | } | ||
2752 | } while_for_each_ftrace_rec(); | ||
2753 | mutex_unlock(&ftrace_lock); | ||
2754 | } | ||
2755 | |||
2756 | static void ftrace_init_module(struct module *mod, | ||
2757 | unsigned long *start, unsigned long *end) | ||
2757 | { | 2758 | { |
2758 | if (ftrace_disabled || start == end) | 2759 | if (ftrace_disabled || start == end) |
2759 | return; | 2760 | return; |
2760 | ftrace_convert_nops(mod, start, end); | 2761 | ftrace_convert_nops(mod, start, end); |
2761 | } | 2762 | } |
2762 | 2763 | ||
2764 | static int ftrace_module_notify(struct notifier_block *self, | ||
2765 | unsigned long val, void *data) | ||
2766 | { | ||
2767 | struct module *mod = data; | ||
2768 | |||
2769 | switch (val) { | ||
2770 | case MODULE_STATE_COMING: | ||
2771 | ftrace_init_module(mod, mod->ftrace_callsites, | ||
2772 | mod->ftrace_callsites + | ||
2773 | mod->num_ftrace_callsites); | ||
2774 | break; | ||
2775 | case MODULE_STATE_GOING: | ||
2776 | ftrace_release(mod->ftrace_callsites, | ||
2777 | mod->ftrace_callsites + | ||
2778 | mod->num_ftrace_callsites); | ||
2779 | break; | ||
2780 | } | ||
2781 | |||
2782 | return 0; | ||
2783 | } | ||
2784 | #else | ||
2785 | static int ftrace_module_notify(struct notifier_block *self, | ||
2786 | unsigned long val, void *data) | ||
2787 | { | ||
2788 | return 0; | ||
2789 | } | ||
2790 | #endif /* CONFIG_MODULES */ | ||
2791 | |||
2792 | struct notifier_block ftrace_module_nb = { | ||
2793 | .notifier_call = ftrace_module_notify, | ||
2794 | .priority = 0, | ||
2795 | }; | ||
2796 | |||
2763 | extern unsigned long __start_mcount_loc[]; | 2797 | extern unsigned long __start_mcount_loc[]; |
2764 | extern unsigned long __stop_mcount_loc[]; | 2798 | extern unsigned long __stop_mcount_loc[]; |
2765 | 2799 | ||
@@ -2791,6 +2825,10 @@ void __init ftrace_init(void) | |||
2791 | __start_mcount_loc, | 2825 | __start_mcount_loc, |
2792 | __stop_mcount_loc); | 2826 | __stop_mcount_loc); |
2793 | 2827 | ||
2828 | ret = register_module_notifier(&ftrace_module_nb); | ||
2829 | if (!ret) | ||
2830 | pr_warning("Failed to register trace ftrace module notifier\n"); | ||
2831 | |||
2794 | return; | 2832 | return; |
2795 | failed: | 2833 | failed: |
2796 | ftrace_disabled = 1; | 2834 | ftrace_disabled = 1; |