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 | 8864b4e59f7945a636eeb27671f10486149be6e6 (patch) | |
tree | 74382658daf648a612e0bda94cb161cac84f0523 /kernel | |
parent | d2c1d40487bb1884be085c187233084f80df052d (diff) |
workqueue: implement get/put_pwq()
Add pool_workqueue->refcnt along with get/put_pwq(). Both per-cpu and
unbound pwqs have refcnts and any work item inserted on a pwq
increments the refcnt which is dropped when the work item finishes.
For per-cpu pwqs the base ref is never dropped and destroy_workqueue()
frees the pwqs as before. For unbound ones, destroy_workqueue()
simply drops the base ref on the first pwq. When the refcnt reaches
zero, pwq_unbound_release_workfn() is scheduled on system_wq, which
unlinks the pwq, puts the associated pool and frees the pwq and wq as
necessary. This needs to be done from a work item as put_pwq() needs
to be protected by pool->lock but release can't happen with the lock
held - e.g. put_unbound_pool() involves blocking operations.
Unbound pool->locks are marked with lockdep subclas 1 as put_pwq()
will schedule the release work item on system_wq while holding the
unbound pool's lock and triggers recursive locking warning spuriously.
This will be used to implement dynamic creation and destruction of
unbound pwqs.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/workqueue.c | 137 |
1 files changed, 114 insertions, 23 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 5ac846e0085e..7dd8e7bcec51 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -179,6 +179,7 @@ struct pool_workqueue { | |||
179 | struct workqueue_struct *wq; /* I: the owning workqueue */ | 179 | struct workqueue_struct *wq; /* I: the owning workqueue */ |
180 | int work_color; /* L: current color */ | 180 | int work_color; /* L: current color */ |
181 | int flush_color; /* L: flushing color */ | 181 | int flush_color; /* L: flushing color */ |
182 | int refcnt; /* L: reference count */ | ||
182 | int nr_in_flight[WORK_NR_COLORS]; | 183 | int nr_in_flight[WORK_NR_COLORS]; |
183 | /* L: nr of in_flight works */ | 184 | /* L: nr of in_flight works */ |
184 | int nr_active; /* L: nr of active works */ | 185 | int nr_active; /* L: nr of active works */ |
@@ -186,6 +187,15 @@ struct pool_workqueue { | |||
186 | struct list_head delayed_works; /* L: delayed works */ | 187 | struct list_head delayed_works; /* L: delayed works */ |
187 | struct list_head pwqs_node; /* R: node on wq->pwqs */ | 188 | struct list_head pwqs_node; /* R: node on wq->pwqs */ |
188 | struct list_head mayday_node; /* W: node on wq->maydays */ | 189 | struct list_head mayday_node; /* W: node on wq->maydays */ |
190 | |||
191 | /* | ||
192 | * Release of unbound pwq is punted to system_wq. See put_pwq() | ||
193 | * and pwq_unbound_release_workfn() for details. pool_workqueue | ||
194 | * itself is also sched-RCU protected so that the first pwq can be | ||
195 | * determined without grabbing workqueue_lock. | ||
196 | */ | ||
197 | struct work_struct unbound_release_work; | ||
198 | struct rcu_head rcu; | ||
189 | } __aligned(1 << WORK_STRUCT_FLAG_BITS); | 199 | } __aligned(1 << WORK_STRUCT_FLAG_BITS); |
190 | 200 | ||
191 | /* | 201 | /* |
@@ -939,6 +949,45 @@ static void move_linked_works(struct work_struct *work, struct list_head *head, | |||
939 | *nextp = n; | 949 | *nextp = n; |
940 | } | 950 | } |
941 | 951 | ||
952 | /** | ||
953 | * get_pwq - get an extra reference on the specified pool_workqueue | ||
954 | * @pwq: pool_workqueue to get | ||
955 | * | ||
956 | * Obtain an extra reference on @pwq. The caller should guarantee that | ||
957 | * @pwq has positive refcnt and be holding the matching pool->lock. | ||
958 | */ | ||
959 | static void get_pwq(struct pool_workqueue *pwq) | ||
960 | { | ||
961 | lockdep_assert_held(&pwq->pool->lock); | ||
962 | WARN_ON_ONCE(pwq->refcnt <= 0); | ||
963 | pwq->refcnt++; | ||
964 | } | ||
965 | |||
966 | /** | ||
967 | * put_pwq - put a pool_workqueue reference | ||
968 | * @pwq: pool_workqueue to put | ||
969 | * | ||
970 | * Drop a reference of @pwq. If its refcnt reaches zero, schedule its | ||
971 | * destruction. The caller should be holding the matching pool->lock. | ||
972 | */ | ||
973 | static void put_pwq(struct pool_workqueue *pwq) | ||
974 | { | ||
975 | lockdep_assert_held(&pwq->pool->lock); | ||
976 | if (likely(--pwq->refcnt)) | ||
977 | return; | ||
978 | if (WARN_ON_ONCE(!(pwq->wq->flags & WQ_UNBOUND))) | ||
979 | return; | ||
980 | /* | ||
981 | * @pwq can't be released under pool->lock, bounce to | ||
982 | * pwq_unbound_release_workfn(). This never recurses on the same | ||
983 | * pool->lock as this path is taken only for unbound workqueues and | ||
984 | * the release work item is scheduled on a per-cpu workqueue. To | ||
985 | * avoid lockdep warning, unbound pool->locks are given lockdep | ||
986 | * subclass of 1 in get_unbound_pool(). | ||
987 | */ | ||
988 | schedule_work(&pwq->unbound_release_work); | ||
989 | } | ||
990 | |||
942 | static void pwq_activate_delayed_work(struct work_struct *work) | 991 | static void pwq_activate_delayed_work(struct work_struct *work) |
943 | { | 992 | { |
944 | struct pool_workqueue *pwq = get_work_pwq(work); | 993 | struct pool_workqueue *pwq = get_work_pwq(work); |
@@ -970,9 +1019,9 @@ static void pwq_activate_first_delayed(struct pool_workqueue *pwq) | |||
970 | */ | 1019 | */ |
971 | static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color) | 1020 | static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color) |
972 | { | 1021 | { |
973 | /* ignore uncolored works */ | 1022 | /* uncolored work items don't participate in flushing or nr_active */ |
974 | if (color == WORK_NO_COLOR) | 1023 | if (color == WORK_NO_COLOR) |
975 | return; | 1024 | goto out_put; |
976 | 1025 | ||
977 | pwq->nr_in_flight[color]--; | 1026 | pwq->nr_in_flight[color]--; |
978 | 1027 | ||
@@ -985,11 +1034,11 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color) | |||
985 | 1034 | ||
986 | /* is flush in progress and are we at the flushing tip? */ | 1035 | /* is flush in progress and are we at the flushing tip? */ |
987 | if (likely(pwq->flush_color != color)) | 1036 | if (likely(pwq->flush_color != color)) |
988 | return; | 1037 | goto out_put; |
989 | 1038 | ||
990 | /* are there still in-flight works? */ | 1039 | /* are there still in-flight works? */ |
991 | if (pwq->nr_in_flight[color]) | 1040 | if (pwq->nr_in_flight[color]) |
992 | return; | 1041 | goto out_put; |
993 | 1042 | ||
994 | /* this pwq is done, clear flush_color */ | 1043 | /* this pwq is done, clear flush_color */ |
995 | pwq->flush_color = -1; | 1044 | pwq->flush_color = -1; |
@@ -1000,6 +1049,8 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color) | |||
1000 | */ | 1049 | */ |
1001 | if (atomic_dec_and_test(&pwq->wq->nr_pwqs_to_flush)) | 1050 | if (atomic_dec_and_test(&pwq->wq->nr_pwqs_to_flush)) |
1002 | complete(&pwq->wq->first_flusher->done); | 1051 | complete(&pwq->wq->first_flusher->done); |
1052 | out_put: | ||
1053 | put_pwq(pwq); | ||
1003 | } | 1054 | } |
1004 | 1055 | ||
1005 | /** | 1056 | /** |
@@ -1122,6 +1173,7 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, | |||
1122 | /* we own @work, set data and link */ | 1173 | /* we own @work, set data and link */ |
1123 | set_work_pwq(work, pwq, extra_flags); | 1174 | set_work_pwq(work, pwq, extra_flags); |
1124 | list_add_tail(&work->entry, head); | 1175 | list_add_tail(&work->entry, head); |
1176 | get_pwq(pwq); | ||
1125 | 1177 | ||
1126 | /* | 1178 | /* |
1127 | * Ensure either worker_sched_deactivated() sees the above | 1179 | * Ensure either worker_sched_deactivated() sees the above |
@@ -3301,6 +3353,7 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) | |||
3301 | if (!pool || init_worker_pool(pool) < 0) | 3353 | if (!pool || init_worker_pool(pool) < 0) |
3302 | goto fail; | 3354 | goto fail; |
3303 | 3355 | ||
3356 | lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */ | ||
3304 | copy_workqueue_attrs(pool->attrs, attrs); | 3357 | copy_workqueue_attrs(pool->attrs, attrs); |
3305 | 3358 | ||
3306 | if (worker_pool_assign_id(pool) < 0) | 3359 | if (worker_pool_assign_id(pool) < 0) |
@@ -3329,7 +3382,41 @@ fail: | |||
3329 | return NULL; | 3382 | return NULL; |
3330 | } | 3383 | } |
3331 | 3384 | ||
3332 | /* initialize @pwq which interfaces with @pool for @wq and link it in */ | 3385 | static void rcu_free_pwq(struct rcu_head *rcu) |
3386 | { | ||
3387 | kmem_cache_free(pwq_cache, | ||
3388 | container_of(rcu, struct pool_workqueue, rcu)); | ||
3389 | } | ||
3390 | |||
3391 | /* | ||
3392 | * Scheduled on system_wq by put_pwq() when an unbound pwq hits zero refcnt | ||
3393 | * and needs to be destroyed. | ||
3394 | */ | ||
3395 | static void pwq_unbound_release_workfn(struct work_struct *work) | ||
3396 | { | ||
3397 | struct pool_workqueue *pwq = container_of(work, struct pool_workqueue, | ||
3398 | unbound_release_work); | ||
3399 | struct workqueue_struct *wq = pwq->wq; | ||
3400 | struct worker_pool *pool = pwq->pool; | ||
3401 | |||
3402 | if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND))) | ||
3403 | return; | ||
3404 | |||
3405 | spin_lock_irq(&workqueue_lock); | ||
3406 | list_del_rcu(&pwq->pwqs_node); | ||
3407 | spin_unlock_irq(&workqueue_lock); | ||
3408 | |||
3409 | put_unbound_pool(pool); | ||
3410 | call_rcu_sched(&pwq->rcu, rcu_free_pwq); | ||
3411 | |||
3412 | /* | ||
3413 | * If we're the last pwq going away, @wq is already dead and no one | ||
3414 | * is gonna access it anymore. Free it. | ||
3415 | */ | ||
3416 | if (list_empty(&wq->pwqs)) | ||
3417 | kfree(wq); | ||
3418 | } | ||
3419 | |||
3333 | static void init_and_link_pwq(struct pool_workqueue *pwq, | 3420 | static void init_and_link_pwq(struct pool_workqueue *pwq, |
3334 | struct workqueue_struct *wq, | 3421 | struct workqueue_struct *wq, |
3335 | struct worker_pool *pool) | 3422 | struct worker_pool *pool) |
@@ -3339,9 +3426,11 @@ static void init_and_link_pwq(struct pool_workqueue *pwq, | |||
3339 | pwq->pool = pool; | 3426 | pwq->pool = pool; |
3340 | pwq->wq = wq; | 3427 | pwq->wq = wq; |
3341 | pwq->flush_color = -1; | 3428 | pwq->flush_color = -1; |
3429 | pwq->refcnt = 1; | ||
3342 | pwq->max_active = wq->saved_max_active; | 3430 | pwq->max_active = wq->saved_max_active; |
3343 | INIT_LIST_HEAD(&pwq->delayed_works); | 3431 | INIT_LIST_HEAD(&pwq->delayed_works); |
3344 | INIT_LIST_HEAD(&pwq->mayday_node); | 3432 | INIT_LIST_HEAD(&pwq->mayday_node); |
3433 | INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn); | ||
3345 | 3434 | ||
3346 | list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs); | 3435 | list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs); |
3347 | } | 3436 | } |
@@ -3384,15 +3473,6 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq) | |||
3384 | return 0; | 3473 | return 0; |
3385 | } | 3474 | } |
3386 | 3475 | ||
3387 | static void free_pwqs(struct workqueue_struct *wq) | ||
3388 | { | ||
3389 | if (!(wq->flags & WQ_UNBOUND)) | ||
3390 | free_percpu(wq->cpu_pwqs); | ||
3391 | else if (!list_empty(&wq->pwqs)) | ||
3392 | kmem_cache_free(pwq_cache, list_first_entry(&wq->pwqs, | ||
3393 | struct pool_workqueue, pwqs_node)); | ||
3394 | } | ||
3395 | |||
3396 | static int wq_clamp_max_active(int max_active, unsigned int flags, | 3476 | static int wq_clamp_max_active(int max_active, unsigned int flags, |
3397 | const char *name) | 3477 | const char *name) |
3398 | { | 3478 | { |
@@ -3524,7 +3604,8 @@ void destroy_workqueue(struct workqueue_struct *wq) | |||
3524 | } | 3604 | } |
3525 | } | 3605 | } |
3526 | 3606 | ||
3527 | if (WARN_ON(pwq->nr_active) || | 3607 | if (WARN_ON(pwq->refcnt > 1) || |
3608 | WARN_ON(pwq->nr_active) || | ||
3528 | WARN_ON(!list_empty(&pwq->delayed_works))) { | 3609 | WARN_ON(!list_empty(&pwq->delayed_works))) { |
3529 | spin_unlock_irq(&workqueue_lock); | 3610 | spin_unlock_irq(&workqueue_lock); |
3530 | return; | 3611 | return; |
@@ -3545,17 +3626,27 @@ void destroy_workqueue(struct workqueue_struct *wq) | |||
3545 | wq->rescuer = NULL; | 3626 | wq->rescuer = NULL; |
3546 | } | 3627 | } |
3547 | 3628 | ||
3548 | /* | 3629 | if (!(wq->flags & WQ_UNBOUND)) { |
3549 | * We're the sole accessor of @wq at this point. Directly access | 3630 | /* |
3550 | * the first pwq and put its pool. | 3631 | * The base ref is never dropped on per-cpu pwqs. Directly |
3551 | */ | 3632 | * free the pwqs and wq. |
3552 | if (wq->flags & WQ_UNBOUND) { | 3633 | */ |
3634 | free_percpu(wq->cpu_pwqs); | ||
3635 | kfree(wq); | ||
3636 | } else { | ||
3637 | /* | ||
3638 | * We're the sole accessor of @wq at this point. Directly | ||
3639 | * access the first pwq and put the base ref. As both pwqs | ||
3640 | * and pools are sched-RCU protected, the lock operations | ||
3641 | * are safe. @wq will be freed when the last pwq is | ||
3642 | * released. | ||
3643 | */ | ||
3553 | pwq = list_first_entry(&wq->pwqs, struct pool_workqueue, | 3644 | pwq = list_first_entry(&wq->pwqs, struct pool_workqueue, |
3554 | pwqs_node); | 3645 | pwqs_node); |
3555 | put_unbound_pool(pwq->pool); | 3646 | spin_lock_irq(&pwq->pool->lock); |
3647 | put_pwq(pwq); | ||
3648 | spin_unlock_irq(&pwq->pool->lock); | ||
3556 | } | 3649 | } |
3557 | free_pwqs(wq); | ||
3558 | kfree(wq); | ||
3559 | } | 3650 | } |
3560 | EXPORT_SYMBOL_GPL(destroy_workqueue); | 3651 | EXPORT_SYMBOL_GPL(destroy_workqueue); |
3561 | 3652 | ||