*
  *   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)
 {
  */
 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;
 }
 
 /*
 
        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;
                }
        }
 
        /*
         * 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) &&
        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;
 }
 
                if ((cp != cs) && old_prs) {
                        switch (parent->partition_root_state) {
                        case PRS_ROOT:
+                       case PRS_ISOLATED:
                                update_parent = true;
                                break;
 
                                 * invalid, child partition roots become
                                 * invalid too.
                                 */
-                               new_prs = PRS_INVALID_ROOT;
+                               if (is_partition_valid(cp))
+                                       new_prs = -cp->partition_root_state;
                                break;
                        }
                }
 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;
 
         * 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;
                        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
 
                /* 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);
        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);
        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;
 }
                val = PRS_ROOT;
        else if (!strcmp(buf, "member"))
                val = PRS_MEMBER;
+       else if (!strcmp(buf, "isolated"))
+               val = PRS_ISOLATED;
        else
                return -EINVAL;