diff options
-rw-r--r-- | include/linux/ftrace.h | 7 | ||||
-rw-r--r-- | include/linux/module.h | 4 | ||||
-rw-r--r-- | kernel/module.c | 19 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 90 |
4 files changed, 75 insertions, 45 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 53869bef6102..97c83e1bc589 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -233,8 +233,6 @@ extern int ftrace_arch_read_dyn_info(char *buf, int size); | |||
233 | 233 | ||
234 | extern int skip_trace(unsigned long ip); | 234 | extern int skip_trace(unsigned long ip); |
235 | 235 | ||
236 | extern void ftrace_release(void *start, unsigned long size); | ||
237 | |||
238 | extern void ftrace_disable_daemon(void); | 236 | extern void ftrace_disable_daemon(void); |
239 | extern void ftrace_enable_daemon(void); | 237 | extern void ftrace_enable_daemon(void); |
240 | #else | 238 | #else |
@@ -325,13 +323,8 @@ static inline void __ftrace_enabled_restore(int enabled) | |||
325 | 323 | ||
326 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | 324 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD |
327 | extern void ftrace_init(void); | 325 | extern void ftrace_init(void); |
328 | extern void ftrace_init_module(struct module *mod, | ||
329 | unsigned long *start, unsigned long *end); | ||
330 | #else | 326 | #else |
331 | static inline void ftrace_init(void) { } | 327 | static inline void ftrace_init(void) { } |
332 | static inline void | ||
333 | ftrace_init_module(struct module *mod, | ||
334 | unsigned long *start, unsigned long *end) { } | ||
335 | #endif | 328 | #endif |
336 | 329 | ||
337 | /* | 330 | /* |
diff --git a/include/linux/module.h b/include/linux/module.h index 6155fa44168b..a8f2c0aa4c32 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -341,6 +341,10 @@ struct module | |||
341 | struct ftrace_event_call *trace_events; | 341 | struct ftrace_event_call *trace_events; |
342 | unsigned int num_trace_events; | 342 | unsigned int num_trace_events; |
343 | #endif | 343 | #endif |
344 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | ||
345 | unsigned long *ftrace_callsites; | ||
346 | unsigned int num_ftrace_callsites; | ||
347 | #endif | ||
344 | 348 | ||
345 | #ifdef CONFIG_MODULE_UNLOAD | 349 | #ifdef CONFIG_MODULE_UNLOAD |
346 | /* What modules depend on me? */ | 350 | /* What modules depend on me? */ |
diff --git a/kernel/module.c b/kernel/module.c index a0394706f10c..2383e60fcf3f 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1490,9 +1490,6 @@ static void free_module(struct module *mod) | |||
1490 | /* Free any allocated parameters. */ | 1490 | /* Free any allocated parameters. */ |
1491 | destroy_params(mod->kp, mod->num_kp); | 1491 | destroy_params(mod->kp, mod->num_kp); |
1492 | 1492 | ||
1493 | /* release any pointers to mcount in this module */ | ||
1494 | ftrace_release(mod->module_core, mod->core_size); | ||
1495 | |||
1496 | /* This may be NULL, but that's OK */ | 1493 | /* This may be NULL, but that's OK */ |
1497 | module_free(mod, mod->module_init); | 1494 | module_free(mod, mod->module_init); |
1498 | kfree(mod->args); | 1495 | kfree(mod->args); |
@@ -1893,11 +1890,9 @@ static noinline struct module *load_module(void __user *umod, | |||
1893 | unsigned int symindex = 0; | 1890 | unsigned int symindex = 0; |
1894 | unsigned int strindex = 0; | 1891 | unsigned int strindex = 0; |
1895 | unsigned int modindex, versindex, infoindex, pcpuindex; | 1892 | unsigned int modindex, versindex, infoindex, pcpuindex; |
1896 | unsigned int num_mcount; | ||
1897 | struct module *mod; | 1893 | struct module *mod; |
1898 | long err = 0; | 1894 | long err = 0; |
1899 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1895 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
1900 | unsigned long *mseg; | ||
1901 | mm_segment_t old_fs; | 1896 | mm_segment_t old_fs; |
1902 | 1897 | ||
1903 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 1898 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
@@ -2179,7 +2174,13 @@ static noinline struct module *load_module(void __user *umod, | |||
2179 | sizeof(*mod->trace_events), | 2174 | sizeof(*mod->trace_events), |
2180 | &mod->num_trace_events); | 2175 | &mod->num_trace_events); |
2181 | #endif | 2176 | #endif |
2182 | 2177 | #ifdef CONFIG_FTRACE_MCOUNT_RECORD | |
2178 | /* sechdrs[0].sh_size is always zero */ | ||
2179 | mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings, | ||
2180 | "__mcount_loc", | ||
2181 | sizeof(*mod->ftrace_callsites), | ||
2182 | &mod->num_ftrace_callsites); | ||
2183 | #endif | ||
2183 | #ifdef CONFIG_MODVERSIONS | 2184 | #ifdef CONFIG_MODVERSIONS |
2184 | if ((mod->num_syms && !mod->crcs) | 2185 | if ((mod->num_syms && !mod->crcs) |
2185 | || (mod->num_gpl_syms && !mod->gpl_crcs) | 2186 | || (mod->num_gpl_syms && !mod->gpl_crcs) |
@@ -2244,11 +2245,6 @@ static noinline struct module *load_module(void __user *umod, | |||
2244 | dynamic_debug_setup(debug, num_debug); | 2245 | dynamic_debug_setup(debug, num_debug); |
2245 | } | 2246 | } |
2246 | 2247 | ||
2247 | /* sechdrs[0].sh_size is always zero */ | ||
2248 | mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", | ||
2249 | sizeof(*mseg), &num_mcount); | ||
2250 | ftrace_init_module(mod, mseg, mseg + num_mcount); | ||
2251 | |||
2252 | err = module_finalize(hdr, sechdrs, mod); | 2248 | err = module_finalize(hdr, sechdrs, mod); |
2253 | if (err < 0) | 2249 | if (err < 0) |
2254 | goto cleanup; | 2250 | goto cleanup; |
@@ -2309,7 +2305,6 @@ static noinline struct module *load_module(void __user *umod, | |||
2309 | cleanup: | 2305 | cleanup: |
2310 | kobject_del(&mod->mkobj.kobj); | 2306 | kobject_del(&mod->mkobj.kobj); |
2311 | kobject_put(&mod->mkobj.kobj); | 2307 | kobject_put(&mod->mkobj.kobj); |
2312 | ftrace_release(mod->module_core, mod->core_size); | ||
2313 | free_unload: | 2308 | free_unload: |
2314 | module_unload_free(mod); | 2309 | module_unload_free(mod); |
2315 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) | 2310 | #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP) |
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; |