|
@@ -68,6 +68,7 @@ enum {
|
|
|
* attach_mutex to avoid changing binding state while
|
|
|
* worker_attach_to_pool() is in progress.
|
|
|
*/
|
|
|
+ POOL_MANAGER_ACTIVE = 1 << 0, /* being managed */
|
|
|
POOL_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
|
|
|
|
|
|
/* worker flags */
|
|
@@ -165,7 +166,6 @@ struct worker_pool {
|
|
|
/* L: hash of busy workers */
|
|
|
|
|
|
/* see manage_workers() for details on the two manager mutexes */
|
|
|
- struct mutex manager_arb; /* manager arbitration */
|
|
|
struct worker *manager; /* L: purely informational */
|
|
|
struct mutex attach_mutex; /* attach/detach exclusion */
|
|
|
struct list_head workers; /* A: attached workers */
|
|
@@ -299,6 +299,7 @@ static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf;
|
|
|
|
|
|
static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */
|
|
|
static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */
|
|
|
+static DECLARE_WAIT_QUEUE_HEAD(wq_manager_wait); /* wait for manager to go away */
|
|
|
|
|
|
static LIST_HEAD(workqueues); /* PR: list of all workqueues */
|
|
|
static bool workqueue_freezing; /* PL: have wqs started freezing? */
|
|
@@ -801,7 +802,7 @@ static bool need_to_create_worker(struct worker_pool *pool)
|
|
|
/* Do we have too many workers and should some go away? */
|
|
|
static bool too_many_workers(struct worker_pool *pool)
|
|
|
{
|
|
|
- bool managing = mutex_is_locked(&pool->manager_arb);
|
|
|
+ bool managing = pool->flags & POOL_MANAGER_ACTIVE;
|
|
|
int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
|
|
|
int nr_busy = pool->nr_workers - nr_idle;
|
|
|
|
|
@@ -1980,24 +1981,17 @@ static bool manage_workers(struct worker *worker)
|
|
|
{
|
|
|
struct worker_pool *pool = worker->pool;
|
|
|
|
|
|
- /*
|
|
|
- * Anyone who successfully grabs manager_arb wins the arbitration
|
|
|
- * and becomes the manager. mutex_trylock() on pool->manager_arb
|
|
|
- * failure while holding pool->lock reliably indicates that someone
|
|
|
- * else is managing the pool and the worker which failed trylock
|
|
|
- * can proceed to executing work items. This means that anyone
|
|
|
- * grabbing manager_arb is responsible for actually performing
|
|
|
- * manager duties. If manager_arb is grabbed and released without
|
|
|
- * actual management, the pool may stall indefinitely.
|
|
|
- */
|
|
|
- if (!mutex_trylock(&pool->manager_arb))
|
|
|
+ if (pool->flags & POOL_MANAGER_ACTIVE)
|
|
|
return false;
|
|
|
+
|
|
|
+ pool->flags |= POOL_MANAGER_ACTIVE;
|
|
|
pool->manager = worker;
|
|
|
|
|
|
maybe_create_worker(pool);
|
|
|
|
|
|
pool->manager = NULL;
|
|
|
- mutex_unlock(&pool->manager_arb);
|
|
|
+ pool->flags &= ~POOL_MANAGER_ACTIVE;
|
|
|
+ wake_up(&wq_manager_wait);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -3248,7 +3242,6 @@ static int init_worker_pool(struct worker_pool *pool)
|
|
|
setup_timer(&pool->mayday_timer, pool_mayday_timeout,
|
|
|
(unsigned long)pool);
|
|
|
|
|
|
- mutex_init(&pool->manager_arb);
|
|
|
mutex_init(&pool->attach_mutex);
|
|
|
INIT_LIST_HEAD(&pool->workers);
|
|
|
|
|
@@ -3318,13 +3311,15 @@ static void put_unbound_pool(struct worker_pool *pool)
|
|
|
hash_del(&pool->hash_node);
|
|
|
|
|
|
/*
|
|
|
- * Become the manager and destroy all workers. Grabbing
|
|
|
- * manager_arb prevents @pool's workers from blocking on
|
|
|
- * attach_mutex.
|
|
|
+ * Become the manager and destroy all workers. This prevents
|
|
|
+ * @pool's workers from blocking on attach_mutex. We're the last
|
|
|
+ * manager and @pool gets freed with the flag set.
|
|
|
*/
|
|
|
- mutex_lock(&pool->manager_arb);
|
|
|
-
|
|
|
spin_lock_irq(&pool->lock);
|
|
|
+ wait_event_lock_irq(wq_manager_wait,
|
|
|
+ !(pool->flags & POOL_MANAGER_ACTIVE), pool->lock);
|
|
|
+ pool->flags |= POOL_MANAGER_ACTIVE;
|
|
|
+
|
|
|
while ((worker = first_idle_worker(pool)))
|
|
|
destroy_worker(worker);
|
|
|
WARN_ON(pool->nr_workers || pool->nr_idle);
|
|
@@ -3338,8 +3333,6 @@ static void put_unbound_pool(struct worker_pool *pool)
|
|
|
if (pool->detach_completion)
|
|
|
wait_for_completion(pool->detach_completion);
|
|
|
|
|
|
- mutex_unlock(&pool->manager_arb);
|
|
|
-
|
|
|
/* shut down the timers */
|
|
|
del_timer_sync(&pool->idle_timer);
|
|
|
del_timer_sync(&pool->mayday_timer);
|