We must clear this WORKER_REBIND before busy_worker_rebind_fn() returns, otherise the worker may go to call idle_worker_rebind() wrongly, which may access to the invalid ->idle_rebind and sleep forever in ->rebind_hold.
Signed-off-by: Lai Jiangshan <[email protected]> --- kernel/workqueue.c | 16 ++++++++++++---- 1 files changed, 12 insertions(+), 4 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7b91332..cc49593 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1655,8 +1655,17 @@ static void busy_worker_rebind_fn(struct work_struct *work) struct worker *worker = container_of(work, struct worker, rebind_work); struct global_cwq *gcwq = worker->pool->gcwq; - if (worker_maybe_bind_and_lock(worker)) - worker_clr_flags(worker, WORKER_REBIND); + worker_maybe_bind_and_lock(worker); + + /* + * If hotplug has happened after rebind_workers(), a new %UNBOUND will + * have been set in worker->flags, so we can clear WORKER_REBIND + * unconditionaly(even the above worker_maybe_bind_and_lock() failed). + * + * And we must clear this WORKER_REBIND before return, otherwise + * this worker may go to call idle_worker_rebind() wrongly. + */ + worker_clr_flags(worker, WORKER_REBIND); spin_unlock_irq(&gcwq->lock); } @@ -2362,8 +2371,7 @@ woke_up: spin_lock_irq(&gcwq->lock); /* - * DIE can be set only while idle and REBIND set while busy has - * @worker->rebind_work scheduled. Checking here is enough. + * DIE or REBIND can be set only while idle. Checking here is enough. */ if (unlikely(worker->flags & (WORKER_REBIND | WORKER_DIE))) { spin_unlock_irq(&gcwq->lock); -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

