Skip to content

Commit 34a08ae

Browse files
htejungregkh
authored andcommitted
workqueue: implicit ordered attribute should be overridable
commit 0a94efb5acbb6980d7c9ab604372d93cd507e4d8 upstream. 5c0338c68706 ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered") automatically enabled ordered attribute for unbound workqueues w/ max_active == 1. Because ordered workqueues reject max_active and some attribute changes, this implicit ordered mode broke cases where the user creates an unbound workqueue w/ max_active == 1 and later explicitly changes the related attributes. This patch distinguishes explicit and implicit ordered setting and overrides from attribute changes if implict. Signed-off-by: Tejun Heo <tj@kernel.org> Fixes: 5c0338c68706 ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered") Cc: Holger Hoffstätte <holger@applied-asynchrony.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0c78704 commit 34a08ae

2 files changed

Lines changed: 12 additions & 5 deletions

File tree

include/linux/workqueue.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ enum {
311311

312312
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
313313
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
314+
__WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
314315

315316
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
316317
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
@@ -408,7 +409,8 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
408409
* Pointer to the allocated workqueue on success, %NULL on failure.
409410
*/
410411
#define alloc_ordered_workqueue(fmt, flags, args...) \
411-
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
412+
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | \
413+
__WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
412414

413415
#define create_workqueue(name) \
414416
alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))

kernel/workqueue.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3647,8 +3647,12 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
36473647
return -EINVAL;
36483648

36493649
/* creating multiple pwqs breaks ordering guarantee */
3650-
if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
3651-
return -EINVAL;
3650+
if (!list_empty(&wq->pwqs)) {
3651+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
3652+
return -EINVAL;
3653+
3654+
wq->flags &= ~__WQ_ORDERED;
3655+
}
36523656

36533657
ctx = apply_wqattrs_prepare(wq, attrs);
36543658

@@ -4032,13 +4036,14 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
40324036
struct pool_workqueue *pwq;
40334037

40344038
/* disallow meddling with max_active for ordered workqueues */
4035-
if (WARN_ON(wq->flags & __WQ_ORDERED))
4039+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
40364040
return;
40374041

40384042
max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
40394043

40404044
mutex_lock(&wq->mutex);
40414045

4046+
wq->flags &= ~__WQ_ORDERED;
40424047
wq->saved_max_active = max_active;
40434048

40444049
for_each_pwq(pwq, wq)
@@ -5164,7 +5169,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
51645169
* attributes breaks ordering guarantee. Disallow exposing ordered
51655170
* workqueues.
51665171
*/
5167-
if (WARN_ON(wq->flags & __WQ_ORDERED))
5172+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
51685173
return -EINVAL;
51695174

51705175
wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);

0 commit comments

Comments
 (0)