Skip to content

Commit 0a94efb

Browse files
committed
workqueue: implicit ordered attribute should be overridable
5c0338c ("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 <[email protected]> Fixes: 5c0338c ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered")
1 parent 5c0338c commit 0a94efb

File tree

2 files changed

+12
-5
lines changed

2 files changed

+12
-5
lines changed

include/linux/workqueue.h

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

324324
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
325325
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
326+
__WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
326327
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
327328

328329
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
@@ -422,7 +423,8 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
422423
* Pointer to the allocated workqueue on success, %NULL on failure.
423424
*/
424425
#define alloc_ordered_workqueue(fmt, flags, args...) \
425-
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
426+
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | \
427+
__WQ_ORDERED_EXPLICIT | (flags), 1, ##args)
426428

427429
#define create_workqueue(name) \
428430
alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))

kernel/workqueue.c

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

37463746
/* creating multiple pwqs breaks ordering guarantee */
3747-
if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
3748-
return -EINVAL;
3747+
if (!list_empty(&wq->pwqs)) {
3748+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
3749+
return -EINVAL;
3750+
3751+
wq->flags &= ~__WQ_ORDERED;
3752+
}
37493753

37503754
ctx = apply_wqattrs_prepare(wq, attrs);
37513755
if (!ctx)
@@ -4129,13 +4133,14 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
41294133
struct pool_workqueue *pwq;
41304134

41314135
/* disallow meddling with max_active for ordered workqueues */
4132-
if (WARN_ON(wq->flags & __WQ_ORDERED))
4136+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
41334137
return;
41344138

41354139
max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
41364140

41374141
mutex_lock(&wq->mutex);
41384142

4143+
wq->flags &= ~__WQ_ORDERED;
41394144
wq->saved_max_active = max_active;
41404145

41414146
for_each_pwq(pwq, wq)
@@ -5263,7 +5268,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
52635268
* attributes breaks ordering guarantee. Disallow exposing ordered
52645269
* workqueues.
52655270
*/
5266-
if (WARN_ON(wq->flags & __WQ_ORDERED))
5271+
if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))
52675272
return -EINVAL;
52685273

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

0 commit comments

Comments
 (0)