Skip to content

Commit 6ba34d3

Browse files
Waiman-Longhtejun
authored andcommitted
cgroup/cpuset: Fix violation of cpuset locking rule
The cpuset fields that manage partition root state do not strictly follow the cpuset locking rule that update to cpuset has to be done with both the callback_lock and cpuset_mutex held. This is now fixed by making sure that the locking rule is upheld. Fixes: 3881b86 ("cpuset: Add an error state to cpuset.sched.partition") Fixes: 4b842da ("cpuset: Make CPU hotplug work with partition") Signed-off-by: Waiman Long <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 15d428e commit 6ba34d3

File tree

1 file changed

+35
-23
lines changed

1 file changed

+35
-23
lines changed

kernel/cgroup/cpuset.c

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
11481148
struct cpuset *parent = parent_cs(cpuset);
11491149
int adding; /* Moving cpus from effective_cpus to subparts_cpus */
11501150
int deleting; /* Moving cpus from subparts_cpus to effective_cpus */
1151+
int new_prs;
11511152
bool part_error = false; /* Partition error? */
11521153

11531154
percpu_rwsem_assert_held(&cpuset_rwsem);
@@ -1183,6 +1184,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
11831184
* A cpumask update cannot make parent's effective_cpus become empty.
11841185
*/
11851186
adding = deleting = false;
1187+
new_prs = cpuset->partition_root_state;
11861188
if (cmd == partcmd_enable) {
11871189
cpumask_copy(tmp->addmask, cpuset->cpus_allowed);
11881190
adding = true;
@@ -1247,11 +1249,11 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
12471249
switch (cpuset->partition_root_state) {
12481250
case PRS_ENABLED:
12491251
if (part_error)
1250-
cpuset->partition_root_state = PRS_ERROR;
1252+
new_prs = PRS_ERROR;
12511253
break;
12521254
case PRS_ERROR:
12531255
if (!part_error)
1254-
cpuset->partition_root_state = PRS_ENABLED;
1256+
new_prs = PRS_ENABLED;
12551257
break;
12561258
}
12571259
/*
@@ -1260,10 +1262,10 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
12601262
part_error = (prev_prs == PRS_ERROR);
12611263
}
12621264

1263-
if (!part_error && (cpuset->partition_root_state == PRS_ERROR))
1265+
if (!part_error && (new_prs == PRS_ERROR))
12641266
return 0; /* Nothing need to be done */
12651267

1266-
if (cpuset->partition_root_state == PRS_ERROR) {
1268+
if (new_prs == PRS_ERROR) {
12671269
/*
12681270
* Remove all its cpus from parent's subparts_cpus.
12691271
*/
@@ -1272,7 +1274,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
12721274
parent->subparts_cpus);
12731275
}
12741276

1275-
if (!adding && !deleting)
1277+
if (!adding && !deleting && (new_prs == cpuset->partition_root_state))
12761278
return 0;
12771279

12781280
/*
@@ -1299,6 +1301,9 @@ static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
12991301
}
13001302

13011303
parent->nr_subparts_cpus = cpumask_weight(parent->subparts_cpus);
1304+
1305+
if (cpuset->partition_root_state != new_prs)
1306+
cpuset->partition_root_state = new_prs;
13021307
spin_unlock_irq(&callback_lock);
13031308

13041309
return cmd == partcmd_update;
@@ -1321,6 +1326,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
13211326
struct cpuset *cp;
13221327
struct cgroup_subsys_state *pos_css;
13231328
bool need_rebuild_sched_domains = false;
1329+
int new_prs;
13241330

13251331
rcu_read_lock();
13261332
cpuset_for_each_descendant_pre(cp, pos_css, cs) {
@@ -1360,7 +1366,8 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
13601366
* update_tasks_cpumask() again for tasks in the parent
13611367
* cpuset if the parent's subparts_cpus changes.
13621368
*/
1363-
if ((cp != cs) && cp->partition_root_state) {
1369+
new_prs = cp->partition_root_state;
1370+
if ((cp != cs) && new_prs) {
13641371
switch (parent->partition_root_state) {
13651372
case PRS_DISABLED:
13661373
/*
@@ -1370,7 +1377,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
13701377
*/
13711378
WARN_ON_ONCE(cp->partition_root_state
13721379
!= PRS_ERROR);
1373-
cp->partition_root_state = PRS_DISABLED;
1380+
new_prs = PRS_DISABLED;
13741381

13751382
/*
13761383
* clear_bit() is an atomic operation and
@@ -1391,11 +1398,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
13911398
/*
13921399
* When parent is invalid, it has to be too.
13931400
*/
1394-
cp->partition_root_state = PRS_ERROR;
1395-
if (cp->nr_subparts_cpus) {
1396-
cp->nr_subparts_cpus = 0;
1397-
cpumask_clear(cp->subparts_cpus);
1398-
}
1401+
new_prs = PRS_ERROR;
13991402
break;
14001403
}
14011404
}
@@ -1407,8 +1410,7 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
14071410
spin_lock_irq(&callback_lock);
14081411

14091412
cpumask_copy(cp->effective_cpus, tmp->new_cpus);
1410-
if (cp->nr_subparts_cpus &&
1411-
(cp->partition_root_state != PRS_ENABLED)) {
1413+
if (cp->nr_subparts_cpus && (new_prs != PRS_ENABLED)) {
14121414
cp->nr_subparts_cpus = 0;
14131415
cpumask_clear(cp->subparts_cpus);
14141416
} else if (cp->nr_subparts_cpus) {
@@ -1435,6 +1437,10 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp)
14351437
= cpumask_weight(cp->subparts_cpus);
14361438
}
14371439
}
1440+
1441+
if (new_prs != cp->partition_root_state)
1442+
cp->partition_root_state = new_prs;
1443+
14381444
spin_unlock_irq(&callback_lock);
14391445

14401446
WARN_ON(!is_in_v2_mode() &&
@@ -1944,25 +1950,25 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
19441950
*/
19451951
static int update_prstate(struct cpuset *cs, int new_prs)
19461952
{
1947-
int err;
1953+
int err, old_prs = cs->partition_root_state;
19481954
struct cpuset *parent = parent_cs(cs);
19491955
struct tmpmasks tmpmask;
19501956

1951-
if (new_prs == cs->partition_root_state)
1957+
if (old_prs == new_prs)
19521958
return 0;
19531959

19541960
/*
19551961
* Cannot force a partial or invalid partition root to a full
19561962
* partition root.
19571963
*/
1958-
if (new_prs && (cs->partition_root_state < 0))
1964+
if (new_prs && (old_prs == PRS_ERROR))
19591965
return -EINVAL;
19601966

19611967
if (alloc_cpumasks(NULL, &tmpmask))
19621968
return -ENOMEM;
19631969

19641970
err = -EINVAL;
1965-
if (!cs->partition_root_state) {
1971+
if (!old_prs) {
19661972
/*
19671973
* Turning on partition root requires setting the
19681974
* CS_CPU_EXCLUSIVE bit implicitly as well and cpus_allowed
@@ -1981,14 +1987,12 @@ static int update_prstate(struct cpuset *cs, int new_prs)
19811987
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
19821988
goto out;
19831989
}
1984-
cs->partition_root_state = PRS_ENABLED;
19851990
} else {
19861991
/*
19871992
* Turning off partition root will clear the
19881993
* CS_CPU_EXCLUSIVE bit.
19891994
*/
1990-
if (cs->partition_root_state == PRS_ERROR) {
1991-
cs->partition_root_state = PRS_DISABLED;
1995+
if (old_prs == PRS_ERROR) {
19921996
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
19931997
err = 0;
19941998
goto out;
@@ -1999,8 +2003,6 @@ static int update_prstate(struct cpuset *cs, int new_prs)
19992003
if (err)
20002004
goto out;
20012005

2002-
cs->partition_root_state = PRS_DISABLED;
2003-
20042006
/* Turning off CS_CPU_EXCLUSIVE will not return error */
20052007
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
20062008
}
@@ -2017,6 +2019,12 @@ static int update_prstate(struct cpuset *cs, int new_prs)
20172019

20182020
rebuild_sched_domains_locked();
20192021
out:
2022+
if (!err) {
2023+
spin_lock_irq(&callback_lock);
2024+
cs->partition_root_state = new_prs;
2025+
spin_unlock_irq(&callback_lock);
2026+
}
2027+
20202028
free_cpumasks(NULL, &tmpmask);
20212029
return err;
20222030
}
@@ -3080,8 +3088,10 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
30803088
if (is_partition_root(cs) && (cpumask_empty(&new_cpus) ||
30813089
(parent->partition_root_state == PRS_ERROR))) {
30823090
if (cs->nr_subparts_cpus) {
3091+
spin_lock_irq(&callback_lock);
30833092
cs->nr_subparts_cpus = 0;
30843093
cpumask_clear(cs->subparts_cpus);
3094+
spin_unlock_irq(&callback_lock);
30853095
compute_effective_cpumask(&new_cpus, cs, parent);
30863096
}
30873097

@@ -3095,7 +3105,9 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs, struct tmpmasks *tmp)
30953105
cpumask_empty(&new_cpus)) {
30963106
update_parent_subparts_cpumask(cs, partcmd_disable,
30973107
NULL, tmp);
3108+
spin_lock_irq(&callback_lock);
30983109
cs->partition_root_state = PRS_ERROR;
3110+
spin_unlock_irq(&callback_lock);
30993111
}
31003112
cpuset_force_rebuild();
31013113
}

0 commit comments

Comments
 (0)