From: Song Chen <[email protected]>

Like kprobe, fprobe and btf, this patch attempts to introduce
a notifier_block for ftrace to decouple its initialization from
load_module.

Below is the table of ftrace fucntions calls in different
module state:

        MODULE_STATE_UNFORMED   ftrace_module_init
        MODULE_STATE_COMING     ftrace_module_enable
        MODULE_STATE_LIVE       ftrace_free_mem
        MODULE_STATE_GOING      ftrace_release_mod

Unlike others, ftrace module notifier must take care of state
MODULE_STATE_UNFORMED to ensure calling ftrace_module_init
before complete_formation which changes module's text property.

That pretty much remains same logic with its original design,
the only thing that changes is blocking_notifier_call_chain
(MODULE_STATE_GOING) has to be moved from coming_cleanup to
ddebug_cleanup in function load_module to ensure
ftrace_release_mod is invoked in case complete_formation fails.

Signed-off-by: Song Chen <[email protected]>
---
 kernel/module/main.c  | 14 ++++----------
 kernel/trace/ftrace.c | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 710ee30b3bea..5dc0a980e9bd 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -45,7 +45,6 @@
 #include <linux/license.h>
 #include <asm/sections.h>
 #include <linux/tracepoint.h>
-#include <linux/ftrace.h>
 #include <linux/livepatch.h>
 #include <linux/async.h>
 #include <linux/percpu.h>
@@ -836,7 +835,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
        klp_module_going(mod);
-       ftrace_release_mod(mod);
 
        async_synchronize_full();
 
@@ -3067,8 +3065,6 @@ static noinline int do_init_module(struct module *mod)
        if (!mod->async_probe_requested)
                async_synchronize_full();
 
-       ftrace_free_mem(mod, mod->mem[MOD_INIT_TEXT].base,
-                       mod->mem[MOD_INIT_TEXT].base + 
mod->mem[MOD_INIT_TEXT].size);
        mutex_lock(&module_mutex);
        /* Drop initial reference. */
        module_put(mod);
@@ -3131,7 +3127,6 @@ static noinline int do_init_module(struct module *mod)
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
        klp_module_going(mod);
-       ftrace_release_mod(mod);
        free_module(mod);
        wake_up_all(&module_wq);
 
@@ -3278,7 +3273,6 @@ static int prepare_coming_module(struct module *mod)
 {
        int err;
 
-       ftrace_module_enable(mod);
        err = klp_module_coming(mod);
        if (err)
                return err;
@@ -3461,7 +3455,8 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
        init_build_id(mod, info);
 
        /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
-       ftrace_module_init(mod);
+       blocking_notifier_call_chain(&module_notify_list,
+                               MODULE_STATE_UNFORMED, mod);
 
        /* Finally it's fully formed, ready to start executing. */
        err = complete_formation(mod, info);
@@ -3513,8 +3508,6 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
  coming_cleanup:
        mod->state = MODULE_STATE_GOING;
        destroy_params(mod->kp, mod->num_kp);
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_GOING, mod);
        klp_module_going(mod);
  bug_cleanup:
        mod->state = MODULE_STATE_GOING;
@@ -3524,7 +3517,8 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
        mutex_unlock(&module_mutex);
 
  ddebug_cleanup:
-       ftrace_release_mod(mod);
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_GOING, mod);
        synchronize_rcu();
        kfree(mod->args);
  free_arch_cleanup:
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 3ec2033c0774..47c74d4a2425 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -5223,6 +5223,43 @@ static int __init ftrace_mod_cmd_init(void)
 }
 core_initcall(ftrace_mod_cmd_init);
 
+static int ftrace_module_callback(struct notifier_block *nb, unsigned long op,
+                       void *module)
+{
+       struct module *mod = module;
+
+       switch (op) {
+       case MODULE_STATE_UNFORMED:
+               ftrace_module_init(mod);
+               break;
+       case MODULE_STATE_COMING:
+               ftrace_module_enable(mod);
+               break;
+       case MODULE_STATE_LIVE:
+               ftrace_free_mem(mod, mod->mem[MOD_INIT_TEXT].base,
+                               mod->mem[MOD_INIT_TEXT].base + 
mod->mem[MOD_INIT_TEXT].size);
+               break;
+       case MODULE_STATE_GOING:
+               ftrace_release_mod(mod);
+               break;
+       default:
+               break;
+       }
+
+       return notifier_from_errno(0);
+}
+
+static struct notifier_block ftrace_module_nb = {
+       .notifier_call = ftrace_module_callback,
+       .priority = 0
+};
+
+static int __init ftrace_register_module_notifier(void)
+{
+       return register_module_notifier(&ftrace_module_nb);
+}
+core_initcall(ftrace_register_module_notifier);
+
 static void function_trace_probe_call(unsigned long ip, unsigned long 
parent_ip,
                                      struct ftrace_ops *op, struct ftrace_regs 
*fregs)
 {
-- 
2.43.0


Reply via email to