Messages in this thread Patch in this message | | | From | Valentin Schneider <> | Subject | [PATCH 2/2] workqueue: Fix affinity of kworkers attached during late hotplug | Date | Thu, 10 Dec 2020 16:38:30 +0000 |
| |
Per-CPU kworkers forcefully migrated away by hotplug via workqueue_offline_cpu() can end up spawning more kworkers via
manage_workers() -> maybe_create_worker()
Workers created at this point will be bound using
pool->attrs->cpumask
which in this case is wrong, as the hotplug state machine already migrated all pinned kworkers away from this CPU. This ends up triggering the BUG_ON condition is sched_cpu_dying() (i.e. there's a kworker enqueued on the dying rq).
Special-case workers being attached to DISASSOCIATED pools and bind them to cpu_active_mask, mimicking them being present when workqueue_offline_cpu() was invoked.
Link: https://lore.kernel.org/r/ff62e3ee994efb3620177bf7b19fab16f4866845.camel@redhat.com Fixes: 06249738a41a ("workqueue: Manually break affinity on hotplug") Reported-by: Qian Cai <cai@redhat.com> Signed-off-by: Valentin Schneider <valentin.schneider@arm.com> --- kernel/workqueue.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 9880b6c0e272..fb1418edf85c 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1848,19 +1848,29 @@ static void worker_attach_to_pool(struct worker *worker, { mutex_lock(&wq_pool_attach_mutex); - /* - * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any - * online CPUs. It'll be re-applied when any of the CPUs come up. - */ - set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask); - /* * The wq_pool_attach_mutex ensures %POOL_DISASSOCIATED remains * stable across this function. See the comments above the flag * definition for details. + * + * Worker might get attached to a pool *after* workqueue_offline_cpu() + * was run - e.g. created by manage_workers() from a kworker which was + * forcefully moved away by hotplug. Kworkers created from this point on + * need to have their affinity changed as if they were present during + * workqueue_offline_cpu(). + * + * This will be resolved in rebind_workers(). */ - if (pool->flags & POOL_DISASSOCIATED) + if (pool->flags & POOL_DISASSOCIATED) { worker->flags |= WORKER_UNBOUND; + set_cpus_allowed_ptr(worker->task, cpu_active_mask); + } else { + /* + * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any + * online CPUs. It'll be re-applied when any of the CPUs come up. + */ + set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask); + } list_add_tail(&worker->node, &pool->workers); worker->pool = pool; -- 2.27.0
| |