diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 7f64bb1a7befa..f53ca022549c7 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 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, if ((cp != cs) && old_prs) { switch (parent->partition_root_state) { case PRS_ROOT: + case PRS_ISOLATED: update_parent = true; break; @@ -1528,7 +1545,8 @@ static void update_cpumasks_hier(struct cpuset *cs, struct tmpmasks *tmp, * 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 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, 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;