[PATCH v14 12/12] cpuset: Use descriptive text when reading/writing cpuset.sched.partition

From: Waiman Long
Date: Fri Oct 19 2018 - 11:46:41 EST


Currently, cpuset.sched.partition returns the values, 0, 1 or -1 on
read. A person who is not familiar with the partition code may not
understand what they mean.

In order to make cpuset.sched.partition more user-friendly, it will
now display the following descriptive text on read:

"normal" - A normal cpuset, not a partition root
"partition" - A partition root
"partition invalid" - An invalid partition root

The cpuset.sched.partition file will now also accept "normal" and
"partition" besides 1 and 0 as valid input values. The "partition
invalid" value is internal only and cannot be written to the file.

Suggested-by: Tejun Heo <tj@xxxxxxxxxx>
Signed-off-by: Waiman Long <longman@xxxxxxxxxx>
---
Documentation/admin-guide/cgroup-v2.rst | 50 +++++++++++++++-------------
kernel/cgroup/cpuset.c | 58 +++++++++++++++++++++++++++++----
2 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index 178cda4..072f09d 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -1688,18 +1688,23 @@ Cpuset Interface Files

cpuset.sched.partition
A read-write single value file which exists on non-root
- cpuset-enabled cgroups. It accepts either "0" (off) or "1"
- (on) when written to. This flag is set and owned by the
+ cpuset-enabled cgroups. This file is set and owned by the
parent cgroup.

- If set, it indicates that the current cgroup is the root of a
- new partition or scheduling domain that comprises itself and
+ It accepts only the following input values when written to.
+
+ "normal" or "0" - normal cpuset, not a partition root
+ "partition" or "1" - partition root
+
+ When set to a partition root, the current cgroup is the root of
+ a new partition or scheduling domain that comprises itself and
all its descendants except those that are separate partition
roots themselves and their descendants. The root cgroup is
always a partition root.

- There are constraints on where this flag can be set. It can
- only be set in a cgroup if all the following conditions are true.
+ There are constraints on where a partition root can be set.
+ It can only be set in a cgroup if all the following conditions
+ are true.

1) The "cpuset.cpus" is not empty and the list of CPUs are
exclusive, i.e. they are not shared by any of its siblings.
@@ -1710,9 +1715,10 @@ Cpuset Interface Files
eliminating corner cases that have to be handled if such a
condition is allowed.

- Setting this flag will take the CPUs away from the effective
- CPUs of the parent cgroup. Once it is set, this flag cannot
- be cleared if there are any child cgroups with cpuset enabled.
+ Setting it to partition root will take the CPUs away from the
+ effective CPUs of the parent cgroup. Once it is set, this
+ file cannot be reverted back to "normal" if there are any child
+ cgroups with cpuset enabled.

A parent partition cannot distribute all its CPUs to its
child partitions. There must be at least one cpu left in the
@@ -1729,28 +1735,28 @@ Cpuset Interface Files
root to change. On read, the "cpuset.sched.partition" file
can show the following values.

- "0" Not a partition root
- "1" Partition root
- "-1" Erroneous partition root
+ "normal" - Normal cpuset, not a partition root
+ "partition" - Partition root
+ "partition invalid" - Invalid partition root

It is a partition root if the first 2 partition root conditions
above are true and at least one CPU from "cpuset.cpus" is
granted by the parent cgroup.

- A partition root can become an erroneous partition root if none
- of CPUs requested in "cpuset.cpus" can be granted by the parent
- cgroup or the parent cgroup is no longer a partition root.
- In this case, it is not a real partition even though the
+ A partition root can become an invalid partition root if none
+ of the CPUs requested in "cpuset.cpus" can be granted by the
+ parent cgroup or the parent cgroup is no longer a partition
+ root. In this case, it is not a real partition even though the
restriction of the first partition root condition above will
still apply. All the tasks in the cgroup will be migrated to
the nearest ancestor partition.

- An erroneous partition root can be transitioned back to a real
- partition root if at least one of the requested CPUs can now be
- granted by its parent. In this case, the tasks will be migrated
- back to the newly created partition. Clearing the partition
- flag of an erroneous partition root is always allowed even if
- child cpusets are present.
+ An invalid partition root can be transitioned back to a real
+ partition root if at least one of the requested CPUs can now
+ be granted by its parent. In this case, the tasks will be
+ migrated back to the newly created partition. Converting an
+ invalid partition root back to "normal" is always allowed even
+ if child cpusets are present.


Device controller
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 34d47e4..d356205 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -2274,9 +2274,6 @@ static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft,
case FILE_SCHED_RELAX_DOMAIN_LEVEL:
retval = update_relax_domain_level(cs, val);
break;
- case FILE_PARTITION_ROOT:
- retval = update_prstate(cs, val);
- break;
default:
retval = -EINVAL;
break;
@@ -2430,8 +2427,6 @@ static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft)
switch (type) {
case FILE_SCHED_RELAX_DOMAIN_LEVEL:
return cs->relax_domain_level;
- case FILE_PARTITION_ROOT:
- return cs->partition_root_state;
default:
BUG();
}
@@ -2440,6 +2435,55 @@ static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft)
return 0;
}

+static int sched_partition_show(struct seq_file *seq, void *v)
+{
+ struct cpuset *cs = css_cs(seq_css(seq));
+
+ switch (cs->partition_root_state) {
+ case PRS_ENABLED:
+ seq_puts(seq, "partition\n");
+ break;
+ case PRS_DISABLED:
+ seq_puts(seq, "normal\n");
+ break;
+ case PRS_ERROR:
+ seq_puts(seq, "partition invalid\n");
+ break;
+ }
+ return 0;
+}
+
+static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf,
+ size_t nbytes, loff_t off)
+{
+ struct cpuset *cs = css_cs(of_css(of));
+ int val;
+ int retval = -ENODEV;
+
+ buf = strstrip(buf);
+
+ /*
+ * Convert "partition"/"1" to 1, and convert "normal"/"0" to 0.
+ */
+ if (!strcmp(buf, "partition") || !strcmp(buf, "1"))
+ val = PRS_ENABLED;
+ else if (!strcmp(buf, "normal") || !strcmp(buf, "0"))
+ val = PRS_DISABLED;
+ else
+ return -EINVAL;
+
+ css_get(&cs->css);
+ mutex_lock(&cpuset_mutex);
+ if (!is_cpuset_online(cs))
+ goto out_unlock;
+
+ retval = update_prstate(cs, val);
+out_unlock:
+ mutex_unlock(&cpuset_mutex);
+ css_put(&cs->css);
+ return retval ?: nbytes;
+}
+
/*
* for the common functions, 'private' gives the type of file
*/
@@ -2583,8 +2627,8 @@ static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft)

{
.name = "sched.partition",
- .read_s64 = cpuset_read_s64,
- .write_s64 = cpuset_write_s64,
+ .seq_show = sched_partition_show,
+ .write = sched_partition_write,
.private = FILE_PARTITION_ROOT,
.flags = CFTYPE_NOT_ON_ROOT,
},
--
1.8.3.1


--------------275CDF22CC2523499699C9E0--