This patch restores POOL_MANAGING_WORKERS which was replaced by pool->manager_mutex by 6037315269 "workqueue: use mutex for global_cwq manager exclusion". There's a subtle idle worker depletion bug across CPU hotplug events and we need to distinguish an actual manager and CPU hotplug preventing management. POOL_MANAGING_WORKERS will be used for the former and manager_mutex the later. This patch just lays POOL_MANAGING_WORKERS on top of the existing manager_mutex and doesn't introduce any synchronization changes. The next patch will update it. Note that this patch fixes a non-critical anomaly where too_many_workers() may return %true spuriously while CPU hotplug is in progress. While the issue could schedule idle timer spuriously, it didn't trigger any actual misbehavior. tj: Rewrote patch description.
Showing the changes to kernel/workqueue.c (1 of 1 file). Show all
Unified · Split
| @@ -66,6 +66,7 @@ enum { · 65 unmodified lines | |||
| 66 | 66 | ||
| 67 | /* pool flags */ | 67 | /* pool flags */ |
| 68 | POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */ | 68 | POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */ |
| 69 | POOL_MANAGING_WORKERS = 1 << 1, /* managing workers */ | ||
| 69 | 70 | ||
| 70 | /* worker flags */ | 71 | /* worker flags */ |
| 71 | WORKER_STARTED = 1 << 0, /* started */ | 72 | WORKER_STARTED = 1 << 0, /* started */ |
| @@ -652,7 +653,7 @@ static bool need_to_manage_workers(struct worker_pool *pool) · 580 unmodified lines | |||
| 652 | /* Do we have too many workers and should some go away? */ | 653 | /* Do we have too many workers and should some go away? */ |
| 653 | static bool too_many_workers(struct worker_pool *pool) | 654 | static bool too_many_workers(struct worker_pool *pool) |
| 654 | { | 655 | { |
| 655 | bool managing = mutex_is_locked(&pool->manager_mutex); | 656 | bool managing = pool->flags & POOL_MANAGING_WORKERS; |
| 656 | int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ | 657 | int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ |
| 657 | int nr_busy = pool->nr_workers - nr_idle; | 658 | int nr_busy = pool->nr_workers - nr_idle; |
| 658 | 659 | ||
| @@ -1827,6 +1828,7 @@ static bool manage_workers(struct worker *worker) · 1168 unmodified lines | |||
| 1827 | if (!mutex_trylock(&pool->manager_mutex)) | 1828 | if (!mutex_trylock(&pool->manager_mutex)) |
| 1828 | return ret; | 1829 | return ret; |
| 1829 | 1830 | ||
| 1831 | pool->flags |= POOL_MANAGING_WORKERS; | ||
| 1830 | pool->flags &= ~POOL_MANAGE_WORKERS; | 1832 | pool->flags &= ~POOL_MANAGE_WORKERS; |
| 1831 | 1833 | ||
| 1832 | /* | 1834 | /* |
| @@ -1836,6 +1838,7 @@ static bool manage_workers(struct worker *worker) · 3 unmodified lines | |||
| 1836 | ret |= maybe_destroy_workers(pool); | 1838 | ret |= maybe_destroy_workers(pool); |
| 1837 | ret |= maybe_create_worker(pool); | 1839 | ret |= maybe_create_worker(pool); |
| 1838 | 1840 | ||
| 1841 | pool->flags &= ~POOL_MANAGING_WORKERS; | ||
| 1839 | mutex_unlock(&pool->manager_mutex); | 1842 | mutex_unlock(&pool->manager_mutex); |
| 1840 | return ret; | 1843 | return ret; |
| 1841 | } | 1844 | } |