78 lines
2.7 KiB
Diff
78 lines
2.7 KiB
Diff
|
From: Rusty Russell <rusty@rustcorp.com.au>
|
||
|
Date: Fri, 28 Sep 2012 05:01:03 +0000 (+0930)
|
||
|
Subject: module: wait when loading a module which is currently initializing.
|
||
|
X-Git-Tag: v3.7-rc1~2^2~32
|
||
|
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9bb9c3be568346538
|
||
|
|
||
|
module: wait when loading a module which is currently initializing.
|
||
|
|
||
|
The original module-init-tools module loader used a fnctl lock on the
|
||
|
.ko file to avoid attempts to simultaneously load a module.
|
||
|
Unfortunately, you can't get an exclusive fcntl lock on a read-only
|
||
|
fd, making this not work for read-only mounted filesystems.
|
||
|
module-init-tools has a hacky sleep-and-loop for this now.
|
||
|
|
||
|
It's not that hard to wait in the kernel, and only return -EEXIST once
|
||
|
the first module has finished loading (or continue loading the module
|
||
|
if the first one failed to initialize for some reason). It's also
|
||
|
consistent with what we do for dependent modules which are still loading.
|
||
|
|
||
|
Suggested-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
|
||
|
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
|
||
|
---
|
||
|
|
||
|
diff --git a/kernel/module.c b/kernel/module.c
|
||
|
index 63cf6e7..74bc195 100644
|
||
|
--- a/kernel/module.c
|
||
|
+++ b/kernel/module.c
|
||
|
@@ -2845,6 +2845,20 @@ static int post_relocation(struct module *mod, const struct load_info *info)
|
||
|
return module_finalize(info->hdr, info->sechdrs, mod);
|
||
|
}
|
||
|
|
||
|
+/* Is this module of this name done loading? No locks held. */
|
||
|
+static bool finished_loading(const char *name)
|
||
|
+{
|
||
|
+ struct module *mod;
|
||
|
+ bool ret;
|
||
|
+
|
||
|
+ mutex_lock(&module_mutex);
|
||
|
+ mod = find_module(name);
|
||
|
+ ret = !mod || mod->state != MODULE_STATE_COMING;
|
||
|
+ mutex_unlock(&module_mutex);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
/* Allocate and load the module: note that size of section 0 is always
|
||
|
zero, and we rely on this for optional sections. */
|
||
|
static struct module *load_module(void __user *umod,
|
||
|
@@ -2852,7 +2866,7 @@ static struct module *load_module(void __user *umod,
|
||
|
const char __user *uargs)
|
||
|
{
|
||
|
struct load_info info = { NULL, };
|
||
|
- struct module *mod;
|
||
|
+ struct module *mod, *old;
|
||
|
long err;
|
||
|
|
||
|
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
|
||
|
@@ -2918,8 +2932,18 @@ static struct module *load_module(void __user *umod,
|
||
|
* function to insert in a way safe to concurrent readers.
|
||
|
* The mutex protects against concurrent writers.
|
||
|
*/
|
||
|
+again:
|
||
|
mutex_lock(&module_mutex);
|
||
|
- if (find_module(mod->name)) {
|
||
|
+ if ((old = find_module(mod->name)) != NULL) {
|
||
|
+ if (old->state == MODULE_STATE_COMING) {
|
||
|
+ /* Wait in case it fails to load. */
|
||
|
+ mutex_unlock(&module_mutex);
|
||
|
+ err = wait_event_interruptible(module_wq,
|
||
|
+ finished_loading(mod->name));
|
||
|
+ if (err)
|
||
|
+ goto free_arch_cleanup;
|
||
|
+ goto again;
|
||
|
+ }
|
||
|
err = -EEXIST;
|
||
|
goto unlock;
|
||
|
}
|