History

workqueue: Add pool_workqueue to pending_pwqs list when unplugging multiple inactive works

In unplug_oldest_pwq(), the first inactive work item on the pool_workqueue is activated correctly. However, if multiple inactive works exist on the same pool_workqueue, subsequent works fail to activate because wq_node_nr_active.pending_pwqs is empty — the list insertion is skipped when the pool_workqueue is plugged. Fix this by checking for additional inactive works in unplug_oldest_pwq() and updating wq_node_nr_active.pending_pwqs accordingly.

Matthew Brost committed 7 months ago

Commit 703ccb61 parent e3989781 file · +13 −1Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+13−1
@@ -1849,8 +1849,20 @@ static void unplug_oldest_pwq(struct workqueue_struct *wq) · 1848 unmodified lines
18491849 raw_spin_lock_irq(&pwq->pool->lock);
18501850 if (pwq->plugged) {
18511851 pwq->plugged = false;
1852− if (pwq_activate_first_inactive(pwq, true))
1852+ if (pwq_activate_first_inactive(pwq, true)) {
1853+ /*
1854+ * While plugged, queueing skips activation which
1855+ * includes bumping the nr_active count and adding the
1856+ * pwq to nna->pending_pwqs if the count can't be
1857+ * obtained. We need to restore both for the pwq being
1858+ * unplugged. The first call activates the first
1859+ * inactive work item and the second, if there are more
1860+ * inactive, puts the pwq on pending_pwqs.
1861+ */
1862+ pwq_activate_first_inactive(pwq, false);
1863+
18531864 kick_pool(pwq->pool);
1865+ }
18541866 }
18551867 raw_spin_unlock_irq(&pwq->pool->lock);
18561868 }