summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/cgroup/cpuset.c74
1 files changed, 63 insertions, 11 deletions
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 7f64bb1a7bef..f53ca022549c 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -178,11 +178,15 @@ struct cpuset {
*
* 0 - member (not a partition root)
* 1 - partition root
+ * 2 - partition root without load balancing (isolated)
* -1 - invalid partition root
+ * -2 - invalid isolated partition root
*/
#define PRS_MEMBER 0
#define PRS_ROOT 1
+#define PRS_ISOLATED 2
#define PRS_INVALID_ROOT -1
+#define PRS_INVALID_ISOLATED -2
static inline bool is_prs_invalid(int prs_state)
{
@@ -282,7 +286,8 @@ static inline int is_partition_invalid(const struct cpuset *cs)
*/
static inline void make_partition_invalid(struct cpuset *cs)
{
- cs->partition_root_state = PRS_INVALID_ROOT;
+ if (is_partition_valid(cs))
+ cs->partition_root_state = -cs->partition_root_state;
}
/*
@@ -1380,17 +1385,19 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
if (cmd == partcmd_update) {
/*
- * Check for possible transition between PRS_ROOT
- * and PRS_INVALID_ROOT.
+ * Check for possible transition between valid and invalid
+ * partition root.
*/
switch (cs->partition_root_state) {
case PRS_ROOT:
+ case PRS_ISOLATED:
if (part_error)
- new_prs = PRS_INVALID_ROOT;
+ new_prs = -old_prs;
break;
case PRS_INVALID_ROOT:
+ case PRS_INVALID_ISOLATED:
if (!part_error)
- new_prs = PRS_ROOT;
+ new_prs = -old_prs;
break;
}
}
@@ -1400,7 +1407,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
/*
* Transitioning between invalid to valid or vice versa may require
- * changing CS_CPU_EXCLUSIVE.
+ * changing CS_CPU_EXCLUSIVE and CS_SCHED_LOAD_BALANCE.
*/
if (old_prs != new_prs) {
if (is_prs_invalid(old_prs) && !is_cpu_exclusive(cs) &&
@@ -1443,8 +1450,17 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
if (adding || deleting)
update_tasks_cpumask(parent);
+ /*
+ * Set or clear CS_SCHED_LOAD_BALANCE when partcmd_update, if necessary.
+ * rebuild_sched_domains_locked() may be called.
+ */
+ if (old_prs != new_prs) {
+ if (old_prs == PRS_ISOLATED)
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 1);
+ else if (new_prs == PRS_ISOLATED)
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
+ }
notify_partition_change(cs, old_prs);
-
return 0;
}
@@ -1519,6 +1535,7 @@ update_parent_subparts:
if ((cp != cs) && old_prs) {
switch (parent->partition_root_state) {
case PRS_ROOT:
+ case PRS_ISOLATED:
update_parent = true;
break;
@@ -1528,7 +1545,8 @@ update_parent_subparts:
* invalid, child partition roots become
* invalid too.
*/
- new_prs = PRS_INVALID_ROOT;
+ if (is_partition_valid(cp))
+ new_prs = -cp->partition_root_state;
break;
}
}
@@ -2110,6 +2128,7 @@ out:
static int update_prstate(struct cpuset *cs, int new_prs)
{
int err = 0, old_prs = cs->partition_root_state;
+ bool sched_domain_rebuilt = false;
struct cpuset *parent = parent_cs(cs);
struct tmpmasks tmpmask;
@@ -2120,8 +2139,10 @@ static int update_prstate(struct cpuset *cs, int new_prs)
* For a previously invalid partition root, leave it at being
* invalid if new_prs is not "member".
*/
- if (new_prs && is_prs_invalid(old_prs))
+ if (new_prs && is_prs_invalid(old_prs)) {
+ cs->partition_root_state = -new_prs;
return 0;
+ }
if (alloc_cpumasks(NULL, &tmpmask))
return -ENOMEM;
@@ -2147,6 +2168,22 @@ static int update_prstate(struct cpuset *cs, int new_prs)
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
goto out;
}
+
+ if (new_prs == PRS_ISOLATED) {
+ /*
+ * Disable the load balance flag should not return an
+ * error unless the system is running out of memory.
+ */
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
+ sched_domain_rebuilt = true;
+ }
+ } else if (old_prs && new_prs) {
+ /*
+ * A change in load balance state only, no change in cpumasks.
+ */
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, (new_prs != PRS_ISOLATED));
+ sched_domain_rebuilt = true;
+ goto out; /* Sched domain is rebuilt in update_flag() */
} else {
/*
* Switching back to member is always allowed even if it
@@ -2168,6 +2205,12 @@ static int update_prstate(struct cpuset *cs, int new_prs)
/* Turning off CS_CPU_EXCLUSIVE will not return error */
update_flag(CS_CPU_EXCLUSIVE, cs, 0);
+
+ if (!is_sched_load_balance(cs)) {
+ /* Make sure load balance is on */
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 1);
+ sched_domain_rebuilt = true;
+ }
}
update_tasks_cpumask(parent);
@@ -2175,13 +2218,14 @@ static int update_prstate(struct cpuset *cs, int new_prs)
if (parent->child_ecpus_count)
update_sibling_cpumasks(parent, cs, &tmpmask);
- rebuild_sched_domains_locked();
+ if (!sched_domain_rebuilt)
+ rebuild_sched_domains_locked();
out:
/*
* Make partition invalid if an error happen
*/
if (err)
- new_prs = PRS_INVALID_ROOT;
+ new_prs = -new_prs;
spin_lock_irq(&callback_lock);
cs->partition_root_state = new_prs;
spin_unlock_irq(&callback_lock);
@@ -2691,12 +2735,18 @@ static int sched_partition_show(struct seq_file *seq, void *v)
case PRS_ROOT:
seq_puts(seq, "root\n");
break;
+ case PRS_ISOLATED:
+ seq_puts(seq, "isolated\n");
+ break;
case PRS_MEMBER:
seq_puts(seq, "member\n");
break;
case PRS_INVALID_ROOT:
seq_puts(seq, "root invalid\n");
break;
+ case PRS_INVALID_ISOLATED:
+ seq_puts(seq, "isolated invalid\n");
+ break;
}
return 0;
}
@@ -2717,6 +2767,8 @@ static ssize_t sched_partition_write(struct kernfs_open_file *of, char *buf,
val = PRS_ROOT;
else if (!strcmp(buf, "member"))
val = PRS_MEMBER;
+ else if (!strcmp(buf, "isolated"))
+ val = PRS_ISOLATED;
else
return -EINVAL;