aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2006-10-27 14:42:37 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-27 18:34:51 -0400
commit735a7ffb739b6efeaeb1e720306ba308eaaeb20e (patch)
tree6156c96aeae04e1fd789f07bdd839dca7eca611a
parent61ce1efe6e40233663d27ab8ac9ba9710eebcaad (diff)
[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>
-rw-r--r--drivers/base/dd.c30
-rw-r--r--include/asm-generic/vmlinux.lds.h9
-rw-r--r--include/linux/init.h28
3 files changed, 57 insertions, 10 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index db01b95a47a5..c5d6bb4290ad 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -18,6 +18,7 @@
18#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/kthread.h> 20#include <linux/kthread.h>
21#include <linux/wait.h>
21 22
22#include "base.h" 23#include "base.h"
23#include "power/power.h" 24#include "power/power.h"
@@ -70,6 +71,8 @@ struct stupid_thread_structure {
70}; 71};
71 72
72static atomic_t probe_count = ATOMIC_INIT(0); 73static atomic_t probe_count = ATOMIC_INIT(0);
74static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
75
73static int really_probe(void *void_data) 76static int really_probe(void *void_data)
74{ 77{
75 struct stupid_thread_structure *data = void_data; 78 struct stupid_thread_structure *data = void_data;
@@ -121,6 +124,7 @@ probe_failed:
121done: 124done:
122 kfree(data); 125 kfree(data);
123 atomic_dec(&probe_count); 126 atomic_dec(&probe_count);
127 wake_up(&probe_waitqueue);
124 return ret; 128 return ret;
125} 129}
126 130
@@ -337,6 +341,32 @@ void driver_detach(struct device_driver * drv)
337 } 341 }
338} 342}
339 343
344#ifdef CONFIG_PCI_MULTITHREAD_PROBE
345static 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
362core_initcall_sync(wait_for_probes);
363postcore_initcall_sync(wait_for_probes);
364arch_initcall_sync(wait_for_probes);
365subsys_initcall_sync(wait_for_probes);
366fs_initcall_sync(wait_for_probes);
367device_initcall_sync(wait_for_probes);
368late_initcall_sync(wait_for_probes);
369#endif
340 370
341EXPORT_SYMBOL_GPL(device_bind_driver); 371EXPORT_SYMBOL_GPL(device_bind_driver);
342EXPORT_SYMBOL_GPL(device_release_driver); 372EXPORT_SYMBOL_GPL(device_release_driver);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index e3e83bcaf710..9d873163a7ab 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -216,10 +216,17 @@
216 216
217#define INITCALLS \ 217#define INITCALLS \
218 *(.initcall1.init) \ 218 *(.initcall1.init) \
219 *(.initcall1s.init) \
219 *(.initcall2.init) \ 220 *(.initcall2.init) \
221 *(.initcall2s.init) \
220 *(.initcall3.init) \ 222 *(.initcall3.init) \
223 *(.initcall3s.init) \
221 *(.initcall4.init) \ 224 *(.initcall4.init) \
225 *(.initcall4s.init) \
222 *(.initcall5.init) \ 226 *(.initcall5.init) \
227 *(.initcall5s.init) \
223 *(.initcall6.init) \ 228 *(.initcall6.init) \
224 *(.initcall7.init) 229 *(.initcall6s.init) \
230 *(.initcall7.init) \
231 *(.initcall7s.init)
225 232
diff --git a/include/linux/init.h b/include/linux/init.h
index e92b1455d7af..ff40ea118e3a 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -84,19 +84,29 @@ extern void setup_arch(char **);
84 * by link order. 84 * by link order.
85 * For backwards compatibility, initcall() puts the call in 85 * For backwards compatibility, initcall() puts the call in
86 * the device init subsection. 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) \ 92#define __define_initcall(level,fn,id) \
90 static initcall_t __initcall_##fn __attribute_used__ \ 93 static initcall_t __initcall_##fn##id __attribute_used__ \
91 __attribute__((__section__(".initcall" level ".init"))) = fn 94 __attribute__((__section__(".initcall" level ".init"))) = fn
92 95
93#define core_initcall(fn) __define_initcall("1",fn) 96#define core_initcall(fn) __define_initcall("1",fn,1)
94#define postcore_initcall(fn) __define_initcall("2",fn) 97#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
95#define arch_initcall(fn) __define_initcall("3",fn) 98#define postcore_initcall(fn) __define_initcall("2",fn,2)
96#define subsys_initcall(fn) __define_initcall("4",fn) 99#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
97#define fs_initcall(fn) __define_initcall("5",fn) 100#define arch_initcall(fn) __define_initcall("3",fn,3)
98#define device_initcall(fn) __define_initcall("6",fn) 101#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
99#define late_initcall(fn) __define_initcall("7",fn) 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#define __initcall(fn) device_initcall(fn) 111#define __initcall(fn) device_initcall(fn)
102 112