Commit 2aafe1a4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-fixes-v3.15-rc2' of...

Merge tag 'trace-fixes-v3.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull ftrace bugfix from Steven Rostedt:
 "Takao Indoh reported that he was able to cause a ftrace bug while
  loading a module and enabling function tracing at the same time.

  He uncovered a race where the module when loaded will convert the
  calls to mcount into nops, and expects the module's text to be RW.
  But when function tracing is enabled, it will convert all kernel text
  (core and module) from RO to RW to convert the nops to calls to ftrace
  to record the function.  After the convertion, it will convert all the
  text back from RW to RO.

  The issue is, it will also convert the module's text that is loading.
  If it converts it to RO before ftrace does its conversion, it will
  cause ftrace to fail and require a reboot to fix it again.

  This patch moves the ftrace module update that converts calls to
  mcount into nops to be done when the module state is still
  MODULE_STATE_UNFORMED.  This will ignore the module when the text is
  being converted from RW back to RO"

* tag 'trace-fixes-v3.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  ftrace/module: Hardcode ftrace_module_init() call into load_module()
parents 87c7662b a949ae56
...@@ -535,6 +535,7 @@ static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_a ...@@ -535,6 +535,7 @@ static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_a
extern int ftrace_arch_read_dyn_info(char *buf, int size); extern int ftrace_arch_read_dyn_info(char *buf, int size);
extern int skip_trace(unsigned long ip); extern int skip_trace(unsigned long ip);
extern void ftrace_module_init(struct module *mod);
extern void ftrace_disable_daemon(void); extern void ftrace_disable_daemon(void);
extern void ftrace_enable_daemon(void); extern void ftrace_enable_daemon(void);
...@@ -544,6 +545,7 @@ static inline int ftrace_force_update(void) { return 0; } ...@@ -544,6 +545,7 @@ static inline int ftrace_force_update(void) { return 0; }
static inline void ftrace_disable_daemon(void) { } static inline void ftrace_disable_daemon(void) { }
static inline void ftrace_enable_daemon(void) { } static inline void ftrace_enable_daemon(void) { }
static inline void ftrace_release_mod(struct module *mod) {} static inline void ftrace_release_mod(struct module *mod) {}
static inline void ftrace_module_init(struct module *mod) {}
static inline __init int register_ftrace_command(struct ftrace_func_command *cmd) static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
{ {
return -EINVAL; return -EINVAL;
......
...@@ -3271,6 +3271,9 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -3271,6 +3271,9 @@ static int load_module(struct load_info *info, const char __user *uargs,
dynamic_debug_setup(info->debug, info->num_debug); dynamic_debug_setup(info->debug, info->num_debug);
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
/* Finally it's fully formed, ready to start executing. */ /* Finally it's fully formed, ready to start executing. */
err = complete_formation(mod, info); err = complete_formation(mod, info);
if (err) if (err)
......
...@@ -4330,16 +4330,11 @@ static void ftrace_init_module(struct module *mod, ...@@ -4330,16 +4330,11 @@ static void ftrace_init_module(struct module *mod,
ftrace_process_locs(mod, start, end); ftrace_process_locs(mod, start, end);
} }
static int ftrace_module_notify_enter(struct notifier_block *self, void ftrace_module_init(struct module *mod)
unsigned long val, void *data)
{ {
struct module *mod = data; ftrace_init_module(mod, mod->ftrace_callsites,
mod->ftrace_callsites +
if (val == MODULE_STATE_COMING) mod->num_ftrace_callsites);
ftrace_init_module(mod, mod->ftrace_callsites,
mod->ftrace_callsites +
mod->num_ftrace_callsites);
return 0;
} }
static int ftrace_module_notify_exit(struct notifier_block *self, static int ftrace_module_notify_exit(struct notifier_block *self,
...@@ -4353,11 +4348,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self, ...@@ -4353,11 +4348,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
return 0; return 0;
} }
#else #else
static int ftrace_module_notify_enter(struct notifier_block *self,
unsigned long val, void *data)
{
return 0;
}
static int ftrace_module_notify_exit(struct notifier_block *self, static int ftrace_module_notify_exit(struct notifier_block *self,
unsigned long val, void *data) unsigned long val, void *data)
{ {
...@@ -4365,11 +4355,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self, ...@@ -4365,11 +4355,6 @@ static int ftrace_module_notify_exit(struct notifier_block *self,
} }
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
struct notifier_block ftrace_module_enter_nb = {
.notifier_call = ftrace_module_notify_enter,
.priority = INT_MAX, /* Run before anything that can use kprobes */
};
struct notifier_block ftrace_module_exit_nb = { struct notifier_block ftrace_module_exit_nb = {
.notifier_call = ftrace_module_notify_exit, .notifier_call = ftrace_module_notify_exit,
.priority = INT_MIN, /* Run after anything that can remove kprobes */ .priority = INT_MIN, /* Run after anything that can remove kprobes */
...@@ -4403,10 +4388,6 @@ void __init ftrace_init(void) ...@@ -4403,10 +4388,6 @@ void __init ftrace_init(void)
__start_mcount_loc, __start_mcount_loc,
__stop_mcount_loc); __stop_mcount_loc);
ret = register_module_notifier(&ftrace_module_enter_nb);
if (ret)
pr_warning("Failed to register trace ftrace module enter notifier\n");
ret = register_module_notifier(&ftrace_module_exit_nb); ret = register_module_notifier(&ftrace_module_exit_nb);
if (ret) if (ret)
pr_warning("Failed to register trace ftrace module exit notifier\n"); pr_warning("Failed to register trace ftrace module exit notifier\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment