Move idempotent definition up and add idempotent_complete declaration.

Add idempotent to struct load_info which gets passed into load_module
and then stored in the struct module.

run idempotent_complete after module is unloaded and give EBUSY
to any process waiting for the module to finish initializing
via finit_module.

Signed-off-by: julian-lagattuta <julian.lagatt...@gmail.com>
---
 kernel/module/internal.h |  3 +++
 kernel/module/main.c     | 29 +++++++++++++++++++++--------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 8d74b0a21c82..43f537475859 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -89,6 +89,9 @@ struct load_info {
                unsigned int vers_ext_crc;
                unsigned int vers_ext_name;
        } index;
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       struct idempotent* idempotent;
+#endif
 };
 
 enum mod_license {
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 217185dbc3c1..256e30259bcf 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -80,6 +80,17 @@ static void do_free_init(struct work_struct *w);
 static DECLARE_WORK(init_free_wq, do_free_init);
 static LLIST_HEAD(init_free_list);
 
+
+struct idempotent {
+       const void *cookie;
+       struct hlist_node entry;
+       struct completion complete;
+       int ret;
+};
+
+static int idempotent_complete(struct idempotent *u, int ret);
+
+
 struct mod_tree_root mod_tree __cacheline_aligned = {
        .addr_min = -1UL,
 };
@@ -784,7 +795,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
                !IS_ENABLED(CONFIG_MODULE_FORCE_UNLOAD))
        ) {
                if (mod->state == MODULE_STATE_GOING)
-               pr_debug("%s already dying\n", mod->name);
+                       pr_debug("%s already dying\n", mod->name);
                ret = -EBUSY;
                goto out;
        }
@@ -833,6 +844,11 @@ SYSCALL_DEFINE2(delete_module, const char __user *, 
name_user,
        strscpy(last_unloaded_module.name, mod->name);
        strscpy(last_unloaded_module.taints, module_flags(mod, buf, false));
 
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       if (did_init_crash && mod->idempotent)
+               idempotent_complete(mod->idempotent, -EBUSY);
+#endif
+
        free_module(mod);
        /* someone could wait for the module in add_unformed_module() */
        wake_up_all(&module_wq);
@@ -3591,12 +3607,6 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        return load_module(&info, uargs, 0);
 }
 
-struct idempotent {
-       const void *cookie;
-       struct hlist_node entry;
-       struct completion complete;
-       int ret;
-};
 
 #define IDEM_HASH_BITS 8
 static struct hlist_head idem_hash[1 << IDEM_HASH_BITS];
@@ -3683,7 +3693,7 @@ static int idempotent_wait_for_completion(struct 
idempotent *u)
        return ret;
 }
 
-static int init_module_from_file(struct file *f, const char __user * uargs, 
int flags)
+static int init_module_from_file(struct file *f, const char __user * uargs, 
int flags, struct idempotent *idempotent __maybe_unused)
 {
        struct load_info info = { };
        void *buf = NULL;
@@ -3707,6 +3717,9 @@ static int init_module_from_file(struct file *f, const 
char __user * uargs, int
                info.hdr = buf;
                info.len = len;
        }
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+       info.idempotent = idempotent;
+#endif
 
        return load_module(&info, uargs, flags);
 }
-- 
2.45.2


Reply via email to