summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}