aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJessica Yu <jeyu@redhat.com>2016-02-16 17:32:33 -0500
committerJiri Kosina <jkosina@suse.cz>2016-02-17 16:14:06 -0500
commit7dcd182bec271ab341b05b66b6006995795fc0e7 (patch)
treeb2850092d0b57e9c33bb8743ca5053ca6404552d /kernel
parent383bf44d1a8b18de5c26ec2a48c6822681b50984 (diff)
ftrace/module: remove ftrace module notifier
Remove the ftrace module notifier in favor of directly calling ftrace_module_enable() and ftrace_release_mod() in the module loader. Hard-coding the function calls directly in the module loader removes dependence on the module notifier call chain and provides better visibility and control over what gets called when, which is important to kernel utilities such as livepatch. This fixes a notifier ordering issue in which the ftrace module notifier (and hence ftrace_module_enable()) for coming modules was being called after klp_module_notify(), which caused livepatch modules to initialize incorrectly. This patch removes dependence on the module notifier call chain in favor of hard coding the corresponding function calls in the module loader. This ensures that ftrace and livepatch code get called in the correct order on patch module load and unload. Fixes: 5156dca34a3e ("ftrace: Fix the race between ftrace and insmod") Signed-off-by: Jessica Yu <jeyu@redhat.com> Reviewed-by: Steven Rostedt <rostedt@goodmis.org> Reviewed-by: Petr Mladek <pmladek@suse.cz> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Reviewed-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/module.c4
-rw-r--r--kernel/trace/ftrace.c36
2 files changed, 5 insertions, 35 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 8358f4697c0c..b05d466cfa02 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -981,6 +981,8 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
981 mod->exit(); 981 mod->exit();
982 blocking_notifier_call_chain(&module_notify_list, 982 blocking_notifier_call_chain(&module_notify_list,
983 MODULE_STATE_GOING, mod); 983 MODULE_STATE_GOING, mod);
984 ftrace_release_mod(mod);
985
984 async_synchronize_full(); 986 async_synchronize_full();
985 987
986 /* Store the name of the last unloaded module for diagnostic purposes */ 988 /* Store the name of the last unloaded module for diagnostic purposes */
@@ -3295,6 +3297,7 @@ fail:
3295 module_put(mod); 3297 module_put(mod);
3296 blocking_notifier_call_chain(&module_notify_list, 3298 blocking_notifier_call_chain(&module_notify_list,
3297 MODULE_STATE_GOING, mod); 3299 MODULE_STATE_GOING, mod);
3300 ftrace_release_mod(mod);
3298 free_module(mod); 3301 free_module(mod);
3299 wake_up_all(&module_wq); 3302 wake_up_all(&module_wq);
3300 return ret; 3303 return ret;
@@ -3371,6 +3374,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
3371 mod->state = MODULE_STATE_COMING; 3374 mod->state = MODULE_STATE_COMING;
3372 mutex_unlock(&module_mutex); 3375 mutex_unlock(&module_mutex);
3373 3376
3377 ftrace_module_enable(mod);
3374 blocking_notifier_call_chain(&module_notify_list, 3378 blocking_notifier_call_chain(&module_notify_list,
3375 MODULE_STATE_COMING, mod); 3379 MODULE_STATE_COMING, mod);
3376 return 0; 3380 return 0;
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index eca592f977b2..57a6eea84694 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4961,7 +4961,7 @@ void ftrace_release_mod(struct module *mod)
4961 mutex_unlock(&ftrace_lock); 4961 mutex_unlock(&ftrace_lock);
4962} 4962}
4963 4963
4964static void ftrace_module_enable(struct module *mod) 4964void ftrace_module_enable(struct module *mod)
4965{ 4965{
4966 struct dyn_ftrace *rec; 4966 struct dyn_ftrace *rec;
4967 struct ftrace_page *pg; 4967 struct ftrace_page *pg;
@@ -5038,38 +5038,8 @@ void ftrace_module_init(struct module *mod)
5038 ftrace_process_locs(mod, mod->ftrace_callsites, 5038 ftrace_process_locs(mod, mod->ftrace_callsites,
5039 mod->ftrace_callsites + mod->num_ftrace_callsites); 5039 mod->ftrace_callsites + mod->num_ftrace_callsites);
5040} 5040}
5041
5042static int ftrace_module_notify(struct notifier_block *self,
5043 unsigned long val, void *data)
5044{
5045 struct module *mod = data;
5046
5047 switch (val) {
5048 case MODULE_STATE_COMING:
5049 ftrace_module_enable(mod);
5050 break;
5051 case MODULE_STATE_GOING:
5052 ftrace_release_mod(mod);
5053 break;
5054 default:
5055 break;
5056 }
5057
5058 return 0;
5059}
5060#else
5061static int ftrace_module_notify(struct notifier_block *self,
5062 unsigned long val, void *data)
5063{
5064 return 0;
5065}
5066#endif /* CONFIG_MODULES */ 5041#endif /* CONFIG_MODULES */
5067 5042
5068struct notifier_block ftrace_module_nb = {
5069 .notifier_call = ftrace_module_notify,
5070 .priority = INT_MIN, /* Run after anything that can remove kprobes */
5071};
5072
5073void __init ftrace_init(void) 5043void __init ftrace_init(void)
5074{ 5044{
5075 extern unsigned long __start_mcount_loc[]; 5045 extern unsigned long __start_mcount_loc[];
@@ -5098,10 +5068,6 @@ void __init ftrace_init(void)
5098 __start_mcount_loc, 5068 __start_mcount_loc,
5099 __stop_mcount_loc); 5069 __stop_mcount_loc);
5100 5070
5101 ret = register_module_notifier(&ftrace_module_nb);
5102 if (ret)
5103 pr_warning("Failed to register trace ftrace module exit notifier\n");
5104
5105 set_ftrace_early_filters(); 5071 set_ftrace_early_filters();
5106 5072
5107 return; 5073 return;