summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathieu Poirier <mathieu.poirier@linaro.org>2018-01-23 13:34:27 -0700
committerMathieu Poirier <mathieu.poirier@linaro.org>2018-02-13 11:25:34 -0700
commit1277c0eb52ca9d0cad388f477cc4f5226a376b78 (patch)
treef9381159397bbd24a890a60bd3196cdac33beeec
parentbbfce0ae54da3d6ed416e26786b6d43dd81487eb (diff)
cgroup: Constrain the addition of CPUs to a new CPUset
Care must be taken when CPUs are added to a new CPUset. If an ancestor of that set has its sched_load_balance flag switch off then the CPUs in the new CPUset will be added to a new root domain. If the ancestor also had DL tasks those will end up covering more than one root domain, breaking at the same time the DL integrity model. This patch prevents adding CPUs to a new CPUset if one of its ancestor had its sched_load_balance flag off and had DL tasks assigned to it. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
-rw-r--r--kernel/cgroup/cpuset.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 4f5e8bac5337..4c1b71608c23 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -481,6 +481,43 @@ static bool cpuset_has_dl_tasks(struct cpuset *cs)
* Assumes RCU read lock and cpuset_mutex are held.
*/
static int
+validate_change_cpus(struct cpuset *cur, struct cpuset *trial)
+{
+ int ret = 0;
+
+ /*
+ * CPUs are being added to a CPUset. If any parent of @trial has its
+ * sched_load_balance flag switched off this operation will create a
+ * new root domain spanning trial->cpus_allowed. At the same time
+ * if any parent of @trial has a DL task, that task will end up
+ * spanning more than one root domain and break the deadline integrity
+ * model.
+ */
+ if (cpumask_weight(cur->cpus_allowed) <
+ cpumask_weight(trial->cpus_allowed)) {
+ struct cpuset *parent;
+
+ parent = parent_cs(trial);
+ /* Go up until we reach the top_cpuset */
+ while (parent) {
+ if (cpuset_has_dl_tasks(parent) &&
+ !is_sched_load_balance(parent)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ parent = parent_cs(parent);
+ }
+ }
+
+out:
+ return ret;
+}
+
+/*
+ * Assumes RCU read lock and cpuset_mutex are held.
+ */
+static int
validate_change_load_balance(struct cpuset *cur, struct cpuset *trial)
{
bool populated = false, dl_tasks = false;
@@ -553,8 +590,11 @@ validate_dl_change(struct cpuset *cur, struct cpuset *trial)
/* Check if the sched_load_balance flag has been changed */
ret = validate_change_load_balance(cur, trial);
if (ret)
- return ret;
+ goto out;
+ ret = validate_change_cpus(cur, trial);
+
+out:
return ret;
}