aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat)2013-02-13 14:18:38 -0600
committerGreg Kroah-Hartman2013-03-03 16:09:03 -0600
commit85fed56cdbc7973f34524ee9efa885ef66e4d831 (patch)
treea814417ffe6681e4aa9f908f44b8b00d1c3386c1
parentffe56d754e59cdb086b76b95fe0c3a0302ec46c8 (diff)
downloadkernel-common-85fed56cdbc7973f34524ee9efa885ef66e4d831.tar.gz
kernel-common-85fed56cdbc7973f34524ee9efa885ef66e4d831.tar.xz
kernel-common-85fed56cdbc7973f34524ee9efa885ef66e4d831.zip
ftrace: Call ftrace cleanup module notifier after all other notifiers
commit 8c189ea64eea01ca20d102ddb74d6936dd16c579 upstream. Commit: c1bf08ac "ftrace: Be first to run code modification on modules" changed ftrace module notifier's priority to INT_MAX in order to process the ftrace nops before anything else could touch them (namely kprobes). This was the correct thing to do. Unfortunately, the ftrace module notifier also contains the ftrace clean up code. As opposed to the set up code, this code should be run *after* all the module notifiers have run in case a module is doing correct clean-up and unregisters its ftrace hooks. Basically, ftrace needs to do clean up on module removal, as it needs to know about code being removed so that it doesn't try to modify that code. But after it removes the module from its records, if a ftrace user tries to remove a probe, that removal will fail due as the record of that code segment no longer exists. Nothing really bad happens if the probe removal is called after ftrace did the clean up, but the ftrace removal function will return an error. Correct code (such as kprobes) will produce a WARN_ON() if it fails to remove the probe. As people get annoyed by frivolous warnings, it's best to do the ftrace clean up after everything else. By splitting the ftrace_module_notifier into two notifiers, one that does the module load setup that is run at high priority, and the other that is called for module clean up that is run at low priority, the problem is solved. Reported-by: Frank Ch. Eigler <fche@redhat.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/trace/ftrace.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index e96eee3a860..86fd4170d24 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3432,37 +3432,51 @@ static void ftrace_init_module(struct module *mod,
3432 ftrace_process_locs(mod, start, end); 3432 ftrace_process_locs(mod, start, end);
3433} 3433}
3434 3434
3435static int ftrace_module_notify(struct notifier_block *self, 3435static int ftrace_module_notify_enter(struct notifier_block *self,
3436 unsigned long val, void *data) 3436 unsigned long val, void *data)
3437{ 3437{
3438 struct module *mod = data; 3438 struct module *mod = data;
3439 3439
3440 switch (val) { 3440 if (val == MODULE_STATE_COMING)
3441 case MODULE_STATE_COMING:
3442 ftrace_init_module(mod, mod->ftrace_callsites, 3441 ftrace_init_module(mod, mod->ftrace_callsites,
3443 mod->ftrace_callsites + 3442 mod->ftrace_callsites +
3444 mod->num_ftrace_callsites); 3443 mod->num_ftrace_callsites);
3445 break; 3444 return 0;
3446 case MODULE_STATE_GOING: 3445}
3446
3447static int ftrace_module_notify_exit(struct notifier_block *self,
3448 unsigned long val, void *data)
3449{
3450 struct module *mod = data;
3451
3452 if (val == MODULE_STATE_GOING)
3447 ftrace_release_mod(mod); 3453 ftrace_release_mod(mod);
3448 break;
3449 }
3450 3454
3451 return 0; 3455 return 0;
3452} 3456}
3453#else 3457#else
3454static int ftrace_module_notify(struct notifier_block *self, 3458static int ftrace_module_notify_enter(struct notifier_block *self,
3455 unsigned long val, void *data) 3459 unsigned long val, void *data)
3460{
3461 return 0;
3462}
3463static int ftrace_module_notify_exit(struct notifier_block *self,
3464 unsigned long val, void *data)
3456{ 3465{
3457 return 0; 3466 return 0;
3458} 3467}
3459#endif /* CONFIG_MODULES */ 3468#endif /* CONFIG_MODULES */
3460 3469
3461struct notifier_block ftrace_module_nb = { 3470struct notifier_block ftrace_module_enter_nb = {
3462 .notifier_call = ftrace_module_notify, 3471 .notifier_call = ftrace_module_notify_enter,
3463 .priority = INT_MAX, /* Run before anything that can use kprobes */ 3472 .priority = INT_MAX, /* Run before anything that can use kprobes */
3464}; 3473};
3465 3474
3475struct notifier_block ftrace_module_exit_nb = {
3476 .notifier_call = ftrace_module_notify_exit,
3477 .priority = INT_MIN, /* Run after anything that can remove kprobes */
3478};
3479
3466extern unsigned long __start_mcount_loc[]; 3480extern unsigned long __start_mcount_loc[];
3467extern unsigned long __stop_mcount_loc[]; 3481extern unsigned long __stop_mcount_loc[];
3468 3482
@@ -3494,9 +3508,13 @@ void __init ftrace_init(void)
3494 __start_mcount_loc, 3508 __start_mcount_loc,
3495 __stop_mcount_loc); 3509 __stop_mcount_loc);
3496 3510
3497 ret = register_module_notifier(&ftrace_module_nb); 3511 ret = register_module_notifier(&ftrace_module_enter_nb);
3512 if (ret)
3513 pr_warning("Failed to register trace ftrace module enter notifier\n");
3514
3515 ret = register_module_notifier(&ftrace_module_exit_nb);
3498 if (ret) 3516 if (ret)
3499 pr_warning("Failed to register trace ftrace module notifier\n"); 3517 pr_warning("Failed to register trace ftrace module exit notifier\n");
3500 3518
3501 set_ftrace_early_filters(); 3519 set_ftrace_early_filters();
3502 3520