Skip to content

Commit 46c521b

Browse files
Waiman-Longhtejun
authored andcommitted
cgroup/cpuset: Enable invalid to valid local partition transition
When a local partition becomes invalid, it won't transition back to valid partition automatically if a proper "cpuset.cpus.exclusive" or "cpuset.cpus" change is made. Instead, system administrators have to explicitly echo "root" or "isolated" into the "cpuset.cpus.partition" file at the partition root. This patch now enables the automatic transition of an invalid local partition back to valid when there is a proper "cpuset.cpus.exclusive" or "cpuset.cpus" change. Automatic transition of an invalid remote partition to a valid one, however, is not covered by this patch. They still need an explicit write to "cpuset.cpus.partition" to become valid again. The test_cpuset_prs.sh test script is updated to add new test cases to test this automatic state transition. Reported-by: Pierre Gondois <pierre.gondois@arm.com> Link: https://lore.kernel.org/lkml/9777f0d2-2fdf-41cb-bd01-19c52939ef42@arm.com Signed-off-by: Waiman Long <longman@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent 9b81d3a commit 46c521b

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

kernel/cgroup/cpuset.c

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,17 +1806,28 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
18061806
*
18071807
* Compute add/delete mask to/from effective_cpus
18081808
*
1809-
* addmask = effective_xcpus & ~newmask & parent->effective_xcpus
1810-
* delmask = newmask & ~cs->effective_xcpus
1811-
* & parent->effective_xcpus
1809+
* For valid partition:
1810+
* addmask = exclusive_cpus & ~newmask
1811+
* & parent->effective_xcpus
1812+
* delmask = newmask & ~exclusive_cpus
1813+
* & parent->effective_xcpus
1814+
*
1815+
* For invalid partition:
1816+
* delmask = newmask & parent->effective_xcpus
18121817
*/
1813-
cpumask_andnot(tmp->addmask, xcpus, newmask);
1814-
adding = cpumask_and(tmp->addmask, tmp->addmask,
1815-
parent->effective_xcpus);
1818+
if (is_prs_invalid(old_prs)) {
1819+
adding = false;
1820+
deleting = cpumask_and(tmp->delmask,
1821+
newmask, parent->effective_xcpus);
1822+
} else {
1823+
cpumask_andnot(tmp->addmask, xcpus, newmask);
1824+
adding = cpumask_and(tmp->addmask, tmp->addmask,
1825+
parent->effective_xcpus);
18161826

1817-
cpumask_andnot(tmp->delmask, newmask, xcpus);
1818-
deleting = cpumask_and(tmp->delmask, tmp->delmask,
1819-
parent->effective_xcpus);
1827+
cpumask_andnot(tmp->delmask, newmask, xcpus);
1828+
deleting = cpumask_and(tmp->delmask, tmp->delmask,
1829+
parent->effective_xcpus);
1830+
}
18201831
/*
18211832
* Make partition invalid if parent's effective_cpus could
18221833
* become empty and there are tasks in the parent.
@@ -1910,9 +1921,11 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
19101921

19111922
/*
19121923
* Transitioning between invalid to valid or vice versa may require
1913-
* changing CS_CPU_EXCLUSIVE.
1924+
* changing CS_CPU_EXCLUSIVE. In the case of partcmd_update,
1925+
* validate_change() has already been successfully called and
1926+
* CPU lists in cs haven't been updated yet. So defer it to later.
19141927
*/
1915-
if (old_prs != new_prs) {
1928+
if ((old_prs != new_prs) && (cmd != partcmd_update)) {
19161929
int err = update_partition_exclusive(cs, new_prs);
19171930

19181931
if (err)
@@ -1960,6 +1973,9 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
19601973

19611974
spin_unlock_irq(&callback_lock);
19621975

1976+
if ((old_prs != new_prs) && (cmd == partcmd_update))
1977+
update_partition_exclusive(cs, new_prs);
1978+
19631979
if (adding || deleting) {
19641980
update_tasks_cpumask(parent, tmp->addmask);
19651981
update_sibling_cpumasks(parent, cs, tmp);
@@ -2356,8 +2372,9 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
23562372
if (alloc_cpumasks(NULL, &tmp))
23572373
return -ENOMEM;
23582374

2359-
if (is_partition_valid(cs)) {
2360-
if (cpumask_empty(trialcs->effective_xcpus)) {
2375+
if (old_prs) {
2376+
if (is_partition_valid(cs) &&
2377+
cpumask_empty(trialcs->effective_xcpus)) {
23612378
invalidate = true;
23622379
cs->prs_err = PERR_INVCPUS;
23632380
} else if (prstate_housekeeping_conflict(old_prs, trialcs->effective_xcpus)) {
@@ -2391,32 +2408,41 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
23912408
*/
23922409
invalidate = true;
23932410
rcu_read_lock();
2394-
cpuset_for_each_child(cp, css, parent)
2411+
cpuset_for_each_child(cp, css, parent) {
2412+
struct cpumask *xcpus = fetch_xcpus(trialcs);
2413+
23952414
if (is_partition_valid(cp) &&
2396-
cpumask_intersects(trialcs->effective_xcpus, cp->effective_xcpus)) {
2415+
cpumask_intersects(xcpus, cp->effective_xcpus)) {
23972416
rcu_read_unlock();
23982417
update_parent_effective_cpumask(cp, partcmd_invalidate, NULL, &tmp);
23992418
rcu_read_lock();
24002419
}
2420+
}
24012421
rcu_read_unlock();
24022422
retval = 0;
24032423
}
24042424

24052425
if (retval < 0)
24062426
goto out_free;
24072427

2408-
if (is_partition_valid(cs)) {
2428+
if (is_partition_valid(cs) ||
2429+
(is_partition_invalid(cs) && !invalidate)) {
2430+
struct cpumask *xcpus = trialcs->effective_xcpus;
2431+
2432+
if (cpumask_empty(xcpus) && is_partition_invalid(cs))
2433+
xcpus = trialcs->cpus_allowed;
2434+
24092435
/*
24102436
* Call remote_cpus_update() to handle valid remote partition
24112437
*/
24122438
if (is_remote_partition(cs))
2413-
remote_cpus_update(cs, trialcs->effective_xcpus, &tmp);
2439+
remote_cpus_update(cs, xcpus, &tmp);
24142440
else if (invalidate)
24152441
update_parent_effective_cpumask(cs, partcmd_invalidate,
24162442
NULL, &tmp);
24172443
else
24182444
update_parent_effective_cpumask(cs, partcmd_update,
2419-
trialcs->effective_xcpus, &tmp);
2445+
xcpus, &tmp);
24202446
} else if (!cpumask_empty(cs->exclusive_cpus)) {
24212447
/*
24222448
* Use trialcs->effective_cpus as a temp cpumask
@@ -2493,7 +2519,7 @@ static int update_exclusive_cpumask(struct cpuset *cs, struct cpuset *trialcs,
24932519
if (retval)
24942520
return retval;
24952521

2496-
if (is_partition_valid(cs)) {
2522+
if (old_prs) {
24972523
if (cpumask_empty(trialcs->effective_xcpus)) {
24982524
invalidate = true;
24992525
cs->prs_err = PERR_INVCPUS;
@@ -2927,19 +2953,10 @@ static int update_prstate(struct cpuset *cs, int new_prs)
29272953
return 0;
29282954

29292955
/*
2930-
* For a previously invalid partition root with valid partition root
2931-
* parent, treat it as if it is a "member". Otherwise, reject it as
2932-
* remote partition cannot currently self-recover from an invalid
2933-
* state.
2956+
* Treat a previously invalid partition root as if it is a "member".
29342957
*/
2935-
if (new_prs && is_prs_invalid(old_prs)) {
2936-
if (is_partition_valid(parent)) {
2937-
old_prs = PRS_MEMBER;
2938-
} else {
2939-
cs->partition_root_state = -new_prs;
2940-
return 0;
2941-
}
2942-
}
2958+
if (new_prs && is_prs_invalid(old_prs))
2959+
old_prs = PRS_MEMBER;
29432960

29442961
if (alloc_cpumasks(NULL, &tmpmask))
29452962
return -ENOMEM;

tools/testing/selftests/cgroup/test_cpuset_prs.sh

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ test_isolated()
220220
# +- B1
221221
#
222222
# P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
223-
# C<l> = add cpu-list
223+
# C<l> = add cpu-list to cpuset.cpus
224+
# X<l> = add cpu-list to cpuset.cpus.exclusive
224225
# S<p> = use prefix in subtree_control
225226
# T = put a task into cgroup
226227
# O<c>=<v> = Write <v> to CPU online file of <c>
@@ -318,16 +319,19 @@ TEST_MATRIX=(
318319
" C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3,A2:1-3,A3:2 A1:P0,A3:P-2"
319320
320321
# cpus.exclusive.effective clearing test
321-
" C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3,A2:1-3,A3:2,XA1:"
322+
" C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3,A2:1-3,A3:2,XA1:"
322323
323-
# Invalid to valid remote partition indirect transition test via member
324-
" C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3,A2:1-3,XA2: A2:P-2"
324+
# Invalid to valid remote partition transition test
325+
" C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3,A2:1-3,XA2: A2:P-2"
325326
" C0-3:S+ C1-3:X3:P2
326-
. . X2-3 P0:P2 . . 0 A1:0-2,A2:3,XA2:3 A2:P2 3"
327+
. . X2-3 P2 . . 0 A1:0-2,A2:3,XA2:3 A2:P2 3"
327328
328329
# Invalid to valid local partition direct transition tests
329-
" C1-3:S+:P2 C2-3:X1:P2 . . . . . . 0 A1:1-3,XA1:1-3,A2:2-3:XA2: A1:P2,A2:P-2 1-3"
330-
" C1-3:S+:P2 C2-3:X1:P2 . . . X3:P2 . . 0 A1:1-2,XA1:1-3,A2:3:XA2:3 A1:P2,A2:P2 1-3"
330+
" C1-3:S+:P2 C2-3:X1:P2 . . . . . . 0 A1:1-3,XA1:1-3,A2:2-3:XA2: A1:P2,A2:P-2 1-3"
331+
" C1-3:S+:P2 C2-3:X1:P2 . . . X3:P2 . . 0 A1:1-2,XA1:1-3,A2:3:XA2:3 A1:P2,A2:P2 1-3"
332+
" C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4,B1:4-6 A1:P-2,B1:P0"
333+
" C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3,B1:4-6 A1:P2,B1:P0 0-3"
334+
" C0-3:P2 . . C3-5:C4-5 . . . . 0 A1:0-3,B1:4-5 A1:P2,B1:P0 0-3"
331335
332336
# Local partition invalidation tests
333337
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
@@ -336,6 +340,9 @@ TEST_MATRIX=(
336340
. . X4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
337341
" C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
338342
. . C4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
343+
# Local partition CPU change tests
344+
" C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2,A2:3-5 A1:P2,A2:P1 0-2"
345+
" C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3,A2:4-5 A1:P2,A2:P1 1-3"
339346
340347
# cpus_allowed/exclusive_cpus update tests
341348
" C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \

0 commit comments

Comments
 (0)