diff options
author | Tejun Heo <tj@kernel.org> | 2010-07-02 04:03:51 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-07-02 04:59:57 -0400 |
commit | bdbc5dd7de5d07d6c9d3536e598956165a031d4c (patch) | |
tree | 1f0f263126c2fc2e07a032df1e9ad3fecb534c9a /kernel/workqueue.c | |
parent | ad72cf9885c536e3adae03f8337557ac9dd1e4bb (diff) |
workqueue: prepare for WQ_UNBOUND implementation
In preparation of WQ_UNBOUND addition, make the following changes.
* Add WORK_CPU_* constants for pseudo cpu id numbers used (currently
only WORK_CPU_NONE) and use them instead of NR_CPUS. This is to
allow another pseudo cpu id for unbound cpu.
* Reorder WQ_* flags.
* Make workqueue_struct->cpu_wq a union which contains a percpu
pointer, regular pointer and an unsigned long value and use
kzalloc/kfree() in UP allocation path. This will be used to
implement unbound workqueues which will use only one cwq on SMPs.
* Move alloc_cwqs() allocation after initialization of wq fields, so
that alloc_cwqs() has access to wq->flags.
* Trivial relocation of wq local variables in freeze functions.
These changes don't cause any functional change.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 83 |
1 files changed, 43 insertions, 40 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2eb9fbddf5c6..a105ddf55f79 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -190,7 +190,11 @@ struct wq_flusher { | |||
190 | */ | 190 | */ |
191 | struct workqueue_struct { | 191 | struct workqueue_struct { |
192 | unsigned int flags; /* I: WQ_* flags */ | 192 | unsigned int flags; /* I: WQ_* flags */ |
193 | struct cpu_workqueue_struct *cpu_wq; /* I: cwq's */ | 193 | union { |
194 | struct cpu_workqueue_struct __percpu *pcpu; | ||
195 | struct cpu_workqueue_struct *single; | ||
196 | unsigned long v; | ||
197 | } cpu_wq; /* I: cwq's */ | ||
194 | struct list_head list; /* W: list of all workqueues */ | 198 | struct list_head list; /* W: list of all workqueues */ |
195 | 199 | ||
196 | struct mutex flush_mutex; /* protects wq flushing */ | 200 | struct mutex flush_mutex; /* protects wq flushing */ |
@@ -362,7 +366,11 @@ static atomic_t *get_gcwq_nr_running(unsigned int cpu) | |||
362 | static struct cpu_workqueue_struct *get_cwq(unsigned int cpu, | 366 | static struct cpu_workqueue_struct *get_cwq(unsigned int cpu, |
363 | struct workqueue_struct *wq) | 367 | struct workqueue_struct *wq) |
364 | { | 368 | { |
365 | return per_cpu_ptr(wq->cpu_wq, cpu); | 369 | #ifndef CONFIG_SMP |
370 | return wq->cpu_wq.single; | ||
371 | #else | ||
372 | return per_cpu_ptr(wq->cpu_wq.pcpu, cpu); | ||
373 | #endif | ||
366 | } | 374 | } |
367 | 375 | ||
368 | static unsigned int work_color_to_flags(int color) | 376 | static unsigned int work_color_to_flags(int color) |
@@ -442,7 +450,7 @@ static struct global_cwq *get_work_gcwq(struct work_struct *work) | |||
442 | return ((struct cpu_workqueue_struct *)data)->gcwq; | 450 | return ((struct cpu_workqueue_struct *)data)->gcwq; |
443 | 451 | ||
444 | cpu = data >> WORK_STRUCT_FLAG_BITS; | 452 | cpu = data >> WORK_STRUCT_FLAG_BITS; |
445 | if (cpu == NR_CPUS) | 453 | if (cpu == WORK_CPU_NONE) |
446 | return NULL; | 454 | return NULL; |
447 | 455 | ||
448 | BUG_ON(cpu >= nr_cpu_ids); | 456 | BUG_ON(cpu >= nr_cpu_ids); |
@@ -846,7 +854,7 @@ static void cwq_unbind_single_cpu(struct cpu_workqueue_struct *cwq) | |||
846 | */ | 854 | */ |
847 | if (likely(!(gcwq->flags & GCWQ_FREEZING))) { | 855 | if (likely(!(gcwq->flags & GCWQ_FREEZING))) { |
848 | smp_wmb(); /* paired with cmpxchg() in __queue_work() */ | 856 | smp_wmb(); /* paired with cmpxchg() in __queue_work() */ |
849 | wq->single_cpu = NR_CPUS; | 857 | wq->single_cpu = WORK_CPU_NONE; |
850 | } | 858 | } |
851 | } | 859 | } |
852 | 860 | ||
@@ -904,7 +912,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
904 | */ | 912 | */ |
905 | retry: | 913 | retry: |
906 | cpu = wq->single_cpu; | 914 | cpu = wq->single_cpu; |
907 | arbitrate = cpu == NR_CPUS; | 915 | arbitrate = cpu == WORK_CPU_NONE; |
908 | if (arbitrate) | 916 | if (arbitrate) |
909 | cpu = req_cpu; | 917 | cpu = req_cpu; |
910 | 918 | ||
@@ -918,7 +926,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, | |||
918 | * visible on the new cpu after this point. | 926 | * visible on the new cpu after this point. |
919 | */ | 927 | */ |
920 | if (arbitrate) | 928 | if (arbitrate) |
921 | cmpxchg(&wq->single_cpu, NR_CPUS, cpu); | 929 | cmpxchg(&wq->single_cpu, WORK_CPU_NONE, cpu); |
922 | 930 | ||
923 | if (unlikely(wq->single_cpu != cpu)) { | 931 | if (unlikely(wq->single_cpu != cpu)) { |
924 | spin_unlock_irqrestore(&gcwq->lock, flags); | 932 | spin_unlock_irqrestore(&gcwq->lock, flags); |
@@ -2572,7 +2580,7 @@ int keventd_up(void) | |||
2572 | return system_wq != NULL; | 2580 | return system_wq != NULL; |
2573 | } | 2581 | } |
2574 | 2582 | ||
2575 | static struct cpu_workqueue_struct *alloc_cwqs(void) | 2583 | static int alloc_cwqs(struct workqueue_struct *wq) |
2576 | { | 2584 | { |
2577 | /* | 2585 | /* |
2578 | * cwqs are forced aligned according to WORK_STRUCT_FLAG_BITS. | 2586 | * cwqs are forced aligned according to WORK_STRUCT_FLAG_BITS. |
@@ -2582,40 +2590,36 @@ static struct cpu_workqueue_struct *alloc_cwqs(void) | |||
2582 | const size_t size = sizeof(struct cpu_workqueue_struct); | 2590 | const size_t size = sizeof(struct cpu_workqueue_struct); |
2583 | const size_t align = max_t(size_t, 1 << WORK_STRUCT_FLAG_BITS, | 2591 | const size_t align = max_t(size_t, 1 << WORK_STRUCT_FLAG_BITS, |
2584 | __alignof__(unsigned long long)); | 2592 | __alignof__(unsigned long long)); |
2585 | struct cpu_workqueue_struct *cwqs; | ||
2586 | #ifndef CONFIG_SMP | 2593 | #ifndef CONFIG_SMP |
2587 | void *ptr; | 2594 | void *ptr; |
2588 | 2595 | ||
2589 | /* | 2596 | /* |
2590 | * On UP, percpu allocator doesn't honor alignment parameter | 2597 | * Allocate enough room to align cwq and put an extra pointer |
2591 | * and simply uses arch-dependent default. Allocate enough | 2598 | * at the end pointing back to the originally allocated |
2592 | * room to align cwq and put an extra pointer at the end | 2599 | * pointer which will be used for free. |
2593 | * pointing back to the originally allocated pointer which | ||
2594 | * will be used for free. | ||
2595 | * | ||
2596 | * FIXME: This really belongs to UP percpu code. Update UP | ||
2597 | * percpu code to honor alignment and remove this ugliness. | ||
2598 | */ | 2600 | */ |
2599 | ptr = __alloc_percpu(size + align + sizeof(void *), 1); | 2601 | ptr = kzalloc(size + align + sizeof(void *), GFP_KERNEL); |
2600 | cwqs = PTR_ALIGN(ptr, align); | 2602 | if (ptr) { |
2601 | *(void **)per_cpu_ptr(cwqs + 1, 0) = ptr; | 2603 | wq->cpu_wq.single = PTR_ALIGN(ptr, align); |
2604 | *(void **)(wq->cpu_wq.single + 1) = ptr; | ||
2605 | } | ||
2602 | #else | 2606 | #else |
2603 | /* On SMP, percpu allocator can do it itself */ | 2607 | /* On SMP, percpu allocator can align itself */ |
2604 | cwqs = __alloc_percpu(size, align); | 2608 | wq->cpu_wq.pcpu = __alloc_percpu(size, align); |
2605 | #endif | 2609 | #endif |
2606 | /* just in case, make sure it's actually aligned */ | 2610 | /* just in case, make sure it's actually aligned */ |
2607 | BUG_ON(!IS_ALIGNED((unsigned long)cwqs, align)); | 2611 | BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align)); |
2608 | return cwqs; | 2612 | return wq->cpu_wq.v ? 0 : -ENOMEM; |
2609 | } | 2613 | } |
2610 | 2614 | ||
2611 | static void free_cwqs(struct cpu_workqueue_struct *cwqs) | 2615 | static void free_cwqs(struct workqueue_struct *wq) |
2612 | { | 2616 | { |
2613 | #ifndef CONFIG_SMP | 2617 | #ifndef CONFIG_SMP |
2614 | /* on UP, the pointer to free is stored right after the cwq */ | 2618 | /* on UP, the pointer to free is stored right after the cwq */ |
2615 | if (cwqs) | 2619 | if (wq->cpu_wq.single) |
2616 | free_percpu(*(void **)per_cpu_ptr(cwqs + 1, 0)); | 2620 | kfree(*(void **)(wq->cpu_wq.single + 1)); |
2617 | #else | 2621 | #else |
2618 | free_percpu(cwqs); | 2622 | free_percpu(wq->cpu_wq.pcpu); |
2619 | #endif | 2623 | #endif |
2620 | } | 2624 | } |
2621 | 2625 | ||
@@ -2645,22 +2649,21 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, | |||
2645 | if (!wq) | 2649 | if (!wq) |
2646 | goto err; | 2650 | goto err; |
2647 | 2651 | ||
2648 | wq->cpu_wq = alloc_cwqs(); | ||
2649 | if (!wq->cpu_wq) | ||
2650 | goto err; | ||
2651 | |||
2652 | wq->flags = flags; | 2652 | wq->flags = flags; |
2653 | wq->saved_max_active = max_active; | 2653 | wq->saved_max_active = max_active; |
2654 | mutex_init(&wq->flush_mutex); | 2654 | mutex_init(&wq->flush_mutex); |
2655 | atomic_set(&wq->nr_cwqs_to_flush, 0); | 2655 | atomic_set(&wq->nr_cwqs_to_flush, 0); |
2656 | INIT_LIST_HEAD(&wq->flusher_queue); | 2656 | INIT_LIST_HEAD(&wq->flusher_queue); |
2657 | INIT_LIST_HEAD(&wq->flusher_overflow); | 2657 | INIT_LIST_HEAD(&wq->flusher_overflow); |
2658 | wq->single_cpu = NR_CPUS; | 2658 | wq->single_cpu = WORK_CPU_NONE; |
2659 | 2659 | ||
2660 | wq->name = name; | 2660 | wq->name = name; |
2661 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); | 2661 | lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); |
2662 | INIT_LIST_HEAD(&wq->list); | 2662 | INIT_LIST_HEAD(&wq->list); |
2663 | 2663 | ||
2664 | if (alloc_cwqs(wq) < 0) | ||
2665 | goto err; | ||
2666 | |||
2664 | for_each_possible_cpu(cpu) { | 2667 | for_each_possible_cpu(cpu) { |
2665 | struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); | 2668 | struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); |
2666 | struct global_cwq *gcwq = get_gcwq(cpu); | 2669 | struct global_cwq *gcwq = get_gcwq(cpu); |
@@ -2710,7 +2713,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, | |||
2710 | return wq; | 2713 | return wq; |
2711 | err: | 2714 | err: |
2712 | if (wq) { | 2715 | if (wq) { |
2713 | free_cwqs(wq->cpu_wq); | 2716 | free_cwqs(wq); |
2714 | free_cpumask_var(wq->mayday_mask); | 2717 | free_cpumask_var(wq->mayday_mask); |
2715 | kfree(wq->rescuer); | 2718 | kfree(wq->rescuer); |
2716 | kfree(wq); | 2719 | kfree(wq); |
@@ -2755,7 +2758,7 @@ void destroy_workqueue(struct workqueue_struct *wq) | |||
2755 | free_cpumask_var(wq->mayday_mask); | 2758 | free_cpumask_var(wq->mayday_mask); |
2756 | } | 2759 | } |
2757 | 2760 | ||
2758 | free_cwqs(wq->cpu_wq); | 2761 | free_cwqs(wq); |
2759 | kfree(wq); | 2762 | kfree(wq); |
2760 | } | 2763 | } |
2761 | EXPORT_SYMBOL_GPL(destroy_workqueue); | 2764 | EXPORT_SYMBOL_GPL(destroy_workqueue); |
@@ -2821,13 +2824,13 @@ EXPORT_SYMBOL_GPL(workqueue_congested); | |||
2821 | * @work: the work of interest | 2824 | * @work: the work of interest |
2822 | * | 2825 | * |
2823 | * RETURNS: | 2826 | * RETURNS: |
2824 | * CPU number if @work was ever queued. NR_CPUS otherwise. | 2827 | * CPU number if @work was ever queued. WORK_CPU_NONE otherwise. |
2825 | */ | 2828 | */ |
2826 | unsigned int work_cpu(struct work_struct *work) | 2829 | unsigned int work_cpu(struct work_struct *work) |
2827 | { | 2830 | { |
2828 | struct global_cwq *gcwq = get_work_gcwq(work); | 2831 | struct global_cwq *gcwq = get_work_gcwq(work); |
2829 | 2832 | ||
2830 | return gcwq ? gcwq->cpu : NR_CPUS; | 2833 | return gcwq ? gcwq->cpu : WORK_CPU_NONE; |
2831 | } | 2834 | } |
2832 | EXPORT_SYMBOL_GPL(work_cpu); | 2835 | EXPORT_SYMBOL_GPL(work_cpu); |
2833 | 2836 | ||
@@ -3300,7 +3303,6 @@ EXPORT_SYMBOL_GPL(work_on_cpu); | |||
3300 | */ | 3303 | */ |
3301 | void freeze_workqueues_begin(void) | 3304 | void freeze_workqueues_begin(void) |
3302 | { | 3305 | { |
3303 | struct workqueue_struct *wq; | ||
3304 | unsigned int cpu; | 3306 | unsigned int cpu; |
3305 | 3307 | ||
3306 | spin_lock(&workqueue_lock); | 3308 | spin_lock(&workqueue_lock); |
@@ -3310,6 +3312,7 @@ void freeze_workqueues_begin(void) | |||
3310 | 3312 | ||
3311 | for_each_possible_cpu(cpu) { | 3313 | for_each_possible_cpu(cpu) { |
3312 | struct global_cwq *gcwq = get_gcwq(cpu); | 3314 | struct global_cwq *gcwq = get_gcwq(cpu); |
3315 | struct workqueue_struct *wq; | ||
3313 | 3316 | ||
3314 | spin_lock_irq(&gcwq->lock); | 3317 | spin_lock_irq(&gcwq->lock); |
3315 | 3318 | ||
@@ -3344,7 +3347,6 @@ void freeze_workqueues_begin(void) | |||
3344 | */ | 3347 | */ |
3345 | bool freeze_workqueues_busy(void) | 3348 | bool freeze_workqueues_busy(void) |
3346 | { | 3349 | { |
3347 | struct workqueue_struct *wq; | ||
3348 | unsigned int cpu; | 3350 | unsigned int cpu; |
3349 | bool busy = false; | 3351 | bool busy = false; |
3350 | 3352 | ||
@@ -3353,6 +3355,7 @@ bool freeze_workqueues_busy(void) | |||
3353 | BUG_ON(!workqueue_freezing); | 3355 | BUG_ON(!workqueue_freezing); |
3354 | 3356 | ||
3355 | for_each_possible_cpu(cpu) { | 3357 | for_each_possible_cpu(cpu) { |
3358 | struct workqueue_struct *wq; | ||
3356 | /* | 3359 | /* |
3357 | * nr_active is monotonically decreasing. It's safe | 3360 | * nr_active is monotonically decreasing. It's safe |
3358 | * to peek without lock. | 3361 | * to peek without lock. |
@@ -3386,7 +3389,6 @@ out_unlock: | |||
3386 | */ | 3389 | */ |
3387 | void thaw_workqueues(void) | 3390 | void thaw_workqueues(void) |
3388 | { | 3391 | { |
3389 | struct workqueue_struct *wq; | ||
3390 | unsigned int cpu; | 3392 | unsigned int cpu; |
3391 | 3393 | ||
3392 | spin_lock(&workqueue_lock); | 3394 | spin_lock(&workqueue_lock); |
@@ -3396,6 +3398,7 @@ void thaw_workqueues(void) | |||
3396 | 3398 | ||
3397 | for_each_possible_cpu(cpu) { | 3399 | for_each_possible_cpu(cpu) { |
3398 | struct global_cwq *gcwq = get_gcwq(cpu); | 3400 | struct global_cwq *gcwq = get_gcwq(cpu); |
3401 | struct workqueue_struct *wq; | ||
3399 | 3402 | ||
3400 | spin_lock_irq(&gcwq->lock); | 3403 | spin_lock_irq(&gcwq->lock); |
3401 | 3404 | ||
@@ -3443,7 +3446,7 @@ void __init init_workqueues(void) | |||
3443 | * sure cpu number won't overflow into kernel pointer area so | 3446 | * sure cpu number won't overflow into kernel pointer area so |
3444 | * that they can be distinguished. | 3447 | * that they can be distinguished. |
3445 | */ | 3448 | */ |
3446 | BUILD_BUG_ON(NR_CPUS << WORK_STRUCT_FLAG_BITS >= PAGE_OFFSET); | 3449 | BUILD_BUG_ON(WORK_CPU_LAST << WORK_STRUCT_FLAG_BITS >= PAGE_OFFSET); |
3447 | 3450 | ||
3448 | hotcpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE); | 3451 | hotcpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE); |
3449 | 3452 | ||