Skip to content

Commit 2a8ab0f

Browse files
committed
Merge branch 'workqueue/for-5.16-fixes' into workqueue/for-5.17
for-5.16-fixes contains two subtle race conditions which were introduced by scheduler side code cleanups. The branch didn't get pushed out, so merge into for-5.17.
2 parents 84f91c6 + 45c753f commit 2a8ab0f

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

kernel/workqueue.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,17 @@ void wq_worker_running(struct task_struct *task)
864864

865865
if (!worker->sleeping)
866866
return;
867+
868+
/*
869+
* If preempted by unbind_workers() between the WORKER_NOT_RUNNING check
870+
* and the nr_running increment below, we may ruin the nr_running reset
871+
* and leave with an unexpected pool->nr_running == 1 on the newly unbound
872+
* pool. Protect against such race.
873+
*/
874+
preempt_disable();
867875
if (!(worker->flags & WORKER_NOT_RUNNING))
868876
atomic_inc(&worker->pool->nr_running);
877+
preempt_enable();
869878
worker->sleeping = 0;
870879
}
871880

@@ -898,6 +907,16 @@ void wq_worker_sleeping(struct task_struct *task)
898907
worker->sleeping = 1;
899908
raw_spin_lock_irq(&pool->lock);
900909

910+
/*
911+
* Recheck in case unbind_workers() preempted us. We don't
912+
* want to decrement nr_running after the worker is unbound
913+
* and nr_running has been reset.
914+
*/
915+
if (worker->flags & WORKER_NOT_RUNNING) {
916+
raw_spin_unlock_irq(&pool->lock);
917+
return;
918+
}
919+
901920
/*
902921
* The counterpart of the following dec_and_test, implied mb,
903922
* worklist not empty test sequence is in insert_work().
@@ -1526,7 +1545,8 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
15261545
* @work: work to queue
15271546
*
15281547
* We queue the work to a specific CPU, the caller must ensure it
1529-
* can't go away.
1548+
* can't go away. Callers that fail to ensure that the specified
1549+
* CPU cannot go away will execute on a randomly chosen CPU.
15301550
*
15311551
* Return: %false if @work was already on a queue, %true otherwise.
15321552
*/

0 commit comments

Comments
 (0)