Skip to content

Commit 737bb14

Browse files
Waiman-Longhtejun
authored andcommitted
cgroup/cpuset: Make cpuset.cpus.exclusive independent of cpuset.cpus
The "cpuset.cpus.exclusive.effective" value is currently limited to a subset of its "cpuset.cpus". This makes the exclusive CPUs distribution hierarchy subsumed within the larger "cpuset.cpus" hierarchy. We have to decide on what CPUs are used locally and what CPUs can be passed down as exclusive CPUs down the hierarchy and combine them into "cpuset.cpus". The advantage of the current scheme is to have only one hierarchy to worry about. However, it make it harder to use as all the "cpuset.cpus" values have to be properly set along the way down to the designated remote partition root. It also makes it more cumbersome to find out what CPUs can be used locally. Make creation of remote partition simpler by breaking the dependency of "cpuset.cpus.exclusive" on "cpuset.cpus" and make them independent entities. Now we have two separate hierarchies - one for setting "cpuset.cpus.effective" and the other one for setting "cpuset.cpus.exclusive.effective". We may not need to set "cpuset.cpus" when we activate a partition root anymore. Also update Documentation/admin-guide/cgroup-v2.rst and cpuset.c comment to document this change. Suggested-by: Petr Malat <[email protected]> Signed-off-by: Waiman Long <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent fe8cd27 commit 737bb14

File tree

2 files changed

+49
-22
lines changed

2 files changed

+49
-22
lines changed

Documentation/admin-guide/cgroup-v2.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2380,8 +2380,8 @@ Cpuset Interface Files
23802380
cpuset-enabled cgroups.
23812381

23822382
This file shows the effective set of exclusive CPUs that
2383-
can be used to create a partition root. The content of this
2384-
file will always be a subset of "cpuset.cpus" and its parent's
2383+
can be used to create a partition root. The content
2384+
of this file will always be a subset of its parent's
23852385
"cpuset.cpus.exclusive.effective" if its parent is not the root
23862386
cgroup. It will also be a subset of "cpuset.cpus.exclusive"
23872387
if it is set. If "cpuset.cpus.exclusive" is not set, it is

kernel/cgroup/cpuset.c

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static const char * const perr_strings[] = {
8787
[PERR_NOTEXCL] = "Cpu list in cpuset.cpus not exclusive",
8888
[PERR_NOCPUS] = "Parent unable to distribute cpu downstream",
8989
[PERR_HOTPLUG] = "No cpu available due to hotplug",
90-
[PERR_CPUSEMPTY] = "cpuset.cpus is empty",
90+
[PERR_CPUSEMPTY] = "cpuset.cpus and cpuset.cpus.exclusive are empty",
9191
[PERR_HKEEPING] = "partition config conflicts with housekeeping setup",
9292
};
9393

@@ -127,19 +127,28 @@ struct cpuset {
127127
/*
128128
* Exclusive CPUs dedicated to current cgroup (default hierarchy only)
129129
*
130-
* This exclusive CPUs must be a subset of cpus_allowed. A parent
131-
* cgroup can only grant exclusive CPUs to one of its children.
130+
* The effective_cpus of a valid partition root comes solely from its
131+
* effective_xcpus and some of the effective_xcpus may be distributed
132+
* to sub-partitions below & hence excluded from its effective_cpus.
133+
* For a valid partition root, its effective_cpus have no relationship
134+
* with cpus_allowed unless its exclusive_cpus isn't set.
132135
*
133-
* When the cgroup becomes a valid partition root, effective_xcpus
134-
* defaults to cpus_allowed if not set. The effective_cpus of a valid
135-
* partition root comes solely from its effective_xcpus and some of the
136-
* effective_xcpus may be distributed to sub-partitions below & hence
137-
* excluded from its effective_cpus.
136+
* This value will only be set if either exclusive_cpus is set or
137+
* when this cpuset becomes a local partition root.
138138
*/
139139
cpumask_var_t effective_xcpus;
140140

141141
/*
142142
* Exclusive CPUs as requested by the user (default hierarchy only)
143+
*
144+
* Its value is independent of cpus_allowed and designates the set of
145+
* CPUs that can be granted to the current cpuset or its children when
146+
* it becomes a valid partition root. The effective set of exclusive
147+
* CPUs granted (effective_xcpus) depends on whether those exclusive
148+
* CPUs are passed down by its ancestors and not yet taken up by
149+
* another sibling partition root along the way.
150+
*
151+
* If its value isn't set, it defaults to cpus_allowed.
143152
*/
144153
cpumask_var_t exclusive_cpus;
145154

@@ -230,6 +239,17 @@ static struct list_head remote_children;
230239
* 2 - partition root without load balancing (isolated)
231240
* -1 - invalid partition root
232241
* -2 - invalid isolated partition root
242+
*
243+
* There are 2 types of partitions - local or remote. Local partitions are
244+
* those whose parents are partition root themselves. Setting of
245+
* cpuset.cpus.exclusive are optional in setting up local partitions.
246+
* Remote partitions are those whose parents are not partition roots. Passing
247+
* down exclusive CPUs by setting cpuset.cpus.exclusive along its ancestor
248+
* nodes are mandatory in creating a remote partition.
249+
*
250+
* For simplicity, a local partition can be created under a local or remote
251+
* partition but a remote partition cannot have any partition root in its
252+
* ancestor chain except the cgroup root.
233253
*/
234254
#define PRS_MEMBER 0
235255
#define PRS_ROOT 1
@@ -709,6 +729,19 @@ static inline void free_cpuset(struct cpuset *cs)
709729
kfree(cs);
710730
}
711731

732+
/* Return user specified exclusive CPUs */
733+
static inline struct cpumask *user_xcpus(struct cpuset *cs)
734+
{
735+
return cpumask_empty(cs->exclusive_cpus) ? cs->cpus_allowed
736+
: cs->exclusive_cpus;
737+
}
738+
739+
static inline bool xcpus_empty(struct cpuset *cs)
740+
{
741+
return cpumask_empty(cs->cpus_allowed) &&
742+
cpumask_empty(cs->exclusive_cpus);
743+
}
744+
712745
static inline struct cpumask *fetch_xcpus(struct cpuset *cs)
713746
{
714747
return !cpumask_empty(cs->exclusive_cpus) ? cs->exclusive_cpus :
@@ -1593,7 +1626,7 @@ EXPORT_SYMBOL_GPL(cpuset_cpu_is_isolated);
15931626
* Return: true if xcpus is not empty, false otherwise.
15941627
*
15951628
* Starting with exclusive_cpus (cpus_allowed if exclusive_cpus is not set),
1596-
* it must be a subset of cpus_allowed and parent's effective_xcpus.
1629+
* it must be a subset of parent's effective_xcpus.
15971630
*/
15981631
static bool compute_effective_exclusive_cpumask(struct cpuset *cs,
15991632
struct cpumask *xcpus)
@@ -1603,12 +1636,7 @@ static bool compute_effective_exclusive_cpumask(struct cpuset *cs,
16031636
if (!xcpus)
16041637
xcpus = cs->effective_xcpus;
16051638

1606-
if (!cpumask_empty(cs->exclusive_cpus))
1607-
cpumask_and(xcpus, cs->exclusive_cpus, cs->cpus_allowed);
1608-
else
1609-
cpumask_copy(xcpus, cs->cpus_allowed);
1610-
1611-
return cpumask_and(xcpus, xcpus, parent->effective_xcpus);
1639+
return cpumask_and(xcpus, user_xcpus(cs), parent->effective_xcpus);
16121640
}
16131641

16141642
static inline bool is_remote_partition(struct cpuset *cs)
@@ -1887,8 +1915,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
18871915
*/
18881916
adding = deleting = false;
18891917
old_prs = new_prs = cs->partition_root_state;
1890-
xcpus = !cpumask_empty(cs->exclusive_cpus)
1891-
? cs->effective_xcpus : cs->cpus_allowed;
1918+
xcpus = user_xcpus(cs);
18921919

18931920
if (cmd == partcmd_invalidate) {
18941921
if (is_prs_invalid(old_prs))
@@ -1916,7 +1943,7 @@ static int update_parent_effective_cpumask(struct cpuset *cs, int cmd,
19161943
return is_partition_invalid(parent)
19171944
? PERR_INVPARENT : PERR_NOTPART;
19181945
}
1919-
if (!newmask && cpumask_empty(cs->cpus_allowed))
1946+
if (!newmask && xcpus_empty(cs))
19201947
return PERR_CPUSEMPTY;
19211948

19221949
nocpu = tasks_nocpu_error(parent, cs, xcpus);
@@ -3130,9 +3157,9 @@ static int update_prstate(struct cpuset *cs, int new_prs)
31303157
? partcmd_enable : partcmd_enablei;
31313158

31323159
/*
3133-
* cpus_allowed cannot be empty.
3160+
* cpus_allowed and exclusive_cpus cannot be both empty.
31343161
*/
3135-
if (cpumask_empty(cs->cpus_allowed)) {
3162+
if (xcpus_empty(cs)) {
31363163
err = PERR_CPUSEMPTY;
31373164
goto out;
31383165
}

0 commit comments

Comments
 (0)