Skip to content

Commit 94cf58b

Browse files
committed
workqueue: make hotplug processing per-pool
Instead of holding locks from both pools and then processing the pools together, make hotplug processing per-pool - grab locks of one pool, process it, release it and then proceed to the next pool. rebind_workers() is updated to take and process @pool instead of @gcwq which results in a lot of de-indentation. gcwq_claim_assoc_and_lock() and its counterpart are replaced with in-line per-pool locking. While this patch changes processing order across pools, order within each pool remains the same. As each pool is independent, this shouldn't break anything. This is part of an effort to remove global_cwq and make worker_pool the top level abstraction, which in turn will help implementing worker pools with user-specified attributes. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Lai Jiangshan <laijs@cn.fujitsu.com>
1 parent d565ed6 commit 94cf58b

File tree

1 file changed

+62
-87
lines changed

1 file changed

+62
-87
lines changed

kernel/workqueue.c

Lines changed: 62 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,10 +1670,10 @@ static void busy_worker_rebind_fn(struct work_struct *work)
16701670
}
16711671

16721672
/**
1673-
* rebind_workers - rebind all workers of a gcwq to the associated CPU
1674-
* @gcwq: gcwq of interest
1673+
* rebind_workers - rebind all workers of a pool to the associated CPU
1674+
* @pool: pool of interest
16751675
*
1676-
* @gcwq->cpu is coming online. Rebind all workers to the CPU. Rebinding
1676+
* @pool->cpu is coming online. Rebind all workers to the CPU. Rebinding
16771677
* is different for idle and busy ones.
16781678
*
16791679
* Idle ones will be removed from the idle_list and woken up. They will
@@ -1691,60 +1691,53 @@ static void busy_worker_rebind_fn(struct work_struct *work)
16911691
* including the manager will not appear on @idle_list until rebind is
16921692
* complete, making local wake-ups safe.
16931693
*/
1694-
static void rebind_workers(struct global_cwq *gcwq)
1694+
static void rebind_workers(struct worker_pool *pool)
16951695
{
1696-
struct worker_pool *pool;
16971696
struct worker *worker, *n;
16981697
struct hlist_node *pos;
16991698
int i;
17001699

1701-
for_each_worker_pool(pool, gcwq) {
1702-
lockdep_assert_held(&pool->assoc_mutex);
1703-
lockdep_assert_held(&pool->lock);
1704-
}
1700+
lockdep_assert_held(&pool->assoc_mutex);
1701+
lockdep_assert_held(&pool->lock);
17051702

17061703
/* dequeue and kick idle ones */
1707-
for_each_worker_pool(pool, gcwq) {
1708-
list_for_each_entry_safe(worker, n, &pool->idle_list, entry) {
1709-
/*
1710-
* idle workers should be off @pool->idle_list
1711-
* until rebind is complete to avoid receiving
1712-
* premature local wake-ups.
1713-
*/
1714-
list_del_init(&worker->entry);
1704+
list_for_each_entry_safe(worker, n, &pool->idle_list, entry) {
1705+
/*
1706+
* idle workers should be off @pool->idle_list until rebind
1707+
* is complete to avoid receiving premature local wake-ups.
1708+
*/
1709+
list_del_init(&worker->entry);
17151710

1716-
/*
1717-
* worker_thread() will see the above dequeuing
1718-
* and call idle_worker_rebind().
1719-
*/
1720-
wake_up_process(worker->task);
1721-
}
1711+
/*
1712+
* worker_thread() will see the above dequeuing and call
1713+
* idle_worker_rebind().
1714+
*/
1715+
wake_up_process(worker->task);
1716+
}
17221717

1723-
/* rebind busy workers */
1724-
for_each_busy_worker(worker, i, pos, pool) {
1725-
struct work_struct *rebind_work = &worker->rebind_work;
1726-
struct workqueue_struct *wq;
1718+
/* rebind busy workers */
1719+
for_each_busy_worker(worker, i, pos, pool) {
1720+
struct work_struct *rebind_work = &worker->rebind_work;
1721+
struct workqueue_struct *wq;
17271722

1728-
if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
1729-
work_data_bits(rebind_work)))
1730-
continue;
1723+
if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
1724+
work_data_bits(rebind_work)))
1725+
continue;
17311726

1732-
debug_work_activate(rebind_work);
1727+
debug_work_activate(rebind_work);
17331728

1734-
/*
1735-
* wq doesn't really matter but let's keep
1736-
* @worker->pool and @cwq->pool consistent for
1737-
* sanity.
1738-
*/
1739-
if (std_worker_pool_pri(worker->pool))
1740-
wq = system_highpri_wq;
1741-
else
1742-
wq = system_wq;
1743-
1744-
insert_work(get_cwq(pool->cpu, wq), rebind_work,
1745-
worker->scheduled.next,
1746-
work_color_to_flags(WORK_NO_COLOR));
1747-
}
1729+
/*
1730+
* wq doesn't really matter but let's keep @worker->pool
1731+
* and @cwq->pool consistent for sanity.
1732+
*/
1733+
if (std_worker_pool_pri(worker->pool))
1734+
wq = system_highpri_wq;
1735+
else
1736+
wq = system_wq;
1737+
1738+
insert_work(get_cwq(pool->cpu, wq), rebind_work,
1739+
worker->scheduled.next,
1740+
work_color_to_flags(WORK_NO_COLOR));
17481741
}
17491742
}
17501743

@@ -3497,40 +3490,14 @@ EXPORT_SYMBOL_GPL(work_busy);
34973490
* are a lot of assumptions on strong associations among work, cwq and
34983491
* gcwq which make migrating pending and scheduled works very
34993492
* difficult to implement without impacting hot paths. Secondly,
3500-
* gcwqs serve mix of short, long and very long running works making
3493+
* worker pools serve mix of short, long and very long running works making
35013494
* blocked draining impractical.
35023495
*
35033496
* This is solved by allowing the pools to be disassociated from the CPU
35043497
* running as an unbound one and allowing it to be reattached later if the
35053498
* cpu comes back online.
35063499
*/
35073500

3508-
/* claim manager positions of all pools */
3509-
static void gcwq_claim_assoc_and_lock(struct global_cwq *gcwq)
3510-
{
3511-
struct worker_pool *pool;
3512-
3513-
for_each_worker_pool(pool, gcwq)
3514-
mutex_lock_nested(&pool->assoc_mutex, pool - gcwq->pools);
3515-
3516-
local_irq_disable();
3517-
for_each_worker_pool(pool, gcwq)
3518-
spin_lock_nested(&pool->lock, pool - gcwq->pools);
3519-
}
3520-
3521-
/* release manager positions */
3522-
static void gcwq_release_assoc_and_unlock(struct global_cwq *gcwq)
3523-
{
3524-
struct worker_pool *pool;
3525-
3526-
for_each_worker_pool(pool, gcwq)
3527-
spin_unlock(&pool->lock);
3528-
local_irq_enable();
3529-
3530-
for_each_worker_pool(pool, gcwq)
3531-
mutex_unlock(&pool->assoc_mutex);
3532-
}
3533-
35343501
static void gcwq_unbind_fn(struct work_struct *work)
35353502
{
35363503
struct global_cwq *gcwq = get_gcwq(smp_processor_id());
@@ -3539,27 +3506,30 @@ static void gcwq_unbind_fn(struct work_struct *work)
35393506
struct hlist_node *pos;
35403507
int i;
35413508

3542-
BUG_ON(gcwq->pools[0].cpu != smp_processor_id());
3509+
for_each_worker_pool(pool, gcwq) {
3510+
BUG_ON(pool->cpu != smp_processor_id());
35433511

3544-
gcwq_claim_assoc_and_lock(gcwq);
3512+
mutex_lock(&pool->assoc_mutex);
3513+
spin_lock_irq(&pool->lock);
35453514

3546-
/*
3547-
* We've claimed all manager positions. Make all workers unbound
3548-
* and set DISASSOCIATED. Before this, all workers except for the
3549-
* ones which are still executing works from before the last CPU
3550-
* down must be on the cpu. After this, they may become diasporas.
3551-
*/
3552-
for_each_worker_pool(pool, gcwq) {
3515+
/*
3516+
* We've claimed all manager positions. Make all workers
3517+
* unbound and set DISASSOCIATED. Before this, all workers
3518+
* except for the ones which are still executing works from
3519+
* before the last CPU down must be on the cpu. After
3520+
* this, they may become diasporas.
3521+
*/
35533522
list_for_each_entry(worker, &pool->idle_list, entry)
35543523
worker->flags |= WORKER_UNBOUND;
35553524

35563525
for_each_busy_worker(worker, i, pos, pool)
35573526
worker->flags |= WORKER_UNBOUND;
35583527

35593528
pool->flags |= POOL_DISASSOCIATED;
3560-
}
35613529

3562-
gcwq_release_assoc_and_unlock(gcwq);
3530+
spin_unlock_irq(&pool->lock);
3531+
mutex_unlock(&pool->assoc_mutex);
3532+
}
35633533

35643534
/*
35653535
* Call schedule() so that we cross rq->lock and thus can guarantee
@@ -3615,11 +3585,16 @@ static int __cpuinit workqueue_cpu_up_callback(struct notifier_block *nfb,
36153585

36163586
case CPU_DOWN_FAILED:
36173587
case CPU_ONLINE:
3618-
gcwq_claim_assoc_and_lock(gcwq);
3619-
for_each_worker_pool(pool, gcwq)
3588+
for_each_worker_pool(pool, gcwq) {
3589+
mutex_lock(&pool->assoc_mutex);
3590+
spin_lock_irq(&pool->lock);
3591+
36203592
pool->flags &= ~POOL_DISASSOCIATED;
3621-
rebind_workers(gcwq);
3622-
gcwq_release_assoc_and_unlock(gcwq);
3593+
rebind_workers(pool);
3594+
3595+
spin_unlock_irq(&pool->lock);
3596+
mutex_unlock(&pool->assoc_mutex);
3597+
}
36233598
break;
36243599
}
36253600
return NOTIFY_OK;

0 commit comments

Comments
 (0)