diff options
author | Ben Collins <bcollins@debian.org> | 2005-11-28 16:43:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-28 17:42:23 -0500 |
commit | bce61dd49d6ba7799be2de17c772e4c701558f14 (patch) | |
tree | a8fd75afc85ffef3c9af0bafa1989d7a14e1a187 /kernel | |
parent | ee500f274914653a7d3dfca7d0140a3d21658e32 (diff) |
[PATCH] Fix hardcoded cpu=0 in workqueue for per_cpu_ptr() calls
Tracked this down on an Ultra Enterprise 3000. It's a 6-way machine. Odd
thing about this machine (and it's good for finding bugs like this) is that
the CPU id's are not 0 based. For instance, on my machine the CPU's are
6/7/10/11/14/15.
This caused some NULL pointer dereference in kernel/workqueue.c because for
single_threaded workqueue's, it hardcoded the cpu to 0.
I changed the 0's to any_online_cpu(cpu_online_mask), which cpumask.h
claims is "First cpu in mask". So this fits the same usage.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/workqueue.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 42df83d7fad2..2bd5aee1c736 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -102,7 +102,7 @@ int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work) | |||
102 | 102 | ||
103 | if (!test_and_set_bit(0, &work->pending)) { | 103 | if (!test_and_set_bit(0, &work->pending)) { |
104 | if (unlikely(is_single_threaded(wq))) | 104 | if (unlikely(is_single_threaded(wq))) |
105 | cpu = 0; | 105 | cpu = any_online_cpu(cpu_online_map); |
106 | BUG_ON(!list_empty(&work->entry)); | 106 | BUG_ON(!list_empty(&work->entry)); |
107 | __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); | 107 | __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); |
108 | ret = 1; | 108 | ret = 1; |
@@ -118,7 +118,7 @@ static void delayed_work_timer_fn(unsigned long __data) | |||
118 | int cpu = smp_processor_id(); | 118 | int cpu = smp_processor_id(); |
119 | 119 | ||
120 | if (unlikely(is_single_threaded(wq))) | 120 | if (unlikely(is_single_threaded(wq))) |
121 | cpu = 0; | 121 | cpu = any_online_cpu(cpu_online_map); |
122 | 122 | ||
123 | __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); | 123 | __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); |
124 | } | 124 | } |
@@ -266,8 +266,8 @@ void fastcall flush_workqueue(struct workqueue_struct *wq) | |||
266 | might_sleep(); | 266 | might_sleep(); |
267 | 267 | ||
268 | if (is_single_threaded(wq)) { | 268 | if (is_single_threaded(wq)) { |
269 | /* Always use cpu 0's area. */ | 269 | /* Always use first cpu's area. */ |
270 | flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, 0)); | 270 | flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, any_online_cpu(cpu_online_map))); |
271 | } else { | 271 | } else { |
272 | int cpu; | 272 | int cpu; |
273 | 273 | ||
@@ -320,7 +320,7 @@ struct workqueue_struct *__create_workqueue(const char *name, | |||
320 | lock_cpu_hotplug(); | 320 | lock_cpu_hotplug(); |
321 | if (singlethread) { | 321 | if (singlethread) { |
322 | INIT_LIST_HEAD(&wq->list); | 322 | INIT_LIST_HEAD(&wq->list); |
323 | p = create_workqueue_thread(wq, 0); | 323 | p = create_workqueue_thread(wq, any_online_cpu(cpu_online_map)); |
324 | if (!p) | 324 | if (!p) |
325 | destroy = 1; | 325 | destroy = 1; |
326 | else | 326 | else |
@@ -374,7 +374,7 @@ void destroy_workqueue(struct workqueue_struct *wq) | |||
374 | /* We don't need the distraction of CPUs appearing and vanishing. */ | 374 | /* We don't need the distraction of CPUs appearing and vanishing. */ |
375 | lock_cpu_hotplug(); | 375 | lock_cpu_hotplug(); |
376 | if (is_single_threaded(wq)) | 376 | if (is_single_threaded(wq)) |
377 | cleanup_workqueue_thread(wq, 0); | 377 | cleanup_workqueue_thread(wq, any_online_cpu(cpu_online_map)); |
378 | else { | 378 | else { |
379 | for_each_online_cpu(cpu) | 379 | for_each_online_cpu(cpu) |
380 | cleanup_workqueue_thread(wq, cpu); | 380 | cleanup_workqueue_thread(wq, cpu); |