Skip to content

Commit 99c621e

Browse files
Lai Jiangshanhtejun
authored andcommitted
workqueue: Protects wq_unbound_cpumask with wq_pool_attach_mutex
When unbind_workers() reads wq_unbound_cpumask to set the affinity of freshly-unbound kworkers, it only holds wq_pool_attach_mutex. This isn't sufficient as wq_unbound_cpumask is only protected by wq_pool_mutex. Make wq_unbound_cpumask protected with wq_pool_attach_mutex and also remove the need of temporary saved_cpumask. Fixes: 10a5a65 ("workqueue: Restrict kworker in the offline CPU pool running on housekeeping CPUs") Reported-by: Valentin Schneider <[email protected]> Signed-off-by: Lai Jiangshan <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent c76feb0 commit 99c621e

File tree

1 file changed

+16
-25
lines changed

1 file changed

+16
-25
lines changed

kernel/workqueue.c

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ static struct rcuwait manager_wait = __RCUWAIT_INITIALIZER(manager_wait);
326326
static LIST_HEAD(workqueues); /* PR: list of all workqueues */
327327
static bool workqueue_freezing; /* PL: have wqs started freezing? */
328328

329-
/* PL: allowable cpus for unbound wqs and work items */
329+
/* PL&A: allowable cpus for unbound wqs and work items */
330330
static cpumask_var_t wq_unbound_cpumask;
331331

332332
/* CPU where unbound work was last round robin scheduled from this CPU */
@@ -3956,7 +3956,8 @@ static void apply_wqattrs_cleanup(struct apply_wqattrs_ctx *ctx)
39563956
/* allocate the attrs and pwqs for later installation */
39573957
static struct apply_wqattrs_ctx *
39583958
apply_wqattrs_prepare(struct workqueue_struct *wq,
3959-
const struct workqueue_attrs *attrs)
3959+
const struct workqueue_attrs *attrs,
3960+
const cpumask_var_t unbound_cpumask)
39603961
{
39613962
struct apply_wqattrs_ctx *ctx;
39623963
struct workqueue_attrs *new_attrs, *tmp_attrs;
@@ -3972,14 +3973,15 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
39723973
goto out_free;
39733974

39743975
/*
3975-
* Calculate the attrs of the default pwq.
3976+
* Calculate the attrs of the default pwq with unbound_cpumask
3977+
* which is wq_unbound_cpumask or to set to wq_unbound_cpumask.
39763978
* If the user configured cpumask doesn't overlap with the
39773979
* wq_unbound_cpumask, we fallback to the wq_unbound_cpumask.
39783980
*/
39793981
copy_workqueue_attrs(new_attrs, attrs);
3980-
cpumask_and(new_attrs->cpumask, new_attrs->cpumask, wq_unbound_cpumask);
3982+
cpumask_and(new_attrs->cpumask, new_attrs->cpumask, unbound_cpumask);
39813983
if (unlikely(cpumask_empty(new_attrs->cpumask)))
3982-
cpumask_copy(new_attrs->cpumask, wq_unbound_cpumask);
3984+
cpumask_copy(new_attrs->cpumask, unbound_cpumask);
39833985

39843986
/*
39853987
* We may create multiple pwqs with differing cpumasks. Make a
@@ -4076,7 +4078,7 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
40764078
wq->flags &= ~__WQ_ORDERED;
40774079
}
40784080

4079-
ctx = apply_wqattrs_prepare(wq, attrs);
4081+
ctx = apply_wqattrs_prepare(wq, attrs, wq_unbound_cpumask);
40804082
if (!ctx)
40814083
return -ENOMEM;
40824084

@@ -5377,7 +5379,7 @@ void thaw_workqueues(void)
53775379
}
53785380
#endif /* CONFIG_FREEZER */
53795381

5380-
static int workqueue_apply_unbound_cpumask(void)
5382+
static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
53815383
{
53825384
LIST_HEAD(ctxs);
53835385
int ret = 0;
@@ -5393,7 +5395,7 @@ static int workqueue_apply_unbound_cpumask(void)
53935395
if (wq->flags & __WQ_ORDERED)
53945396
continue;
53955397

5396-
ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs);
5398+
ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs, unbound_cpumask);
53975399
if (!ctx) {
53985400
ret = -ENOMEM;
53995401
break;
@@ -5408,6 +5410,11 @@ static int workqueue_apply_unbound_cpumask(void)
54085410
apply_wqattrs_cleanup(ctx);
54095411
}
54105412

5413+
if (!ret) {
5414+
mutex_lock(&wq_pool_attach_mutex);
5415+
cpumask_copy(wq_unbound_cpumask, unbound_cpumask);
5416+
mutex_unlock(&wq_pool_attach_mutex);
5417+
}
54115418
return ret;
54125419
}
54135420

@@ -5426,7 +5433,6 @@ static int workqueue_apply_unbound_cpumask(void)
54265433
int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
54275434
{
54285435
int ret = -EINVAL;
5429-
cpumask_var_t saved_cpumask;
54305436

54315437
/*
54325438
* Not excluding isolated cpus on purpose.
@@ -5440,23 +5446,8 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
54405446
goto out_unlock;
54415447
}
54425448

5443-
if (!zalloc_cpumask_var(&saved_cpumask, GFP_KERNEL)) {
5444-
ret = -ENOMEM;
5445-
goto out_unlock;
5446-
}
5447-
5448-
/* save the old wq_unbound_cpumask. */
5449-
cpumask_copy(saved_cpumask, wq_unbound_cpumask);
5450-
5451-
/* update wq_unbound_cpumask at first and apply it to wqs. */
5452-
cpumask_copy(wq_unbound_cpumask, cpumask);
5453-
ret = workqueue_apply_unbound_cpumask();
5454-
5455-
/* restore the wq_unbound_cpumask when failed. */
5456-
if (ret < 0)
5457-
cpumask_copy(wq_unbound_cpumask, saved_cpumask);
5449+
ret = workqueue_apply_unbound_cpumask(cpumask);
54585450

5459-
free_cpumask_var(saved_cpumask);
54605451
out_unlock:
54615452
apply_wqattrs_unlock();
54625453
}

0 commit comments

Comments
 (0)