Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jessica Yu and committed by
Jiri Kosina
7dcd182b 383bf44d

+9 -37
+4 -2
include/linux/ftrace.h
··· 604 604 605 605 extern int skip_trace(unsigned long ip); 606 606 extern void ftrace_module_init(struct module *mod); 607 + extern void ftrace_module_enable(struct module *mod); 607 608 extern void ftrace_release_mod(struct module *mod); 608 609 609 610 extern void ftrace_disable_daemon(void); ··· 614 613 static inline int ftrace_force_update(void) { return 0; } 615 614 static inline void ftrace_disable_daemon(void) { } 616 615 static inline void ftrace_enable_daemon(void) { } 617 - static inline void ftrace_release_mod(struct module *mod) {} 618 - static inline void ftrace_module_init(struct module *mod) {} 616 + static inline void ftrace_module_init(struct module *mod) { } 617 + static inline void ftrace_module_enable(struct module *mod) { } 618 + static inline void ftrace_release_mod(struct module *mod) { } 619 619 static inline __init int register_ftrace_command(struct ftrace_func_command *cmd) 620 620 { 621 621 return -EINVAL;
+4
kernel/module.c
··· 981 981 mod->exit(); 982 982 blocking_notifier_call_chain(&module_notify_list, 983 983 MODULE_STATE_GOING, mod); 984 + ftrace_release_mod(mod); 985 + 984 986 async_synchronize_full(); 985 987 986 988 /* Store the name of the last unloaded module for diagnostic purposes */ ··· 3297 3295 module_put(mod); 3298 3296 blocking_notifier_call_chain(&module_notify_list, 3299 3297 MODULE_STATE_GOING, mod); 3298 + ftrace_release_mod(mod); 3300 3299 free_module(mod); 3301 3300 wake_up_all(&module_wq); 3302 3301 return ret; ··· 3374 3371 mod->state = MODULE_STATE_COMING; 3375 3372 mutex_unlock(&module_mutex); 3376 3373 3374 + ftrace_module_enable(mod); 3377 3375 blocking_notifier_call_chain(&module_notify_list, 3378 3376 MODULE_STATE_COMING, mod); 3379 3377 return 0;
+1 -35
kernel/trace/ftrace.c
··· 4961 4961 mutex_unlock(&ftrace_lock); 4962 4962 } 4963 4963 4964 - static void ftrace_module_enable(struct module *mod) 4964 + void ftrace_module_enable(struct module *mod) 4965 4965 { 4966 4966 struct dyn_ftrace *rec; 4967 4967 struct ftrace_page *pg; ··· 5038 5038 ftrace_process_locs(mod, mod->ftrace_callsites, 5039 5039 mod->ftrace_callsites + mod->num_ftrace_callsites); 5040 5040 } 5041 - 5042 - static 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 5061 - static int ftrace_module_notify(struct notifier_block *self, 5062 - unsigned long val, void *data) 5063 - { 5064 - return 0; 5065 - } 5066 5041 #endif /* CONFIG_MODULES */ 5067 - 5068 - struct notifier_block ftrace_module_nb = { 5069 - .notifier_call = ftrace_module_notify, 5070 - .priority = INT_MIN, /* Run after anything that can remove kprobes */ 5071 - }; 5072 5042 5073 5043 void __init ftrace_init(void) 5074 5044 { ··· 5067 5097 ret = ftrace_process_locs(NULL, 5068 5098 __start_mcount_loc, 5069 5099 __stop_mcount_loc); 5070 - 5071 - ret = register_module_notifier(&ftrace_module_nb); 5072 - if (ret) 5073 - pr_warning("Failed to register trace ftrace module exit notifier\n"); 5074 5100 5075 5101 set_ftrace_early_filters(); 5076 5102