aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/ftrace.h
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-04-24 10:40:12 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-04-28 10:37:21 -0400
commita949ae560a511fe4e3adf48fa44fefded93e5c2b (patch)
treec47563e7c5696f264050aa5e049ad6f69787f536 /include/linux/ftrace.h
parenta798c10faf62a505d24e5f6213fbaf904a39623f (diff)
ftrace/module: Hardcode ftrace_module_init() call into load_module()
A race exists between module loading and enabling of function tracer. CPU 1 CPU 2 ----- ----- load_module() module->state = MODULE_STATE_COMING register_ftrace_function() mutex_lock(&ftrace_lock); ftrace_startup() update_ftrace_function(); ftrace_arch_code_modify_prepare() set_all_module_text_rw(); <enables-ftrace> ftrace_arch_code_modify_post_process() set_all_module_text_ro(); [ here all module text is set to RO, including the module that is loading!! ] blocking_notifier_call_chain(MODULE_STATE_COMING); ftrace_init_module() [ tries to modify code, but it's RO, and fails! ftrace_bug() is called] When this race happens, ftrace_bug() will produces a nasty warning and all of the function tracing features will be disabled until reboot. The simple solution is to treate module load the same way the core kernel is treated at boot. To hardcode the ftrace function modification of converting calls to mcount into nops. This is done in init/main.c there's no reason it could not be done in load_module(). This gives a better control of the changes and doesn't tie the state of the module to its notifiers as much. Ftrace is special, it needs to be treated as such. The reason this would work, is that the ftrace_module_init() would be called while the module is in MODULE_STATE_UNFORMED, which is ignored by the set_all_module_text_ro() call. Link: http://lkml.kernel.org/r/1395637826-3312-1-git-send-email-indou.takao@jp.fujitsu.com Reported-by: Takao Indoh <indou.takao@jp.fujitsu.com> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Cc: stable@vger.kernel.org # 2.6.38+ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'include/linux/ftrace.h')
-rw-r--r--include/linux/ftrace.h2
1 files changed, 2 insertions, 0 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9212b017bc72..ae9504b4b67d 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -535,6 +535,7 @@ static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_a
535extern int ftrace_arch_read_dyn_info(char *buf, int size); 535extern int ftrace_arch_read_dyn_info(char *buf, int size);
536 536
537extern int skip_trace(unsigned long ip); 537extern int skip_trace(unsigned long ip);
538extern void ftrace_module_init(struct module *mod);
538 539
539extern void ftrace_disable_daemon(void); 540extern void ftrace_disable_daemon(void);
540extern void ftrace_enable_daemon(void); 541extern void ftrace_enable_daemon(void);
@@ -544,6 +545,7 @@ static inline int ftrace_force_update(void) { return 0; }
544static inline void ftrace_disable_daemon(void) { } 545static inline void ftrace_disable_daemon(void) { }
545static inline void ftrace_enable_daemon(void) { } 546static inline void ftrace_enable_daemon(void) { }
546static inline void ftrace_release_mod(struct module *mod) {} 547static inline void ftrace_release_mod(struct module *mod) {}
548static inline void ftrace_module_init(struct module *mod) {}
547static inline __init int register_ftrace_command(struct ftrace_func_command *cmd) 549static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
548{ 550{
549 return -EINVAL; 551 return -EINVAL;