diff options
-rw-r--r-- | kernel/cgroup/cpuset.c | 42 |
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; } |