sched, modules: Fix nested sleep in add_unformed_module()
authorPeter Zijlstra <[email protected]>
Wed, 24 Sep 2014 08:18:53 +0000 (10:18 +0200)
committerIngo Molnar <[email protected]>
Tue, 28 Oct 2014 09:56:30 +0000 (10:56 +0100)
This is a genuine bug in add_unformed_module(), we cannot use blocking
primitives inside a wait loop.

So rewrite the wait_event_interruptible() usage to use the fresh
wait_woken() stuff.

Reported-by: Fengguang Wu <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: Rusty Russell <[email protected]>
Cc: [email protected]
Cc: Linus Torvalds <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ So this is probably complex to backport and the race wasn't reported AFAIK,
  so not marked for -stable. ]
Signed-off-by: Ingo Molnar <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
kernel/module.c

index 88cec1ddb1e3c516496b951ae192cba21ff80c90..e52a8739361aac595a5123b08404518fb1ab6fe5 100644 (file)
@@ -3096,6 +3096,32 @@ static int may_init_module(void)
        return 0;
 }
 
+/*
+ * Can't use wait_event_interruptible() because our condition
+ * 'finished_loading()' contains a blocking primitive itself (mutex_lock).
+ */
+static int wait_finished_loading(struct module *mod)
+{
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
+       int ret = 0;
+
+       add_wait_queue(&module_wq, &wait);
+       for (;;) {
+               if (finished_loading(mod->name))
+                       break;
+
+               if (signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+       }
+       remove_wait_queue(&module_wq, &wait);
+
+       return ret;
+}
+
 /*
  * We try to place it in the list now to make sure it's unique before
  * we dedicate too many resources.  In particular, temporary percpu
@@ -3116,8 +3142,8 @@ again:
                    || old->state == MODULE_STATE_UNFORMED) {
                        /* Wait in case it fails to load. */
                        mutex_unlock(&module_mutex);
-                       err = wait_event_interruptible(module_wq,
-                                              finished_loading(mod->name));
+
+                       err = wait_finished_loading(mod);
                        if (err)
                                goto out_unlocked;
                        goto again;