Hello, Johannes. On Fri, May 05, 2023 at 11:05:45PM +0200, Johannes Berg wrote: ... > The implementation of (2) is a bit ... awkward, @Tejun, @Lai, there's no > way to "pause" an ordered workqueue, is there? I came up with the below > patch, but it's a bit ugly and requires a lot of context switches. Just > flushing isn't enough since then some work might start and hang on > acquiring the lock. There isn't currently but workqueue already does something similar for freezing by temporarily setting max_active to zero, so if you apply a patch like the following diff --git a/kernel/workqueue.c b/kernel/workqueue.c index b8b541caed48..6daf9ee7450d 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4360,11 +4360,11 @@ static int wq_clamp_max_active(int max_active, unsigned int flags, { int lim = flags & WQ_UNBOUND ? WQ_UNBOUND_MAX_ACTIVE : WQ_MAX_ACTIVE; - if (max_active < 1 || max_active > lim) + if (max_active < 0 || max_active > lim) pr_warn("workqueue: max_active %d requested for %s is out of range, clamping between %d and %d\n", max_active, name, 1, lim); - return clamp_val(max_active, 1, lim); + return clamp_val(max_active, 0, lim); } /* @@ -4625,7 +4625,8 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) struct pool_workqueue *pwq; /* disallow meddling with max_active for ordered workqueues */ - if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT)) + if (WARN_ON((wq->flags & __WQ_ORDERED_EXPLICIT) && + max_active != 0 && max_active != 1)) return; max_active = wq_clamp_max_active(max_active, wq->flags, wq->name); and then do set_max_active(wq, 0) followed by flush_workqueue(), it should be paused until max_active is restored to 1. It probably would be better to add a separate pause / resume interface which sets a per-wq flag which is read by pwq_adjust_max_active() tho. Anyways, it's not difficult to implement at all. Thanks. -- tejun