aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c90
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
919void 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
943static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) 919static 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
2755void ftrace_init_module(struct module *mod, 2731#ifdef CONFIG_MODULES
2756 unsigned long *start, unsigned long *end) 2732void 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
2756static 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
2764static 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
2785static int ftrace_module_notify(struct notifier_block *self,
2786 unsigned long val, void *data)
2787{
2788 return 0;
2789}
2790#endif /* CONFIG_MODULES */
2791
2792struct notifier_block ftrace_module_nb = {
2793 .notifier_call = ftrace_module_notify,
2794 .priority = 0,
2795};
2796
2763extern unsigned long __start_mcount_loc[]; 2797extern unsigned long __start_mcount_loc[];
2764extern unsigned long __stop_mcount_loc[]; 2798extern 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;