diff options
author | Tejun Heo <tj@kernel.org> | 2013-03-12 14:30:04 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-03-12 14:30:04 -0400 |
commit | d2c1d40487bb1884be085c187233084f80df052d (patch) | |
tree | 11ea6d2f331ed75935d0e65643d657f74278d881 /kernel/workqueue.c | |
parent | 493008a8e475771a2126e0ce95a73e35b371d277 (diff) |
workqueue: restructure __alloc_workqueue_key()
* Move initialization and linking of pool_workqueues into
init_and_link_pwq().
* Make the failure path use destroy_workqueue() once pool_workqueue
initialization succeeds.
These changes are to prepare for dynamic management of pool_workqueues
and don't introduce any functional changes.
While at it, convert list_del(&wq->list) to list_del_init() as a
precaution as scheduled changes will make destruction more complex.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 67 |
1 files changed, 38 insertions, 29 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7ff2b9c5cc3a..5ac846e0085e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -3329,6 +3329,23 @@ fail: | |||
3329 | return NULL; | 3329 | return NULL; |
3330 | } | 3330 | } |
3331 | 3331 | ||
3332 | /* initialize @pwq which interfaces with @pool for @wq and link it in */ | ||
3333 | static void init_and_link_pwq(struct pool_workqueue *pwq, | ||
3334 | struct workqueue_struct *wq, | ||
3335 | struct worker_pool *pool) | ||
3336 | { | ||
3337 | BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK); | ||
3338 | |||
3339 | pwq->pool = pool; | ||
3340 | pwq->wq = wq; | ||
3341 | pwq->flush_color = -1; | ||
3342 | pwq->max_active = wq->saved_max_active; | ||
3343 | INIT_LIST_HEAD(&pwq->delayed_works); | ||
3344 | INIT_LIST_HEAD(&pwq->mayday_node); | ||
3345 | |||
3346 | list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs); | ||
3347 | } | ||
3348 | |||
3332 | static int alloc_and_link_pwqs(struct workqueue_struct *wq) | 3349 | static int alloc_and_link_pwqs(struct workqueue_struct *wq) |
3333 | { | 3350 | { |
3334 | bool highpri = wq->flags & WQ_HIGHPRI; | 3351 | bool highpri = wq->flags & WQ_HIGHPRI; |
@@ -3345,23 +3362,23 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) | |||
3345 | struct worker_pool *cpu_pools = | 3362 | struct worker_pool *cpu_pools = |
3346 | per_cpu(cpu_worker_pools, cpu); | 3363 | per_cpu(cpu_worker_pools, cpu); |
3347 | 3364 | ||
3348 | pwq->pool = &cpu_pools[highpri]; | 3365 | init_and_link_pwq(pwq, wq, &cpu_pools[highpri]); |
3349 | list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs); | ||
3350 | } | 3366 | } |
3351 | } else { | 3367 | } else { |
3352 | struct pool_workqueue *pwq; | 3368 | struct pool_workqueue *pwq; |
3369 | struct worker_pool *pool; | ||
3353 | 3370 | ||
3354 | pwq = kmem_cache_zalloc(pwq_cache, GFP_KERNEL); | 3371 | pwq = kmem_cache_zalloc(pwq_cache, GFP_KERNEL); |
3355 | if (!pwq) | 3372 | if (!pwq) |
3356 | return -ENOMEM; | 3373 | return -ENOMEM; |
3357 | 3374 | ||
3358 | pwq->pool = get_unbound_pool(unbound_std_wq_attrs[highpri]); | 3375 | pool = get_unbound_pool(unbound_std_wq_attrs[highpri]); |
3359 | if (!pwq->pool) { | 3376 | if (!pool) { |
3360 | kmem_cache_free(pwq_cache, pwq); | 3377 | kmem_cache_free(pwq_cache, pwq); |
3361 | return -ENOMEM; | 3378 | return -ENOMEM; |
3362 | } | 3379 | } |
3363 | 3380 | ||
3364 | list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs); | 3381 | init_and_link_pwq(pwq, wq, pool); |
3365 | } | 3382 | } |
3366 | 3383 | ||
3367 | return 0; | 3384 | return 0; |
@@ -3406,7 +3423,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3406 | 3423 | ||
3407 | wq = kzalloc(sizeof(*wq) + namelen, GFP_KERNEL); | 3424 | wq = kzalloc(sizeof(*wq) + namelen, GFP_KERNEL); |
3408 | if (!wq) | 3425 | if (!wq) |
3409 | goto err; | 3426 | return NULL; |
3410 | 3427 | ||
3411 | vsnprintf(wq->name, namelen, fmt, args1); | 3428 | vsnprintf(wq->name, namelen, fmt, args1); |
3412 | va_end(args); | 3429 | va_end(args); |
@@ -3429,18 +3446,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3429 | INIT_LIST_HEAD(&wq->list); | 3446 | INIT_LIST_HEAD(&wq->list); |
3430 | 3447 | ||
3431 | if (alloc_and_link_pwqs(wq) < 0) | 3448 | if (alloc_and_link_pwqs(wq) < 0) |
3432 | goto err; | 3449 | goto err_free_wq; |
3433 | |||
3434 | local_irq_disable(); | ||
3435 | for_each_pwq(pwq, wq) { | ||
3436 | BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK); | ||
3437 | pwq->wq = wq; | ||
3438 | pwq->flush_color = -1; | ||
3439 | pwq->max_active = max_active; | ||
3440 | INIT_LIST_HEAD(&pwq->delayed_works); | ||
3441 | INIT_LIST_HEAD(&pwq->mayday_node); | ||
3442 | } | ||
3443 | local_irq_enable(); | ||
3444 | 3450 | ||
3445 | /* | 3451 | /* |
3446 | * Workqueues which may be used during memory reclaim should | 3452 | * Workqueues which may be used during memory reclaim should |
@@ -3449,16 +3455,19 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3449 | if (flags & WQ_MEM_RECLAIM) { | 3455 | if (flags & WQ_MEM_RECLAIM) { |
3450 | struct worker *rescuer; | 3456 | struct worker *rescuer; |
3451 | 3457 | ||
3452 | wq->rescuer = rescuer = alloc_worker(); | 3458 | rescuer = alloc_worker(); |
3453 | if (!rescuer) | 3459 | if (!rescuer) |
3454 | goto err; | 3460 | goto err_destroy; |
3455 | 3461 | ||
3456 | rescuer->rescue_wq = wq; | 3462 | rescuer->rescue_wq = wq; |
3457 | rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", | 3463 | rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", |
3458 | wq->name); | 3464 | wq->name); |
3459 | if (IS_ERR(rescuer->task)) | 3465 | if (IS_ERR(rescuer->task)) { |
3460 | goto err; | 3466 | kfree(rescuer); |
3467 | goto err_destroy; | ||
3468 | } | ||
3461 | 3469 | ||
3470 | wq->rescuer = rescuer; | ||
3462 | rescuer->task->flags |= PF_THREAD_BOUND; | 3471 | rescuer->task->flags |= PF_THREAD_BOUND; |
3463 | wake_up_process(rescuer->task); | 3472 | wake_up_process(rescuer->task); |
3464 | } | 3473 | } |
@@ -3479,12 +3488,12 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3479 | spin_unlock_irq(&workqueue_lock); | 3488 | spin_unlock_irq(&workqueue_lock); |
3480 | 3489 | ||
3481 | return wq; | 3490 | return wq; |
3482 | err: | 3491 | |
3483 | if (wq) { | 3492 | err_free_wq: |
3484 | free_pwqs(wq); | 3493 | kfree(wq); |
3485 | kfree(wq->rescuer); | 3494 | return NULL; |
3486 | kfree(wq); | 3495 | err_destroy: |
3487 | } | 3496 | destroy_workqueue(wq); |
3488 | return NULL; | 3497 | return NULL; |
3489 | } | 3498 | } |
3490 | EXPORT_SYMBOL_GPL(__alloc_workqueue_key); | 3499 | EXPORT_SYMBOL_GPL(__alloc_workqueue_key); |
@@ -3526,7 +3535,7 @@ void destroy_workqueue(struct workqueue_struct *wq) | |||
3526 | * wq list is used to freeze wq, remove from list after | 3535 | * wq list is used to freeze wq, remove from list after |
3527 | * flushing is complete in case freeze races us. | 3536 | * flushing is complete in case freeze races us. |
3528 | */ | 3537 | */ |
3529 | list_del(&wq->list); | 3538 | list_del_init(&wq->list); |
3530 | 3539 | ||
3531 | spin_unlock_irq(&workqueue_lock); | 3540 | spin_unlock_irq(&workqueue_lock); |
3532 | 3541 | ||