summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/module/main.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/kernel/module/main.c b/kernel/module/main.c
index d9592195c5bb..6f4ec857bdef 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -3183,15 +3183,28 @@ static int idempotent_init_module(struct file *f, const char __user * uargs, int
if (!f || !(f->f_mode & FMODE_READ))
return -EBADF;
- /* See if somebody else is doing the operation? */
- if (idempotent(&idem, file_inode(f))) {
- wait_for_completion(&idem.complete);
- return idem.ret;
+ /* Are we the winners of the race and get to do this? */
+ if (!idempotent(&idem, file_inode(f))) {
+ int ret = init_module_from_file(f, uargs, flags);
+ return idempotent_complete(&idem, ret);
}
- /* Otherwise, we'll do it and complete others */
- return idempotent_complete(&idem,
- init_module_from_file(f, uargs, flags));
+ /*
+ * Somebody else won the race and is loading the module.
+ *
+ * We have to wait for it forever, since our 'idem' is
+ * on the stack and the list entry stays there until
+ * completed (but we could fix it under the idem_lock)
+ *
+ * It's also unclear what a real timeout might be,
+ * but we could maybe at least make this killable
+ * and remove the idem entry in that case?
+ */
+ for (;;) {
+ if (wait_for_completion_timeout(&idem.complete, 10*HZ))
+ return idem.ret;
+ pr_warn_once("module '%pD' taking a long time to load", f);
+ }
}
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)