Commit 735a7ffb739b6efeaeb1e720306ba308eaaeb20e

Authored by Andrew Morton
Committed by Linus Torvalds
1 parent 61ce1efe6e

[PATCH] drivers: wait for threaded probes between initcall levels

The multithreaded-probing code has a problem: after one initcall level (eg,
core_initcall) has been processed, we will then start processing the next
level (postcore_initcall) while the kernel threads which are handling
core_initcall are still executing.  This breaks the guarantees which the
layered initcalls previously gave us.

IOW, we want to be multithreaded _within_ an initcall level, but not between
different levels.

Fix that up by causing the probing code to wait for all outstanding probes at
one level to complete before we start processing the next level.

Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 3 changed files with 57 additions and 10 deletions Side-by-side Diff

... ... @@ -18,6 +18,7 @@
18 18 #include <linux/device.h>
19 19 #include <linux/module.h>
20 20 #include <linux/kthread.h>
  21 +#include <linux/wait.h>
21 22  
22 23 #include "base.h"
23 24 #include "power/power.h"
... ... @@ -70,6 +71,8 @@
70 71 };
71 72  
72 73 static atomic_t probe_count = ATOMIC_INIT(0);
  74 +static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
  75 +
73 76 static int really_probe(void *void_data)
74 77 {
75 78 struct stupid_thread_structure *data = void_data;
... ... @@ -121,6 +124,7 @@
121 124 done:
122 125 kfree(data);
123 126 atomic_dec(&probe_count);
  127 + wake_up(&probe_waitqueue);
124 128 return ret;
125 129 }
126 130  
... ... @@ -337,6 +341,32 @@
337 341 }
338 342 }
339 343  
  344 +#ifdef CONFIG_PCI_MULTITHREAD_PROBE
  345 +static int __init wait_for_probes(void)
  346 +{
  347 + DEFINE_WAIT(wait);
  348 +
  349 + printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__,
  350 + atomic_read(&probe_count));
  351 + if (!atomic_read(&probe_count))
  352 + return 0;
  353 + while (atomic_read(&probe_count)) {
  354 + prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE);
  355 + if (atomic_read(&probe_count))
  356 + schedule();
  357 + }
  358 + finish_wait(&probe_waitqueue, &wait);
  359 + return 0;
  360 +}
  361 +
  362 +core_initcall_sync(wait_for_probes);
  363 +postcore_initcall_sync(wait_for_probes);
  364 +arch_initcall_sync(wait_for_probes);
  365 +subsys_initcall_sync(wait_for_probes);
  366 +fs_initcall_sync(wait_for_probes);
  367 +device_initcall_sync(wait_for_probes);
  368 +late_initcall_sync(wait_for_probes);
  369 +#endif
340 370  
341 371 EXPORT_SYMBOL_GPL(device_bind_driver);
342 372 EXPORT_SYMBOL_GPL(device_release_driver);
include/asm-generic/vmlinux.lds.h
... ... @@ -216,10 +216,17 @@
216 216  
217 217 #define INITCALLS \
218 218 *(.initcall1.init) \
  219 + *(.initcall1s.init) \
219 220 *(.initcall2.init) \
  221 + *(.initcall2s.init) \
220 222 *(.initcall3.init) \
  223 + *(.initcall3s.init) \
221 224 *(.initcall4.init) \
  225 + *(.initcall4s.init) \
222 226 *(.initcall5.init) \
  227 + *(.initcall5s.init) \
223 228 *(.initcall6.init) \
224   - *(.initcall7.init)
  229 + *(.initcall6s.init) \
  230 + *(.initcall7.init) \
  231 + *(.initcall7s.init)
include/linux/init.h
... ... @@ -84,19 +84,29 @@
84 84 * by link order.
85 85 * For backwards compatibility, initcall() puts the call in
86 86 * the device init subsection.
  87 + *
  88 + * The `id' arg to __define_initcall() is needed so that multiple initcalls
  89 + * can point at the same handler without causing duplicate-symbol build errors.
87 90 */
88 91  
89   -#define __define_initcall(level,fn) \
90   - static initcall_t __initcall_##fn __attribute_used__ \
  92 +#define __define_initcall(level,fn,id) \
  93 + static initcall_t __initcall_##fn##id __attribute_used__ \
91 94 __attribute__((__section__(".initcall" level ".init"))) = fn
92 95  
93   -#define core_initcall(fn) __define_initcall("1",fn)
94   -#define postcore_initcall(fn) __define_initcall("2",fn)
95   -#define arch_initcall(fn) __define_initcall("3",fn)
96   -#define subsys_initcall(fn) __define_initcall("4",fn)
97   -#define fs_initcall(fn) __define_initcall("5",fn)
98   -#define device_initcall(fn) __define_initcall("6",fn)
99   -#define late_initcall(fn) __define_initcall("7",fn)
  96 +#define core_initcall(fn) __define_initcall("1",fn,1)
  97 +#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
  98 +#define postcore_initcall(fn) __define_initcall("2",fn,2)
  99 +#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
  100 +#define arch_initcall(fn) __define_initcall("3",fn,3)
  101 +#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
  102 +#define subsys_initcall(fn) __define_initcall("4",fn,4)
  103 +#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
  104 +#define fs_initcall(fn) __define_initcall("5",fn,5)
  105 +#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
  106 +#define device_initcall(fn) __define_initcall("6",fn,6)
  107 +#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
  108 +#define late_initcall(fn) __define_initcall("7",fn,7)
  109 +#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
100 110  
101 111 #define __initcall(fn) device_initcall(fn)
102 112