Store idempotent and init_pid in struct module.

Signed-off-by: julian-lagattuta <[email protected]>
---
 kernel/module/main.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 413ac6ea3702..2277c53aef2e 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -752,6 +752,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
        char name[MODULE_NAME_LEN];
        char buf[MODULE_FLAGS_BUF_SIZE];
        int ret, forced = 0;
+       bool did_init_crash __maybe_unused = false;
 
        if (!capable(CAP_SYS_MODULE) || modules_disabled)
                return -EPERM;
@@ -778,8 +779,11 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
        }
 
        /* Doing init or already dying? */
-       if (mod->state != MODULE_STATE_LIVE) {
-               /* FIXME: if (force), slam module count damn the torpedoes */
+       if (mod->state == MODULE_STATE_GOING ||
+               (mod->state != MODULE_STATE_LIVE &&
+               !IS_ENABLED(CONFIG_MODULE_FORCE_UNLOAD))
+       ) {
+               if (mod->state == MODULE_STATE_GOING)
                pr_debug("%s already dying\n", mod->name);
                ret = -EBUSY;
                goto out;
@@ -795,6 +799,21 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
                }
        }
 
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       if (mod->state == MODULE_STATE_COMING) {
+               struct task_struct *init_process = get_pid_task(mod->init_pid, 
PIDTYPE_PID);
+
+               /* Did the init process die? */
+               if (init_process) {
+                       put_task_struct(init_process);
+                       ret = -EBUSY;
+                       goto out;
+               } else {
+                       did_init_crash = true;
+               }
+       }
+#endif
+
        ret = try_stop_module(mod, flags, &forced);
        if (ret != 0)
                goto out;
@@ -1380,6 +1399,10 @@ static void free_module(struct module *mod)
        mod->state = MODULE_STATE_UNFORMED;
        mutex_unlock(&module_mutex);
 
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       if (mod->init_pid)
+               put_pid(mod->init_pid);
+#endif
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -3044,6 +3067,11 @@ static noinline int do_init_module(struct module *mod)
        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);
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       put_pid(mod->init_pid);
+       mod->init_pid = NULL;
+       mod->idempotent = NULL;
+#endif
        /* Drop initial reference. */
        module_put(mod);
        trim_init_extable(mod);
@@ -3474,6 +3502,10 @@ static int load_module(struct load_info *info, const 
char __user *uargs,
        if (codetag_load_module(mod))
                goto sysfs_cleanup;
 
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       mod->init_pid = get_pid(task_pid(current));
+       mod->idempotent = info->idempotent;
+#endif
        /* Get rid of temporary copy. */
        free_copy(info, flags);
 
-- 
2.45.2


Reply via email to