aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/workqueue.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 383548ed0b54..1e1373bcb3e3 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1825,10 +1825,45 @@ static bool manage_workers(struct worker *worker)
1825 struct worker_pool *pool = worker->pool; 1825 struct worker_pool *pool = worker->pool;
1826 bool ret = false; 1826 bool ret = false;
1827 1827
1828 if (!mutex_trylock(&pool->manager_mutex)) 1828 if (pool->flags & POOL_MANAGING_WORKERS)
1829 return ret; 1829 return ret;
1830 1830
1831 pool->flags |= POOL_MANAGING_WORKERS; 1831 pool->flags |= POOL_MANAGING_WORKERS;
1832
1833 /*
1834 * To simplify both worker management and CPU hotplug, hold off
1835 * management while hotplug is in progress. CPU hotplug path can't
1836 * grab %POOL_MANAGING_WORKERS to achieve this because that can
1837 * lead to idle worker depletion (all become busy thinking someone
1838 * else is managing) which in turn can result in deadlock under
1839 * extreme circumstances. Use @pool->manager_mutex to synchronize
1840 * manager against CPU hotplug.
1841 *
1842 * manager_mutex would always be free unless CPU hotplug is in
1843 * progress. trylock first without dropping @gcwq->lock.
1844 */
1845 if (unlikely(!mutex_trylock(&pool->manager_mutex))) {
1846 spin_unlock_irq(&pool->gcwq->lock);
1847 mutex_lock(&pool->manager_mutex);
1848 /*
1849 * CPU hotplug could have happened while we were waiting
1850 * for manager_mutex. Hotplug itself can't handle us
1851 * because manager isn't either on idle or busy list, and
1852 * @gcwq's state and ours could have deviated.
1853 *
1854 * As hotplug is now excluded via manager_mutex, we can
1855 * simply try to bind. It will succeed or fail depending
1856 * on @gcwq's current state. Try it and adjust
1857 * %WORKER_UNBOUND accordingly.
1858 */
1859 if (worker_maybe_bind_and_lock(worker))
1860 worker->flags &= ~WORKER_UNBOUND;
1861 else
1862 worker->flags |= WORKER_UNBOUND;
1863
1864 ret = true;
1865 }
1866
1832 pool->flags &= ~POOL_MANAGE_WORKERS; 1867 pool->flags &= ~POOL_MANAGE_WORKERS;
1833 1868
1834 /* 1869 /*