[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250918201109.24620-12-julian.lagattuta@gmail.com>
Date: Thu, 18 Sep 2025 16:11:14 -0400
From: julian-lagattuta <julian.lagattuta@...il.com>
To: Luis Chamberlain <mcgrof@...nel.org>,
Petr Pavlu <petr.pavlu@...e.com>
Cc: Sami Tolvanen <samitolvanen@...gle.com>,
Daniel Gomez <da.gomez@...sung.com>,
linux-modules@...r.kernel.org,
linux-kernel@...r.kernel.org,
julian-lagattuta <julian.lagattuta@...il.com>
Subject: [PATCH 5/6] module: store and complete idempotent upon force unloading
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.lagattuta@...il.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
Powered by blists - more mailing lists