Skip to content

Commit 5156dca

Browse files
QiuPeiyangrostedt
authored andcommitted
ftrace: Fix the race between ftrace and insmod
We hit ftrace_bug report when booting Android on a 64bit ATOM SOC chip. Basically, there is a race between insmod and ftrace_run_update_code. After load_module=>ftrace_module_init, another thread jumps in to call ftrace_run_update_code=>ftrace_arch_code_modify_prepare =>set_all_modules_text_rw, to change all modules as RW. Since the new module is at MODULE_STATE_UNFORMED, the text attribute is not changed. Then, the 2nd thread goes ahead to change codes. However, load_module continues to call complete_formation=>set_section_ro_nx, then 2nd thread would fail when probing the module's TEXT. The patch fixes it by using notifier to delay the enabling of ftrace records to the time when module is at state MODULE_STATE_COMING. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Qiu Peiyang <[email protected]> Signed-off-by: Zhang Yanmin <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent b7ffffb commit 5156dca

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

kernel/trace/ftrace.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5037,29 +5037,36 @@ void ftrace_module_init(struct module *mod)
50375037

50385038
ftrace_process_locs(mod, mod->ftrace_callsites,
50395039
mod->ftrace_callsites + mod->num_ftrace_callsites);
5040-
ftrace_module_enable(mod);
50415040
}
50425041

5043-
static int ftrace_module_notify_exit(struct notifier_block *self,
5044-
unsigned long val, void *data)
5042+
static int ftrace_module_notify(struct notifier_block *self,
5043+
unsigned long val, void *data)
50455044
{
50465045
struct module *mod = data;
50475046

5048-
if (val == MODULE_STATE_GOING)
5047+
switch (val) {
5048+
case MODULE_STATE_COMING:
5049+
ftrace_module_enable(mod);
5050+
break;
5051+
case MODULE_STATE_GOING:
50495052
ftrace_release_mod(mod);
5053+
break;
5054+
default:
5055+
break;
5056+
}
50505057

50515058
return 0;
50525059
}
50535060
#else
5054-
static int ftrace_module_notify_exit(struct notifier_block *self,
5055-
unsigned long val, void *data)
5061+
static int ftrace_module_notify(struct notifier_block *self,
5062+
unsigned long val, void *data)
50565063
{
50575064
return 0;
50585065
}
50595066
#endif /* CONFIG_MODULES */
50605067

5061-
struct notifier_block ftrace_module_exit_nb = {
5062-
.notifier_call = ftrace_module_notify_exit,
5068+
struct notifier_block ftrace_module_nb = {
5069+
.notifier_call = ftrace_module_notify,
50635070
.priority = INT_MIN, /* Run after anything that can remove kprobes */
50645071
};
50655072

@@ -5091,7 +5098,7 @@ void __init ftrace_init(void)
50915098
__start_mcount_loc,
50925099
__stop_mcount_loc);
50935100

5094-
ret = register_module_notifier(&ftrace_module_exit_nb);
5101+
ret = register_module_notifier(&ftrace_module_nb);
50955102
if (ret)
50965103
pr_warning("Failed to register trace ftrace module exit notifier\n");
50975104

0 commit comments

Comments
 (0)