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