]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/module.c
drivers/base/cpu.c: Fix typo in comment
[karo-tx-linux.git] / kernel / module.c
index 250092c1d57d6cf582ef801f70a10969e19abab2..b10b048367e14b0e89f6b7bfc5e740afd666516b 100644 (file)
@@ -3013,6 +3013,12 @@ static int do_init_module(struct module *mod)
 {
        int ret = 0;
 
+       /*
+        * We want to find out whether @mod uses async during init.  Clear
+        * PF_USED_ASYNC.  async_schedule*() will set it.
+        */
+       current->flags &= ~PF_USED_ASYNC;
+
        blocking_notifier_call_chain(&module_notify_list,
                        MODULE_STATE_COMING, mod);
 
@@ -3058,8 +3064,25 @@ static int do_init_module(struct module *mod)
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_LIVE, mod);
 
-       /* We need to finish all async code before the module init sequence is done */
-       async_synchronize_full();
+       /*
+        * We need to finish all async code before the module init sequence
+        * is done.  This has potential to deadlock.  For example, a newly
+        * detected block device can trigger request_module() of the
+        * default iosched from async probing task.  Once userland helper
+        * reaches here, async_synchronize_full() will wait on the async
+        * task waiting on request_module() and deadlock.
+        *
+        * This deadlock is avoided by perfomring async_synchronize_full()
+        * iff module init queued any async jobs.  This isn't a full
+        * solution as it will deadlock the same if module loading from
+        * async jobs nests more than once; however, due to the various
+        * constraints, this hack seems to be the best option for now.
+        * Please refer to the following thread for details.
+        *
+        * http://thread.gmane.org/gmane.linux.kernel/1420814
+        */
+       if (current->flags & PF_USED_ASYNC)
+               async_synchronize_full();
 
        mutex_lock(&module_mutex);
        /* Drop initial reference. */