]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/cpuset.c
tracelevel module: Prioritize trace events
[linux-2.6.git] / kernel / cpuset.c
index d5738910c34cfbad58d4a90777a2c242ff01ea14..10131fdaff70c36dc9fb181ace777015296891e3 100644 (file)
@@ -14,6 +14,8 @@
  *  2003-10-22 Updates by Stephen Hemminger.
  *  2004 May-July Rework by Paul Jackson.
  *  2006 Rework by Paul Menage to use generic cgroups
+ *  2008 Rework of the scheduler domains and CPU hotplug handling
+ *       by Max Krasnyansky
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of the Linux
@@ -34,6 +36,7 @@
 #include <linux/list.h>
 #include <linux/mempolicy.h>
 #include <linux/mm.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/sort.h>
 
 #include <asm/uaccess.h>
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 #include <linux/mutex.h>
-#include <linux/kfifo.h>
 #include <linux/workqueue.h>
 #include <linux/cgroup.h>
 
+/*
+ * Workqueue for cpuset related tasks.
+ *
+ * Using kevent workqueue may cause deadlock when memory_migrate
+ * is set. So we create a separate workqueue thread for cpuset.
+ */
+static struct workqueue_struct *cpuset_wq;
+
 /*
  * Tracks how many cpusets are currently defined in system.
  * When there is only one cpuset (the root cpuset) we can
@@ -82,17 +92,11 @@ struct cpuset {
        struct cgroup_subsys_state css;
 
        unsigned long flags;            /* "unsigned long" so bitops work */
-       cpumask_t cpus_allowed;         /* CPUs allowed to tasks in cpuset */
+       cpumask_var_t cpus_allowed;     /* CPUs allowed to tasks in cpuset */
        nodemask_t mems_allowed;        /* Memory Nodes allowed to tasks */
 
        struct cpuset *parent;          /* my parent */
 
-       /*
-        * Copy of global cpuset_mems_generation as of the most
-        * recent time this cpuset changed its mems_allowed.
-        */
-       int mems_generation;
-
        struct fmeter fmeter;           /* memory_pressure filter */
 
        /* partition number for rebuild_sched_domains() */
@@ -101,7 +105,7 @@ struct cpuset {
        /* for custom sched domain */
        int relax_domain_level;
 
-       /* used for walking a cpuset heirarchy */
+       /* used for walking a cpuset hierarchy */
        struct list_head stack_list;
 };
 
@@ -118,10 +122,6 @@ static inline struct cpuset *task_cs(struct task_struct *task)
        return container_of(task_subsys_state(task, cpuset_subsys_id),
                            struct cpuset, css);
 }
-struct cpuset_hotplug_scanner {
-       struct cgroup_scanner scan;
-       struct cgroup *to;
-};
 
 /* bits in struct cpuset flags field */
 typedef enum {
@@ -170,31 +170,8 @@ static inline int is_spread_slab(const struct cpuset *cs)
        return test_bit(CS_SPREAD_SLAB, &cs->flags);
 }
 
-/*
- * Increment this integer everytime any cpuset changes its
- * mems_allowed value.  Users of cpusets can track this generation
- * number, and avoid having to lock and reload mems_allowed unless
- * the cpuset they're using changes generation.
- *
- * A single, global generation is needed because cpuset_attach_task() could
- * reattach a task to a different cpuset, which must not have its
- * generation numbers aliased with those of that tasks previous cpuset.
- *
- * Generations are needed for mems_allowed because one task cannot
- * modify another's memory placement.  So we must enable every task,
- * on every visit to __alloc_pages(), to efficiently check whether
- * its current->cpuset->mems_allowed has changed, requiring an update
- * of its current->mems_allowed.
- *
- * Since writes to cpuset_mems_generation are guarded by the cgroup lock
- * there is no need to mark it atomic.
- */
-static int cpuset_mems_generation;
-
 static struct cpuset top_cpuset = {
        .flags = ((1 << CS_CPU_EXCLUSIVE) | (1 << CS_MEM_EXCLUSIVE)),
-       .cpus_allowed = CPU_MASK_ALL,
-       .mems_allowed = NODE_MASK_ALL,
 };
 
 /*
@@ -224,12 +201,9 @@ static struct cpuset top_cpuset = {
  * If a task is only holding callback_mutex, then it has read-only
  * access to cpusets.
  *
- * The task_struct fields mems_allowed and mems_generation may only
- * be accessed in the context of that task, so require no locks.
- *
- * The cpuset_common_file_write handler for operations that modify
- * the cpuset hierarchy holds cgroup_mutex across the entire operation,
- * single threading all such cpuset modifications across the system.
+ * Now, the task_struct fields mems_allowed and mempolicy may be changed
+ * by other task, we use alloc_lock in the task_struct fields to protect
+ * them.
  *
  * The cpuset_common_file_read() handlers only hold callback_mutex across
  * small pieces of code, such as when reading out possibly multi-word
@@ -241,21 +215,33 @@ static struct cpuset top_cpuset = {
 
 static DEFINE_MUTEX(callback_mutex);
 
-/* This is ugly, but preserves the userspace API for existing cpuset
+/*
+ * cpuset_buffer_lock protects both the cpuset_name and cpuset_nodelist
+ * buffers.  They are statically allocated to prevent using excess stack
+ * when calling cpuset_print_task_mems_allowed().
+ */
+#define CPUSET_NAME_LEN                (128)
+#define        CPUSET_NODELIST_LEN     (256)
+static char cpuset_name[CPUSET_NAME_LEN];
+static char cpuset_nodelist[CPUSET_NODELIST_LEN];
+static DEFINE_SPINLOCK(cpuset_buffer_lock);
+
+/*
+ * This is ugly, but preserves the userspace API for existing cpuset
  * users. If someone tries to mount the "cpuset" filesystem, we
- * silently switch it to mount "cgroup" instead */
-static int cpuset_get_sb(struct file_system_type *fs_type,
-                        int flags, const char *unused_dev_name,
-                        void *data, struct vfsmount *mnt)
+ * silently switch it to mount "cgroup" instead
+ */
+static struct dentry *cpuset_mount(struct file_system_type *fs_type,
+                        int flags, const char *unused_dev_name, void *data)
 {
        struct file_system_type *cgroup_fs = get_fs_type("cgroup");
-       int ret = -ENODEV;
+       struct dentry *ret = ERR_PTR(-ENODEV);
        if (cgroup_fs) {
                char mountopts[] =
                        "cpuset,noprefix,"
                        "release_agent=/sbin/cpuset_release_agent";
-               ret = cgroup_fs->get_sb(cgroup_fs, flags,
-                                          unused_dev_name, mountopts, mnt);
+               ret = cgroup_fs->mount(cgroup_fs, flags,
+                                          unused_dev_name, mountopts);
                put_filesystem(cgroup_fs);
        }
        return ret;
@@ -263,11 +249,11 @@ static int cpuset_get_sb(struct file_system_type *fs_type,
 
 static struct file_system_type cpuset_fs_type = {
        .name = "cpuset",
-       .get_sb = cpuset_get_sb,
+       .mount = cpuset_mount,
 };
 
 /*
- * Return in *pmask the portion of a cpusets's cpus_allowed that
+ * Return in pmask the portion of a cpusets's cpus_allowed that
  * are online.  If none are online, walk up the cpuset hierarchy
  * until we find one that does have some online cpus.  If we get
  * all the way to the top and still haven't found any online cpus,
@@ -280,15 +266,16 @@ static struct file_system_type cpuset_fs_type = {
  * Call with callback_mutex held.
  */
 
-static void guarantee_online_cpus(const struct cpuset *cs, cpumask_t *pmask)
+static void guarantee_online_cpus(const struct cpuset *cs,
+                                 struct cpumask *pmask)
 {
-       while (cs && !cpus_intersects(cs->cpus_allowed, cpu_online_map))
+       while (cs && !cpumask_intersects(cs->cpus_allowed, cpu_online_mask))
                cs = cs->parent;
        if (cs)
-               cpus_and(*pmask, cs->cpus_allowed, cpu_online_map);
+               cpumask_and(pmask, cs->cpus_allowed, cpu_online_mask);
        else
-               *pmask = cpu_online_map;
-       BUG_ON(!cpus_intersects(*pmask, cpu_online_map));
+               cpumask_copy(pmask, cpu_online_mask);
+       BUG_ON(!cpumask_intersects(pmask, cpu_online_mask));
 }
 
 /*
@@ -317,80 +304,22 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
        BUG_ON(!nodes_intersects(*pmask, node_states[N_HIGH_MEMORY]));
 }
 
-/**
- * cpuset_update_task_memory_state - update task memory placement
- *
- * If the current tasks cpusets mems_allowed changed behind our
- * backs, update current->mems_allowed, mems_generation and task NUMA
- * mempolicy to the new value.
- *
- * Task mempolicy is updated by rebinding it relative to the
- * current->cpuset if a task has its memory placement changed.
- * Do not call this routine if in_interrupt().
- *
- * Call without callback_mutex or task_lock() held.  May be
- * called with or without cgroup_mutex held.  Thanks in part to
- * 'the_top_cpuset_hack', the task's cpuset pointer will never
- * be NULL.  This routine also might acquire callback_mutex during
- * call.
- *
- * Reading current->cpuset->mems_generation doesn't need task_lock
- * to guard the current->cpuset derefence, because it is guarded
- * from concurrent freeing of current->cpuset using RCU.
- *
- * The rcu_dereference() is technically probably not needed,
- * as I don't actually mind if I see a new cpuset pointer but
- * an old value of mems_generation.  However this really only
- * matters on alpha systems using cpusets heavily.  If I dropped
- * that rcu_dereference(), it would save them a memory barrier.
- * For all other arch's, rcu_dereference is a no-op anyway, and for
- * alpha systems not using cpusets, another planned optimization,
- * avoiding the rcu critical section for tasks in the root cpuset
- * which is statically allocated, so can't vanish, will make this
- * irrelevant.  Better to use RCU as intended, than to engage in
- * some cute trick to save a memory barrier that is impossible to
- * test, for alpha systems using cpusets heavily, which might not
- * even exist.
- *
- * This routine is needed to update the per-task mems_allowed data,
- * within the tasks context, when it is trying to allocate memory
- * (in various mm/mempolicy.c routines) and notices that some other
- * task has been modifying its cpuset.
+/*
+ * update task's spread flag if cpuset's page/slab spread flag is set
+ *
+ * Called with callback_mutex/cgroup_mutex held
  */
-
-void cpuset_update_task_memory_state(void)
+static void cpuset_update_task_spread_flag(struct cpuset *cs,
+                                       struct task_struct *tsk)
 {
-       int my_cpusets_mem_gen;
-       struct task_struct *tsk = current;
-       struct cpuset *cs;
-
-       if (task_cs(tsk) == &top_cpuset) {
-               /* Don't need rcu for top_cpuset.  It's never freed. */
-               my_cpusets_mem_gen = top_cpuset.mems_generation;
-       } else {
-               rcu_read_lock();
-               my_cpusets_mem_gen = task_cs(current)->mems_generation;
-               rcu_read_unlock();
-       }
-
-       if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) {
-               mutex_lock(&callback_mutex);
-               task_lock(tsk);
-               cs = task_cs(tsk); /* Maybe changed when task not locked */
-               guarantee_online_mems(cs, &tsk->mems_allowed);
-               tsk->cpuset_mems_generation = cs->mems_generation;
-               if (is_spread_page(cs))
-                       tsk->flags |= PF_SPREAD_PAGE;
-               else
-                       tsk->flags &= ~PF_SPREAD_PAGE;
-               if (is_spread_slab(cs))
-                       tsk->flags |= PF_SPREAD_SLAB;
-               else
-                       tsk->flags &= ~PF_SPREAD_SLAB;
-               task_unlock(tsk);
-               mutex_unlock(&callback_mutex);
-               mpol_rebind_task(tsk, &tsk->mems_allowed);
-       }
+       if (is_spread_page(cs))
+               tsk->flags |= PF_SPREAD_PAGE;
+       else
+               tsk->flags &= ~PF_SPREAD_PAGE;
+       if (is_spread_slab(cs))
+               tsk->flags |= PF_SPREAD_SLAB;
+       else
+               tsk->flags &= ~PF_SPREAD_SLAB;
 }
 
 /*
@@ -403,12 +332,43 @@ void cpuset_update_task_memory_state(void)
 
 static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
 {
-       return  cpus_subset(p->cpus_allowed, q->cpus_allowed) &&
+       return  cpumask_subset(p->cpus_allowed, q->cpus_allowed) &&
                nodes_subset(p->mems_allowed, q->mems_allowed) &&
                is_cpu_exclusive(p) <= is_cpu_exclusive(q) &&
                is_mem_exclusive(p) <= is_mem_exclusive(q);
 }
 
+/**
+ * alloc_trial_cpuset - allocate a trial cpuset
+ * @cs: the cpuset that the trial cpuset duplicates
+ */
+static struct cpuset *alloc_trial_cpuset(const struct cpuset *cs)
+{
+       struct cpuset *trial;
+
+       trial = kmemdup(cs, sizeof(*cs), GFP_KERNEL);
+       if (!trial)
+               return NULL;
+
+       if (!alloc_cpumask_var(&trial->cpus_allowed, GFP_KERNEL)) {
+               kfree(trial);
+               return NULL;
+       }
+       cpumask_copy(trial->cpus_allowed, cs->cpus_allowed);
+
+       return trial;
+}
+
+/**
+ * free_trial_cpuset - free the trial cpuset
+ * @trial: the trial cpuset to be freed
+ */
+static void free_trial_cpuset(struct cpuset *trial)
+{
+       free_cpumask_var(trial->cpus_allowed);
+       kfree(trial);
+}
+
 /*
  * validate_change() - Used to validate that any proposed cpuset change
  *                    follows the structural rules for cpusets.
@@ -458,7 +418,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
                c = cgroup_cs(cont);
                if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
                    c != cur &&
-                   cpus_intersects(trial->cpus_allowed, c->cpus_allowed))
+                   cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
                        return -EINVAL;
                if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
                    c != cur &&
@@ -468,7 +428,7 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
 
        /* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
        if (cgroup_task_count(cur->css.cgroup)) {
-               if (cpus_empty(trial->cpus_allowed) ||
+               if (cpumask_empty(trial->cpus_allowed) ||
                    nodes_empty(trial->mems_allowed)) {
                        return -ENOSPC;
                }
@@ -477,44 +437,63 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
        return 0;
 }
 
+#ifdef CONFIG_SMP
 /*
- * Helper routine for rebuild_sched_domains().
+ * Helper routine for generate_sched_domains().
  * Do cpusets a, b have overlapping cpus_allowed masks?
  */
-
 static int cpusets_overlap(struct cpuset *a, struct cpuset *b)
 {
-       return cpus_intersects(a->cpus_allowed, b->cpus_allowed);
+       return cpumask_intersects(a->cpus_allowed, b->cpus_allowed);
 }
 
 static void
 update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c)
 {
-       if (!dattr)
-               return;
        if (dattr->relax_domain_level < c->relax_domain_level)
                dattr->relax_domain_level = c->relax_domain_level;
        return;
 }
 
+static void
+update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
+{
+       LIST_HEAD(q);
+
+       list_add(&c->stack_list, &q);
+       while (!list_empty(&q)) {
+               struct cpuset *cp;
+               struct cgroup *cont;
+               struct cpuset *child;
+
+               cp = list_first_entry(&q, struct cpuset, stack_list);
+               list_del(q.next);
+
+               if (cpumask_empty(cp->cpus_allowed))
+                       continue;
+
+               if (is_sched_load_balance(cp))
+                       update_domain_attr(dattr, cp);
+
+               list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
+                       child = cgroup_cs(cont);
+                       list_add_tail(&child->stack_list, &q);
+               }
+       }
+}
+
 /*
- * rebuild_sched_domains()
+ * generate_sched_domains()
  *
- * If the flag 'sched_load_balance' of any cpuset with non-empty
- * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
- * which has that flag enabled, or if any cpuset with a non-empty
- * 'cpus' is removed, then call this routine to rebuild the
- * scheduler's dynamic sched domains.
- *
- * This routine builds a partial partition of the systems CPUs
- * (the set of non-overlappping cpumask_t's in the array 'part'
- * below), and passes that partial partition to the kernel/sched.c
- * partition_sched_domains() routine, which will rebuild the
- * schedulers load balancing domains (sched domains) as specified
- * by that partial partition.  A 'partial partition' is a set of
- * non-overlapping subsets whose union is a subset of that set.
+ * This function builds a partial partition of the systems CPUs
+ * A 'partial partition' is a set of non-overlapping subsets whose
+ * union is a subset of that set.
+ * The output of this function needs to be passed to kernel/sched.c
+ * partition_sched_domains() routine, which will rebuild the scheduler's
+ * load balancing domains (sched domains) as specified by that partial
+ * partition.
  *
- * See "What is sched_load_balance" in Documentation/cpusets.txt
+ * See "What is sched_load_balance" in Documentation/cgroups/cpusets.txt
  * for a background explanation of this.
  *
  * Does not return errors, on the theory that the callers of this
@@ -522,16 +501,10 @@ update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c)
  * domains when operating in the severe memory shortage situations
  * that could cause allocation failures below.
  *
- * Call with cgroup_mutex held.  May take callback_mutex during
- * call due to the kfifo_alloc() and kmalloc() calls.  May nest
- * a call to the get_online_cpus()/put_online_cpus() pair.
- * Must not be called holding callback_mutex, because we must not
- * call get_online_cpus() while holding callback_mutex.  Elsewhere
- * the kernel nests callback_mutex inside get_online_cpus() calls.
- * So the reverse nesting would risk an ABBA deadlock.
+ * Must be called with cgroup_lock held.
  *
  * The three key local variables below are:
- *    q  - a kfifo queue of cpuset pointers, used to implement a
+ *    q  - a linked-list queue of cpuset pointers, used to implement a
  *        top-down scan of all cpusets.  This scan loads a pointer
  *        to each cpuset marked is_sched_load_balance into the
  *        array 'csa'.  For our purposes, rebuilding the schedulers
@@ -563,57 +536,70 @@ update_domain_attr(struct sched_domain_attr *dattr, struct cpuset *c)
  *     element of the partition (one sched domain) to be passed to
  *     partition_sched_domains().
  */
-
-void rebuild_sched_domains(void)
+static int generate_sched_domains(cpumask_var_t **domains,
+                       struct sched_domain_attr **attributes)
 {
-       struct kfifo *q;        /* queue of cpusets to be scanned */
+       LIST_HEAD(q);           /* queue of cpusets to be scanned */
        struct cpuset *cp;      /* scans q */
        struct cpuset **csa;    /* array of all cpuset ptrs */
        int csn;                /* how many cpuset ptrs in csa so far */
        int i, j, k;            /* indices for partition finding loops */
-       cpumask_t *doms;        /* resulting partition; i.e. sched domains */
+       cpumask_var_t *doms;    /* resulting partition; i.e. sched domains */
        struct sched_domain_attr *dattr;  /* attributes for custom domains */
-       int ndoms;              /* number of sched domains in result */
-       int nslot;              /* next empty doms[] cpumask_t slot */
+       int ndoms = 0;          /* number of sched domains in result */
+       int nslot;              /* next empty doms[] struct cpumask slot */
 
-       q = NULL;
-       csa = NULL;
        doms = NULL;
        dattr = NULL;
+       csa = NULL;
 
        /* Special case for the 99% of systems with one, full, sched domain */
        if (is_sched_load_balance(&top_cpuset)) {
                ndoms = 1;
-               doms = kmalloc(sizeof(cpumask_t), GFP_KERNEL);
+               doms = alloc_sched_domains(ndoms);
                if (!doms)
-                       goto rebuild;
+                       goto done;
+
                dattr = kmalloc(sizeof(struct sched_domain_attr), GFP_KERNEL);
                if (dattr) {
                        *dattr = SD_ATTR_INIT;
-                       update_domain_attr(dattr, &top_cpuset);
+                       update_domain_attr_tree(dattr, &top_cpuset);
                }
-               *doms = top_cpuset.cpus_allowed;
-               goto rebuild;
-       }
+               cpumask_copy(doms[0], top_cpuset.cpus_allowed);
 
-       q = kfifo_alloc(number_of_cpusets * sizeof(cp), GFP_KERNEL, NULL);
-       if (IS_ERR(q))
                goto done;
+       }
+
        csa = kmalloc(number_of_cpusets * sizeof(cp), GFP_KERNEL);
        if (!csa)
                goto done;
        csn = 0;
 
-       cp = &top_cpuset;
-       __kfifo_put(q, (void *)&cp, sizeof(cp));
-       while (__kfifo_get(q, (void *)&cp, sizeof(cp))) {
+       list_add(&top_cpuset.stack_list, &q);
+       while (!list_empty(&q)) {
                struct cgroup *cont;
                struct cpuset *child;   /* scans child cpusets of cp */
-               if (is_sched_load_balance(cp))
+
+               cp = list_first_entry(&q, struct cpuset, stack_list);
+               list_del(q.next);
+
+               if (cpumask_empty(cp->cpus_allowed))
+                       continue;
+
+               /*
+                * All child cpusets contain a subset of the parent's cpus, so
+                * just skip them, and then we call update_domain_attr_tree()
+                * to calc relax_domain_level of the corresponding sched
+                * domain.
+                */
+               if (is_sched_load_balance(cp)) {
                        csa[csn++] = cp;
+                       continue;
+               }
+
                list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
                        child = cgroup_cs(cont);
-                       __kfifo_put(q, (void *)&child, sizeof(cp));
+                       list_add_tail(&child->stack_list, &q);
                }
        }
 
@@ -644,93 +630,158 @@ restart:
                }
        }
 
-       /* Convert <csn, csa> to <ndoms, doms> */
-       doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL);
+       /*
+        * Now we know how many domains to create.
+        * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
+        */
+       doms = alloc_sched_domains(ndoms);
        if (!doms)
-               goto rebuild;
+               goto done;
+
+       /*
+        * The rest of the code, including the scheduler, can deal with
+        * dattr==NULL case. No need to abort if alloc fails.
+        */
        dattr = kmalloc(ndoms * sizeof(struct sched_domain_attr), GFP_KERNEL);
 
        for (nslot = 0, i = 0; i < csn; i++) {
                struct cpuset *a = csa[i];
+               struct cpumask *dp;
                int apn = a->pn;
 
-               if (apn >= 0) {
-                       cpumask_t *dp = doms + nslot;
-
-                       if (nslot == ndoms) {
-                               static int warnings = 10;
-                               if (warnings) {
-                                       printk(KERN_WARNING
-                                        "rebuild_sched_domains confused:"
-                                         " nslot %d, ndoms %d, csn %d, i %d,"
-                                         " apn %d\n",
-                                         nslot, ndoms, csn, i, apn);
-                                       warnings--;
-                               }
-                               continue;
+               if (apn < 0) {
+                       /* Skip completed partitions */
+                       continue;
+               }
+
+               dp = doms[nslot];
+
+               if (nslot == ndoms) {
+                       static int warnings = 10;
+                       if (warnings) {
+                               printk(KERN_WARNING
+                                "rebuild_sched_domains confused:"
+                                 " nslot %d, ndoms %d, csn %d, i %d,"
+                                 " apn %d\n",
+                                 nslot, ndoms, csn, i, apn);
+                               warnings--;
                        }
+                       continue;
+               }
 
-                       cpus_clear(*dp);
-                       if (dattr)
-                               *(dattr + nslot) = SD_ATTR_INIT;
-                       for (j = i; j < csn; j++) {
-                               struct cpuset *b = csa[j];
-
-                               if (apn == b->pn) {
-                                       cpus_or(*dp, *dp, b->cpus_allowed);
-                                       b->pn = -1;
-                                       if (dattr)
-                                               update_domain_attr(dattr
-                                                                  + nslot, b);
-                               }
+               cpumask_clear(dp);
+               if (dattr)
+                       *(dattr + nslot) = SD_ATTR_INIT;
+               for (j = i; j < csn; j++) {
+                       struct cpuset *b = csa[j];
+
+                       if (apn == b->pn) {
+                               cpumask_or(dp, dp, b->cpus_allowed);
+                               if (dattr)
+                                       update_domain_attr_tree(dattr + nslot, b);
+
+                               /* Done with this partition */
+                               b->pn = -1;
                        }
-                       nslot++;
                }
+               nslot++;
        }
        BUG_ON(nslot != ndoms);
 
-rebuild:
-       /* Have scheduler rebuild sched domains */
+done:
+       kfree(csa);
+
+       /*
+        * Fallback to the default domain if kmalloc() failed.
+        * See comments in partition_sched_domains().
+        */
+       if (doms == NULL)
+               ndoms = 1;
+
+       *domains    = doms;
+       *attributes = dattr;
+       return ndoms;
+}
+
+/*
+ * Rebuild scheduler domains.
+ *
+ * Call with neither cgroup_mutex held nor within get_online_cpus().
+ * Takes both cgroup_mutex and get_online_cpus().
+ *
+ * Cannot be directly called from cpuset code handling changes
+ * to the cpuset pseudo-filesystem, because it cannot be called
+ * from code that already holds cgroup_mutex.
+ */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+       struct sched_domain_attr *attr;
+       cpumask_var_t *doms;
+       int ndoms;
+
        get_online_cpus();
-       partition_sched_domains(ndoms, doms, dattr);
+
+       /* Generate domain masks and attrs */
+       cgroup_lock();
+       ndoms = generate_sched_domains(&doms, &attr);
+       cgroup_unlock();
+
+       /* Have scheduler rebuild the domains */
+       partition_sched_domains(ndoms, doms, attr);
+
        put_online_cpus();
+}
+#else /* !CONFIG_SMP */
+static void do_rebuild_sched_domains(struct work_struct *unused)
+{
+}
 
-done:
-       if (q && !IS_ERR(q))
-               kfifo_free(q);
-       kfree(csa);
-       /* Don't kfree(doms) -- partition_sched_domains() does that. */
-       /* Don't kfree(dattr) -- partition_sched_domains() does that. */
+static int generate_sched_domains(cpumask_var_t **domains,
+                       struct sched_domain_attr **attributes)
+{
+       *domains = NULL;
+       return 1;
 }
+#endif /* CONFIG_SMP */
 
-static inline int started_after_time(struct task_struct *t1,
-                                    struct timespec *time,
-                                    struct task_struct *t2)
+static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
+
+/*
+ * Rebuild scheduler domains, asynchronously via workqueue.
+ *
+ * If the flag 'sched_load_balance' of any cpuset with non-empty
+ * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
+ * which has that flag enabled, or if any cpuset with a non-empty
+ * 'cpus' is removed, then call this routine to rebuild the
+ * scheduler's dynamic sched domains.
+ *
+ * The rebuild_sched_domains() and partition_sched_domains()
+ * routines must nest cgroup_lock() inside get_online_cpus(),
+ * but such cpuset changes as these must nest that locking the
+ * other way, holding cgroup_lock() for much of the code.
+ *
+ * So in order to avoid an ABBA deadlock, the cpuset code handling
+ * these user changes delegates the actual sched domain rebuilding
+ * to a separate workqueue thread, which ends up processing the
+ * above do_rebuild_sched_domains() function.
+ */
+static void async_rebuild_sched_domains(void)
 {
-       int start_diff = timespec_compare(&t1->start_time, time);
-       if (start_diff > 0) {
-               return 1;
-       } else if (start_diff < 0) {
-               return 0;
-       } else {
-               /*
-                * Arbitrarily, if two processes started at the same
-                * time, we'll say that the lower pointer value
-                * started first. Note that t2 may have exited by now
-                * so this may not be a valid pointer any longer, but
-                * that's fine - it still serves to distinguish
-                * between two tasks started (effectively)
-                * simultaneously.
-                */
-               return t1 > t2;
-       }
+       queue_work(cpuset_wq, &rebuild_sched_domains_work);
 }
 
-static inline int started_after(void *p1, void *p2)
+/*
+ * Accomplishes the same scheduler domain rebuild as the above
+ * async_rebuild_sched_domains(), however it directly calls the
+ * rebuild routine synchronously rather than calling it via an
+ * asynchronous work thread.
+ *
+ * This can only be called from code that is not holding
+ * cgroup_mutex (not nested in a cgroup_lock() call.)
+ */
+void rebuild_sched_domains(void)
 {
-       struct task_struct *t1 = p1;
-       struct task_struct *t2 = p2;
-       return started_after_time(t1, &t2->start_time, t2);
+       do_rebuild_sched_domains(NULL);
 }
 
 /**
@@ -746,7 +797,7 @@ static inline int started_after(void *p1, void *p2)
 static int cpuset_test_cpumask(struct task_struct *tsk,
                               struct cgroup_scanner *scan)
 {
-       return !cpus_equal(tsk->cpus_allowed,
+       return !cpumask_equal(&tsk->cpus_allowed,
                        (cgroup_cs(scan->cg))->cpus_allowed);
 }
 
@@ -764,7 +815,31 @@ static int cpuset_test_cpumask(struct task_struct *tsk,
 static void cpuset_change_cpumask(struct task_struct *tsk,
                                  struct cgroup_scanner *scan)
 {
-       set_cpus_allowed_ptr(tsk, &((cgroup_cs(scan->cg))->cpus_allowed));
+       set_cpus_allowed_ptr(tsk, ((cgroup_cs(scan->cg))->cpus_allowed));
+}
+
+/**
+ * update_tasks_cpumask - Update the cpumasks of tasks in the cpuset.
+ * @cs: the cpuset in which each task's cpus_allowed mask needs to be changed
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ *
+ * Called with cgroup_mutex held
+ *
+ * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * calling callback functions for each.
+ *
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
+ */
+static void update_tasks_cpumask(struct cpuset *cs, struct ptr_heap *heap)
+{
+       struct cgroup_scanner scan;
+
+       scan.cg = cs->css.cgroup;
+       scan.test_task = cpuset_test_cpumask;
+       scan.process_task = cpuset_change_cpumask;
+       scan.heap = heap;
+       cgroup_scan_tasks(&scan);
 }
 
 /**
@@ -772,10 +847,9 @@ static void cpuset_change_cpumask(struct task_struct *tsk,
  * @cs: the cpuset to consider
  * @buf: buffer of cpu numbers written to this cpuset
  */
-static int update_cpumask(struct cpuset *cs, char *buf)
+static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
+                         const char *buf)
 {
-       struct cpuset trialcs;
-       struct cgroup_scanner scan;
        struct ptr_heap heap;
        int retval;
        int is_load_balanced;
@@ -784,56 +858,50 @@ static int update_cpumask(struct cpuset *cs, char *buf)
        if (cs == &top_cpuset)
                return -EACCES;
 
-       trialcs = *cs;
-
        /*
         * An empty cpus_allowed is ok only if the cpuset has no tasks.
         * Since cpulist_parse() fails on an empty mask, we special case
         * that parsing.  The validate_change() call ensures that cpusets
         * with tasks have cpus.
         */
-       buf = strstrip(buf);
        if (!*buf) {
-               cpus_clear(trialcs.cpus_allowed);
+               cpumask_clear(trialcs->cpus_allowed);
        } else {
-               retval = cpulist_parse(buf, trialcs.cpus_allowed);
+               retval = cpulist_parse(buf, trialcs->cpus_allowed);
                if (retval < 0)
                        return retval;
 
-               if (!cpus_subset(trialcs.cpus_allowed, cpu_online_map))
+               if (!cpumask_subset(trialcs->cpus_allowed, cpu_active_mask))
                        return -EINVAL;
        }
-       retval = validate_change(cs, &trialcs);
+       retval = validate_change(cs, trialcs);
        if (retval < 0)
                return retval;
 
        /* Nothing to do if the cpus didn't change */
-       if (cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed))
+       if (cpumask_equal(cs->cpus_allowed, trialcs->cpus_allowed))
                return 0;
 
-       retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, &started_after);
+       retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
        if (retval)
                return retval;
 
-       is_load_balanced = is_sched_load_balance(&trialcs);
+       is_load_balanced = is_sched_load_balance(trialcs);
 
        mutex_lock(&callback_mutex);
-       cs->cpus_allowed = trialcs.cpus_allowed;
+       cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
        mutex_unlock(&callback_mutex);
 
        /*
         * Scan tasks in the cpuset, and update the cpumasks of any
         * that need an update.
         */
-       scan.cg = cs->css.cgroup;
-       scan.test_task = cpuset_test_cpumask;
-       scan.process_task = cpuset_change_cpumask;
-       scan.heap = &heap;
-       cgroup_scan_tasks(&scan);
+       update_tasks_cpumask(cs, &heap);
+
        heap_free(&heap);
 
        if (is_load_balanced)
-               rebuild_sched_domains();
+               async_rebuild_sched_domains();
        return 0;
 }
 
@@ -851,21 +919,10 @@ static int update_cpumask(struct cpuset *cs, char *buf)
  *    call to guarantee_online_mems(), as we know no one is changing
  *    our task's cpuset.
  *
- *    Hold callback_mutex around the two modifications of our tasks
- *    mems_allowed to synchronize with cpuset_mems_allowed().
- *
  *    While the mm_struct we are migrating is typically from some
  *    other task, the task_struct mems_allowed that we are hacking
  *    is for our current task, which must allocate new pages for that
  *    migrating memory region.
- *
- *    We call cpuset_update_task_memory_state() before hacking
- *    our tasks mems_allowed, so that we are assured of being in
- *    sync with our tasks cpuset, and in particular, callbacks to
- *    cpuset_update_task_memory_state() from nested page allocations
- *    won't see any mismatch of our cpuset and task mems_generation
- *    values, so won't overwrite our hacked tasks mems_allowed
- *    nodemask.
  */
 
 static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
@@ -873,55 +930,182 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 {
        struct task_struct *tsk = current;
 
-       cpuset_update_task_memory_state();
-
-       mutex_lock(&callback_mutex);
        tsk->mems_allowed = *to;
-       mutex_unlock(&callback_mutex);
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
-       mutex_lock(&callback_mutex);
        guarantee_online_mems(task_cs(tsk),&tsk->mems_allowed);
-       mutex_unlock(&callback_mutex);
+}
+
+/*
+ * cpuset_change_task_nodemask - change task's mems_allowed and mempolicy
+ * @tsk: the task to change
+ * @newmems: new nodes that the task will be set
+ *
+ * In order to avoid seeing no nodes if the old and new nodes are disjoint,
+ * we structure updates as setting all new allowed nodes, then clearing newly
+ * disallowed ones.
+ */
+static void cpuset_change_task_nodemask(struct task_struct *tsk,
+                                       nodemask_t *newmems)
+{
+repeat:
+       /*
+        * Allow tasks that have access to memory reserves because they have
+        * been OOM killed to get memory anywhere.
+        */
+       if (unlikely(test_thread_flag(TIF_MEMDIE)))
+               return;
+       if (current->flags & PF_EXITING) /* Let dying task have memory */
+               return;
+
+       task_lock(tsk);
+       nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
+       mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
+
+
+       /*
+        * ensure checking ->mems_allowed_change_disable after setting all new
+        * allowed nodes.
+        *
+        * the read-side task can see an nodemask with new allowed nodes and
+        * old allowed nodes. and if it allocates page when cpuset clears newly
+        * disallowed ones continuous, it can see the new allowed bits.
+        *
+        * And if setting all new allowed nodes is after the checking, setting
+        * all new allowed nodes and clearing newly disallowed ones will be done
+        * continuous, and the read-side task may find no node to alloc page.
+        */
+       smp_mb();
+
+       /*
+        * Allocation of memory is very fast, we needn't sleep when waiting
+        * for the read-side.
+        */
+       while (ACCESS_ONCE(tsk->mems_allowed_change_disable)) {
+               task_unlock(tsk);
+               if (!task_curr(tsk))
+                       yield();
+               goto repeat;
+       }
+
+       /*
+        * ensure checking ->mems_allowed_change_disable before clearing all new
+        * disallowed nodes.
+        *
+        * if clearing newly disallowed bits before the checking, the read-side
+        * task may find no node to alloc page.
+        */
+       smp_mb();
+
+       mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP2);
+       tsk->mems_allowed = *newmems;
+       task_unlock(tsk);
+}
+
+/*
+ * Update task's mems_allowed and rebind its mempolicy and vmas' mempolicy
+ * of it to cpuset's new mems_allowed, and migrate pages to new nodes if
+ * memory_migrate flag is set. Called with cgroup_mutex held.
+ */
+static void cpuset_change_nodemask(struct task_struct *p,
+                                  struct cgroup_scanner *scan)
+{
+       struct mm_struct *mm;
+       struct cpuset *cs;
+       int migrate;
+       const nodemask_t *oldmem = scan->data;
+       static nodemask_t newmems;      /* protected by cgroup_mutex */
+
+       cs = cgroup_cs(scan->cg);
+       guarantee_online_mems(cs, &newmems);
+
+       cpuset_change_task_nodemask(p, &newmems);
+
+       mm = get_task_mm(p);
+       if (!mm)
+               return;
+
+       migrate = is_memory_migrate(cs);
+
+       mpol_rebind_mm(mm, &cs->mems_allowed);
+       if (migrate)
+               cpuset_migrate_mm(mm, oldmem, &cs->mems_allowed);
+       mmput(mm);
+}
+
+static void *cpuset_being_rebound;
+
+/**
+ * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset.
+ * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
+ * @oldmem: old mems_allowed of cpuset cs
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ *
+ * Called with cgroup_mutex held
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
+ */
+static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
+                                struct ptr_heap *heap)
+{
+       struct cgroup_scanner scan;
+
+       cpuset_being_rebound = cs;              /* causes mpol_dup() rebind */
+
+       scan.cg = cs->css.cgroup;
+       scan.test_task = NULL;
+       scan.process_task = cpuset_change_nodemask;
+       scan.heap = heap;
+       scan.data = (nodemask_t *)oldmem;
+
+       /*
+        * The mpol_rebind_mm() call takes mmap_sem, which we couldn't
+        * take while holding tasklist_lock.  Forks can happen - the
+        * mpol_dup() cpuset_being_rebound check will catch such forks,
+        * and rebind their vma mempolicies too.  Because we still hold
+        * the global cgroup_mutex, we know that no other rebind effort
+        * will be contending for the global variable cpuset_being_rebound.
+        * It's ok if we rebind the same mm twice; mpol_rebind_mm()
+        * is idempotent.  Also migrate pages in each mm to new nodes.
+        */
+       cgroup_scan_tasks(&scan);
+
+       /* We're done rebinding vmas to this cpuset's new mems_allowed. */
+       cpuset_being_rebound = NULL;
 }
 
 /*
  * Handle user request to change the 'mems' memory placement
  * of a cpuset.  Needs to validate the request, update the
- * cpusets mems_allowed and mems_generation, and for each
- * task in the cpuset, rebind any vma mempolicies and if
- * the cpuset is marked 'memory_migrate', migrate the tasks
- * pages to the new memory.
+ * cpusets mems_allowed, and for each task in the cpuset,
+ * update mems_allowed and rebind task's mempolicy and any vma
+ * mempolicies and if the cpuset is marked 'memory_migrate',
+ * migrate the tasks pages to the new memory.
  *
  * Call with cgroup_mutex held.  May take callback_mutex during call.
  * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
  * lock each such tasks mm->mmap_sem, scan its vma's and rebind
  * their mempolicies to the cpusets new mems_allowed.
  */
-
-static void *cpuset_being_rebound;
-
-static int update_nodemask(struct cpuset *cs, char *buf)
+static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
+                          const char *buf)
 {
-       struct cpuset trialcs;
-       nodemask_t oldmem;
-       struct task_struct *p;
-       struct mm_struct **mmarray;
-       int i, n, ntasks;
-       int migrate;
-       int fudge;
+       NODEMASK_ALLOC(nodemask_t, oldmem, GFP_KERNEL);
        int retval;
-       struct cgroup_iter it;
+       struct ptr_heap heap;
+
+       if (!oldmem)
+               return -ENOMEM;
 
        /*
         * top_cpuset.mems_allowed tracks node_stats[N_HIGH_MEMORY];
         * it's read-only
         */
-       if (cs == &top_cpuset)
-               return -EACCES;
-
-       trialcs = *cs;
+       if (cs == &top_cpuset) {
+               retval = -EACCES;
+               goto done;
+       }
 
        /*
         * An empty mems_allowed is ok iff there are no tasks in the cpuset.
@@ -929,125 +1113,104 @@ static int update_nodemask(struct cpuset *cs, char *buf)
         * that parsing.  The validate_change() call ensures that cpusets
         * with tasks have memory.
         */
-       buf = strstrip(buf);
        if (!*buf) {
-               nodes_clear(trialcs.mems_allowed);
+               nodes_clear(trialcs->mems_allowed);
        } else {
-               retval = nodelist_parse(buf, trialcs.mems_allowed);
+               retval = nodelist_parse(buf, trialcs->mems_allowed);
                if (retval < 0)
                        goto done;
 
-               if (!nodes_subset(trialcs.mems_allowed,
-                               node_states[N_HIGH_MEMORY]))
-                       return -EINVAL;
+               if (!nodes_subset(trialcs->mems_allowed,
+                               node_states[N_HIGH_MEMORY])) {
+                       retval =  -EINVAL;
+                       goto done;
+               }
        }
-       oldmem = cs->mems_allowed;
-       if (nodes_equal(oldmem, trialcs.mems_allowed)) {
+       *oldmem = cs->mems_allowed;
+       if (nodes_equal(*oldmem, trialcs->mems_allowed)) {
                retval = 0;             /* Too easy - nothing to do */
                goto done;
        }
-       retval = validate_change(cs, &trialcs);
+       retval = validate_change(cs, trialcs);
+       if (retval < 0)
+               goto done;
+
+       retval = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
        if (retval < 0)
                goto done;
 
        mutex_lock(&callback_mutex);
-       cs->mems_allowed = trialcs.mems_allowed;
-       cs->mems_generation = cpuset_mems_generation++;
+       cs->mems_allowed = trialcs->mems_allowed;
        mutex_unlock(&callback_mutex);
 
-       cpuset_being_rebound = cs;              /* causes mpol_dup() rebind */
-
-       fudge = 10;                             /* spare mmarray[] slots */
-       fudge += cpus_weight(cs->cpus_allowed); /* imagine one fork-bomb/cpu */
-       retval = -ENOMEM;
-
-       /*
-        * Allocate mmarray[] to hold mm reference for each task
-        * in cpuset cs.  Can't kmalloc GFP_KERNEL while holding
-        * tasklist_lock.  We could use GFP_ATOMIC, but with a
-        * few more lines of code, we can retry until we get a big
-        * enough mmarray[] w/o using GFP_ATOMIC.
-        */
-       while (1) {
-               ntasks = cgroup_task_count(cs->css.cgroup);  /* guess */
-               ntasks += fudge;
-               mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
-               if (!mmarray)
-                       goto done;
-               read_lock(&tasklist_lock);              /* block fork */
-               if (cgroup_task_count(cs->css.cgroup) <= ntasks)
-                       break;                          /* got enough */
-               read_unlock(&tasklist_lock);            /* try again */
-               kfree(mmarray);
-       }
-
-       n = 0;
+       update_tasks_nodemask(cs, oldmem, &heap);
 
-       /* Load up mmarray[] with mm reference for each task in cpuset. */
-       cgroup_iter_start(cs->css.cgroup, &it);
-       while ((p = cgroup_iter_next(cs->css.cgroup, &it))) {
-               struct mm_struct *mm;
+       heap_free(&heap);
+done:
+       NODEMASK_FREE(oldmem);
+       return retval;
+}
 
-               if (n >= ntasks) {
-                       printk(KERN_WARNING
-                               "Cpuset mempolicy rebind incomplete.\n");
-                       break;
-               }
-               mm = get_task_mm(p);
-               if (!mm)
-                       continue;
-               mmarray[n++] = mm;
-       }
-       cgroup_iter_end(cs->css.cgroup, &it);
-       read_unlock(&tasklist_lock);
+int current_cpuset_is_being_rebound(void)
+{
+       return task_cs(current) == cpuset_being_rebound;
+}
 
-       /*
-        * Now that we've dropped the tasklist spinlock, we can
-        * rebind the vma mempolicies of each mm in mmarray[] to their
-        * new cpuset, and release that mm.  The mpol_rebind_mm()
-        * call takes mmap_sem, which we couldn't take while holding
-        * tasklist_lock.  Forks can happen again now - the mpol_dup()
-        * cpuset_being_rebound check will catch such forks, and rebind
-        * their vma mempolicies too.  Because we still hold the global
-        * cgroup_mutex, we know that no other rebind effort will
-        * be contending for the global variable cpuset_being_rebound.
-        * It's ok if we rebind the same mm twice; mpol_rebind_mm()
-        * is idempotent.  Also migrate pages in each mm to new nodes.
-        */
-       migrate = is_memory_migrate(cs);
-       for (i = 0; i < n; i++) {
-               struct mm_struct *mm = mmarray[i];
+static int update_relax_domain_level(struct cpuset *cs, s64 val)
+{
+#ifdef CONFIG_SMP
+       if (val < -1 || val >= sched_domain_level_max)
+               return -EINVAL;
+#endif
 
-               mpol_rebind_mm(mm, &cs->mems_allowed);
-               if (migrate)
-                       cpuset_migrate_mm(mm, &oldmem, &cs->mems_allowed);
-               mmput(mm);
+       if (val != cs->relax_domain_level) {
+               cs->relax_domain_level = val;
+               if (!cpumask_empty(cs->cpus_allowed) &&
+                   is_sched_load_balance(cs))
+                       async_rebuild_sched_domains();
        }
 
-       /* We're done rebinding vmas to this cpuset's new mems_allowed. */
-       kfree(mmarray);
-       cpuset_being_rebound = NULL;
-       retval = 0;
-done:
-       return retval;
+       return 0;
 }
 
-int current_cpuset_is_being_rebound(void)
+/*
+ * cpuset_change_flag - make a task's spread flags the same as its cpuset's
+ * @tsk: task to be updated
+ * @scan: struct cgroup_scanner containing the cgroup of the task
+ *
+ * Called by cgroup_scan_tasks() for each task in a cgroup.
+ *
+ * We don't need to re-check for the cgroup/cpuset membership, since we're
+ * holding cgroup_lock() at this point.
+ */
+static void cpuset_change_flag(struct task_struct *tsk,
+                               struct cgroup_scanner *scan)
 {
-       return task_cs(current) == cpuset_being_rebound;
+       cpuset_update_task_spread_flag(cgroup_cs(scan->cg), tsk);
 }
 
-static int update_relax_domain_level(struct cpuset *cs, s64 val)
+/*
+ * update_tasks_flags - update the spread flags of tasks in the cpuset.
+ * @cs: the cpuset in which each task's spread flags needs to be changed
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ *
+ * Called with cgroup_mutex held
+ *
+ * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * calling callback functions for each.
+ *
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
+ */
+static void update_tasks_flags(struct cpuset *cs, struct ptr_heap *heap)
 {
-       if (val < -1 || val >= SD_LV_MAX)
-               return -EINVAL;
-
-       if (val != cs->relax_domain_level) {
-               cs->relax_domain_level = val;
-               rebuild_sched_domains();
-       }
+       struct cgroup_scanner scan;
 
-       return 0;
+       scan.cg = cs->css.cgroup;
+       scan.test_task = NULL;
+       scan.process_task = cpuset_change_flag;
+       scan.heap = heap;
+       cgroup_scan_tasks(&scan);
 }
 
 /*
@@ -1062,32 +1225,48 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val)
 static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
                       int turning_on)
 {
-       struct cpuset trialcs;
+       struct cpuset *trialcs;
+       int balance_flag_changed;
+       int spread_flag_changed;
+       struct ptr_heap heap;
        int err;
-       int cpus_nonempty, balance_flag_changed;
 
-       trialcs = *cs;
+       trialcs = alloc_trial_cpuset(cs);
+       if (!trialcs)
+               return -ENOMEM;
+
        if (turning_on)
-               set_bit(bit, &trialcs.flags);
+               set_bit(bit, &trialcs->flags);
        else
-               clear_bit(bit, &trialcs.flags);
+               clear_bit(bit, &trialcs->flags);
 
-       err = validate_change(cs, &trialcs);
+       err = validate_change(cs, trialcs);
        if (err < 0)
-               return err;
+               goto out;
+
+       err = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
+       if (err < 0)
+               goto out;
 
-       cpus_nonempty = !cpus_empty(trialcs.cpus_allowed);
        balance_flag_changed = (is_sched_load_balance(cs) !=
-                                       is_sched_load_balance(&trialcs));
+                               is_sched_load_balance(trialcs));
+
+       spread_flag_changed = ((is_spread_slab(cs) != is_spread_slab(trialcs))
+                       || (is_spread_page(cs) != is_spread_page(trialcs)));
 
        mutex_lock(&callback_mutex);
-       cs->flags = trialcs.flags;
+       cs->flags = trialcs->flags;
        mutex_unlock(&callback_mutex);
 
-       if (cpus_nonempty && balance_flag_changed)
-               rebuild_sched_domains();
+       if (!cpumask_empty(trialcs->cpus_allowed) && balance_flag_changed)
+               async_rebuild_sched_domains();
 
-       return 0;
+       if (spread_flag_changed)
+               update_tasks_flags(cs, &heap);
+       heap_free(&heap);
+out:
+       free_trial_cpuset(trialcs);
+       return err;
 }
 
 /*
@@ -1189,54 +1368,93 @@ static int fmeter_getrate(struct fmeter *fmp)
 }
 
 /* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
-static int cpuset_can_attach(struct cgroup_subsys *ss,
-                            struct cgroup *cont, struct task_struct *tsk)
+static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
+                            struct task_struct *tsk)
 {
        struct cpuset *cs = cgroup_cs(cont);
 
-       if (cpus_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
+       if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
                return -ENOSPC;
-       if (tsk->flags & PF_THREAD_BOUND) {
-               cpumask_t mask;
 
-               mutex_lock(&callback_mutex);
-               mask = cs->cpus_allowed;
-               mutex_unlock(&callback_mutex);
-               if (!cpus_equal(tsk->cpus_allowed, mask))
-                       return -EINVAL;
-       }
+       /*
+        * Kthreads bound to specific cpus cannot be moved to a new cpuset; we
+        * cannot change their cpu affinity and isolating such threads by their
+        * set of allowed nodes is unnecessary.  Thus, cpusets are not
+        * applicable for such threads.  This prevents checking for success of
+        * set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may
+        * be changed.
+        */
+       if (tsk->flags & PF_THREAD_BOUND)
+               return -EINVAL;
 
-       return security_task_setscheduler(tsk, 0, NULL);
+       return 0;
 }
 
-static void cpuset_attach(struct cgroup_subsys *ss,
-                         struct cgroup *cont, struct cgroup *oldcont,
-                         struct task_struct *tsk)
+static int cpuset_can_attach_task(struct cgroup *cgrp, struct task_struct *task)
+{
+       return security_task_setscheduler(task);
+}
+
+/*
+ * Protected by cgroup_lock. The nodemasks must be stored globally because
+ * dynamically allocating them is not allowed in pre_attach, and they must
+ * persist among pre_attach, attach_task, and attach.
+ */
+static cpumask_var_t cpus_attach;
+static nodemask_t cpuset_attach_nodemask_from;
+static nodemask_t cpuset_attach_nodemask_to;
+
+/* Set-up work for before attaching each task. */
+static void cpuset_pre_attach(struct cgroup *cont)
 {
-       cpumask_t cpus;
-       nodemask_t from, to;
-       struct mm_struct *mm;
        struct cpuset *cs = cgroup_cs(cont);
-       struct cpuset *oldcs = cgroup_cs(oldcont);
+
+       if (cs == &top_cpuset)
+               cpumask_copy(cpus_attach, cpu_possible_mask);
+       else
+               guarantee_online_cpus(cs, cpus_attach);
+
+       guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+}
+
+/* Per-thread attachment work. */
+static void cpuset_attach_task(struct cgroup *cont, struct task_struct *tsk)
+{
        int err;
+       struct cpuset *cs = cgroup_cs(cont);
 
-       mutex_lock(&callback_mutex);
-       guarantee_online_cpus(cs, &cpus);
-       err = set_cpus_allowed_ptr(tsk, &cpus);
-       mutex_unlock(&callback_mutex);
-       if (err)
-               return;
+       /*
+        * can_attach beforehand should guarantee that this doesn't fail.
+        * TODO: have a better way to handle failure here
+        */
+       err = set_cpus_allowed_ptr(tsk, cpus_attach);
+       WARN_ON_ONCE(err);
+
+       cpuset_change_task_nodemask(tsk, &cpuset_attach_nodemask_to);
+       cpuset_update_task_spread_flag(cs, tsk);
+}
+
+static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cont,
+                         struct cgroup *oldcont, struct task_struct *tsk)
+{
+       struct mm_struct *mm;
+       struct cpuset *cs = cgroup_cs(cont);
+       struct cpuset *oldcs = cgroup_cs(oldcont);
 
-       from = oldcs->mems_allowed;
-       to = cs->mems_allowed;
+       /*
+        * Change mm, possibly for multiple threads in a threadgroup. This is
+        * expensive and may sleep.
+        */
+       cpuset_attach_nodemask_from = oldcs->mems_allowed;
+       cpuset_attach_nodemask_to = cs->mems_allowed;
        mm = get_task_mm(tsk);
        if (mm) {
-               mpol_rebind_mm(mm, &to);
+               mpol_rebind_mm(mm, &cpuset_attach_nodemask_to);
                if (is_memory_migrate(cs))
-                       cpuset_migrate_mm(mm, &from, &to);
+                       cpuset_migrate_mm(mm, &cpuset_attach_nodemask_from,
+                                         &cpuset_attach_nodemask_to);
                mmput(mm);
        }
-
 }
 
 /* The various types of files and directories in a cpuset file system */
@@ -1256,72 +1474,14 @@ typedef enum {
        FILE_SPREAD_SLAB,
 } cpuset_filetype_t;
 
-static ssize_t cpuset_common_file_write(struct cgroup *cont,
-                                       struct cftype *cft,
-                                       struct file *file,
-                                       const char __user *userbuf,
-                                       size_t nbytes, loff_t *unused_ppos)
-{
-       struct cpuset *cs = cgroup_cs(cont);
-       cpuset_filetype_t type = cft->private;
-       char *buffer;
-       int retval = 0;
-
-       /* Crude upper limit on largest legitimate cpulist user might write. */
-       if (nbytes > 100U + 6 * max(NR_CPUS, MAX_NUMNODES))
-               return -E2BIG;
-
-       /* +1 for nul-terminator */
-       buffer = kmalloc(nbytes + 1, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       if (copy_from_user(buffer, userbuf, nbytes)) {
-               retval = -EFAULT;
-               goto out1;
-       }
-       buffer[nbytes] = 0;     /* nul-terminate */
-
-       cgroup_lock();
-
-       if (cgroup_is_removed(cont)) {
-               retval = -ENODEV;
-               goto out2;
-       }
-
-       switch (type) {
-       case FILE_CPULIST:
-               retval = update_cpumask(cs, buffer);
-               break;
-       case FILE_MEMLIST:
-               retval = update_nodemask(cs, buffer);
-               break;
-       default:
-               retval = -EINVAL;
-               goto out2;
-       }
-
-       if (retval == 0)
-               retval = nbytes;
-out2:
-       cgroup_unlock();
-out1:
-       kfree(buffer);
-       return retval;
-}
-
 static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
 {
        int retval = 0;
        struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
 
-       cgroup_lock();
-
-       if (cgroup_is_removed(cgrp)) {
-               cgroup_unlock();
+       if (!cgroup_lock_live_group(cgrp))
                return -ENODEV;
-       }
 
        switch (type) {
        case FILE_CPU_EXCLUSIVE:
@@ -1347,11 +1507,9 @@ static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
                break;
        case FILE_SPREAD_PAGE:
                retval = update_flag(CS_SPREAD_PAGE, cs, val);
-               cs->mems_generation = cpuset_mems_generation++;
                break;
        case FILE_SPREAD_SLAB:
                retval = update_flag(CS_SPREAD_SLAB, cs, val);
-               cs->mems_generation = cpuset_mems_generation++;
                break;
        default:
                retval = -EINVAL;
@@ -1367,12 +1525,9 @@ static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
        struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
 
-       cgroup_lock();
-
-       if (cgroup_is_removed(cgrp)) {
-               cgroup_unlock();
+       if (!cgroup_lock_live_group(cgrp))
                return -ENODEV;
-       }
+
        switch (type) {
        case FILE_SCHED_RELAX_DOMAIN_LEVEL:
                retval = update_relax_domain_level(cs, val);
@@ -1385,6 +1540,43 @@ static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
        return retval;
 }
 
+/*
+ * Common handling for a write to a "cpus" or "mems" file.
+ */
+static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
+                               const char *buf)
+{
+       int retval = 0;
+       struct cpuset *cs = cgroup_cs(cgrp);
+       struct cpuset *trialcs;
+
+       if (!cgroup_lock_live_group(cgrp))
+               return -ENODEV;
+
+       trialcs = alloc_trial_cpuset(cs);
+       if (!trialcs) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       switch (cft->private) {
+       case FILE_CPULIST:
+               retval = update_cpumask(cs, trialcs, buf);
+               break;
+       case FILE_MEMLIST:
+               retval = update_nodemask(cs, trialcs, buf);
+               break;
+       default:
+               retval = -EINVAL;
+               break;
+       }
+
+       free_trial_cpuset(trialcs);
+out:
+       cgroup_unlock();
+       return retval;
+}
+
 /*
  * These ascii lists should be read in a single call, by using a user
  * buffer large enough to hold the entire map.  If read in smaller
@@ -1397,26 +1589,26 @@ static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
  * across a page fault.
  */
 
-static int cpuset_sprintf_cpulist(char *page, struct cpuset *cs)
+static size_t cpuset_sprintf_cpulist(char *page, struct cpuset *cs)
 {
-       cpumask_t mask;
+       size_t count;
 
        mutex_lock(&callback_mutex);
-       mask = cs->cpus_allowed;
+       count = cpulist_scnprintf(page, PAGE_SIZE, cs->cpus_allowed);
        mutex_unlock(&callback_mutex);
 
-       return cpulist_scnprintf(page, PAGE_SIZE, mask);
+       return count;
 }
 
-static int cpuset_sprintf_memlist(char *page, struct cpuset *cs)
+static size_t cpuset_sprintf_memlist(char *page, struct cpuset *cs)
 {
-       nodemask_t mask;
+       size_t count;
 
        mutex_lock(&callback_mutex);
-       mask = cs->mems_allowed;
+       count = nodelist_scnprintf(page, PAGE_SIZE, cs->mems_allowed);
        mutex_unlock(&callback_mutex);
 
-       return nodelist_scnprintf(page, PAGE_SIZE, mask);
+       return count;
 }
 
 static ssize_t cpuset_common_file_read(struct cgroup *cont,
@@ -1481,6 +1673,9 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
        default:
                BUG();
        }
+
+       /* Unreachable but makes gcc happy */
+       return 0;
 }
 
 static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
@@ -1493,6 +1688,9 @@ static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
        default:
                BUG();
        }
+
+       /* Unrechable but makes gcc happy */
+       return 0;
 }
 
 
@@ -1504,14 +1702,16 @@ static struct cftype files[] = {
        {
                .name = "cpus",
                .read = cpuset_common_file_read,
-               .write = cpuset_common_file_write,
+               .write_string = cpuset_write_resmask,
+               .max_write_len = (100U + 6 * NR_CPUS),
                .private = FILE_CPULIST,
        },
 
        {
                .name = "mems",
                .read = cpuset_common_file_read,
-               .write = cpuset_common_file_write,
+               .write_string = cpuset_write_resmask,
+               .max_write_len = (100U + 6 * MAX_NUMNODES),
                .private = FILE_MEMLIST,
        },
 
@@ -1562,6 +1762,7 @@ static struct cftype files[] = {
                .read_u64 = cpuset_read_u64,
                .write_u64 = cpuset_write_u64,
                .private = FILE_MEMORY_PRESSURE,
+               .mode = S_IRUGO,
        },
 
        {
@@ -1601,10 +1802,9 @@ static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
 }
 
 /*
- * post_clone() is called at the end of cgroup_clone().
- * 'cgroup' was just created automatically as a result of
- * a cgroup_clone(), and the current task is about to
- * be moved into 'cgroup'.
+ * post_clone() is called during cgroup_create() when the
+ * clone_children mount argument was specified.  The cgroup
+ * can not yet have any tasks.
  *
  * Currently we refuse to set up the cgroup - thereby
  * refusing the task to be entered, and as a result refusing
@@ -1632,8 +1832,10 @@ static void cpuset_post_clone(struct cgroup_subsys *ss,
        cs = cgroup_cs(cgroup);
        parent_cs = cgroup_cs(parent);
 
+       mutex_lock(&callback_mutex);
        cs->mems_allowed = parent_cs->mems_allowed;
-       cs->cpus_allowed = parent_cs->cpus_allowed;
+       cpumask_copy(cs->cpus_allowed, parent_cs->cpus_allowed);
+       mutex_unlock(&callback_mutex);
        return;
 }
 
@@ -1651,25 +1853,25 @@ static struct cgroup_subsys_state *cpuset_create(
        struct cpuset *parent;
 
        if (!cont->parent) {
-               /* This is early initialization for the top cgroup */
-               top_cpuset.mems_generation = cpuset_mems_generation++;
                return &top_cpuset.css;
        }
        parent = cgroup_cs(cont->parent);
        cs = kmalloc(sizeof(*cs), GFP_KERNEL);
        if (!cs)
                return ERR_PTR(-ENOMEM);
+       if (!alloc_cpumask_var(&cs->cpus_allowed, GFP_KERNEL)) {
+               kfree(cs);
+               return ERR_PTR(-ENOMEM);
+       }
 
-       cpuset_update_task_memory_state();
        cs->flags = 0;
        if (is_spread_page(parent))
                set_bit(CS_SPREAD_PAGE, &cs->flags);
        if (is_spread_slab(parent))
                set_bit(CS_SPREAD_SLAB, &cs->flags);
        set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
-       cpus_clear(cs->cpus_allowed);
+       cpumask_clear(cs->cpus_allowed);
        nodes_clear(cs->mems_allowed);
-       cs->mems_generation = cpuset_mems_generation++;
        fmeter_init(&cs->fmeter);
        cs->relax_domain_level = -1;
 
@@ -1679,35 +1881,31 @@ static struct cgroup_subsys_state *cpuset_create(
 }
 
 /*
- * Locking note on the strange update_flag() call below:
- *
  * If the cpuset being removed has its flag 'sched_load_balance'
  * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains().  The get_online_cpus()
- * call in rebuild_sched_domains() must not be made while holding
- * callback_mutex.  Elsewhere the kernel nests callback_mutex inside
- * get_online_cpus() calls.  So the reverse nesting would risk an
- * ABBA deadlock.
+ * will call async_rebuild_sched_domains().
  */
 
 static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
 {
        struct cpuset *cs = cgroup_cs(cont);
 
-       cpuset_update_task_memory_state();
-
        if (is_sched_load_balance(cs))
                update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
 
        number_of_cpusets--;
+       free_cpumask_var(cs->cpus_allowed);
        kfree(cs);
 }
 
 struct cgroup_subsys cpuset_subsys = {
        .name = "cpuset",
        .create = cpuset_create,
-       .destroy  = cpuset_destroy,
+       .destroy = cpuset_destroy,
        .can_attach = cpuset_can_attach,
+       .can_attach_task = cpuset_can_attach_task,
+       .pre_attach = cpuset_pre_attach,
+       .attach_task = cpuset_attach_task,
        .attach = cpuset_attach,
        .populate = cpuset_populate,
        .post_clone = cpuset_post_clone,
@@ -1715,19 +1913,6 @@ struct cgroup_subsys cpuset_subsys = {
        .early_init = 1,
 };
 
-/*
- * cpuset_init_early - just enough so that the calls to
- * cpuset_update_task_memory_state() in early init code
- * are harmless.
- */
-
-int __init cpuset_init_early(void)
-{
-       top_cpuset.mems_generation = cpuset_mems_generation++;
-       return 0;
-}
-
-
 /**
  * cpuset_init - initialize cpusets at system boot
  *
@@ -1738,11 +1923,13 @@ int __init cpuset_init(void)
 {
        int err = 0;
 
-       cpus_setall(top_cpuset.cpus_allowed);
+       if (!alloc_cpumask_var(&top_cpuset.cpus_allowed, GFP_KERNEL))
+               BUG();
+
+       cpumask_setall(top_cpuset.cpus_allowed);
        nodes_setall(top_cpuset.mems_allowed);
 
        fmeter_init(&top_cpuset.fmeter);
-       top_cpuset.mems_generation = cpuset_mems_generation++;
        set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags);
        top_cpuset.relax_domain_level = -1;
 
@@ -1750,6 +1937,9 @@ int __init cpuset_init(void)
        if (err < 0)
                return err;
 
+       if (!alloc_cpumask_var(&cpus_attach, GFP_KERNEL))
+               BUG();
+
        number_of_cpusets = 1;
        return 0;
 }
@@ -1765,10 +1955,9 @@ int __init cpuset_init(void)
 static void cpuset_do_move_task(struct task_struct *tsk,
                                struct cgroup_scanner *scan)
 {
-       struct cpuset_hotplug_scanner *chsp;
+       struct cgroup *new_cgroup = scan->data;
 
-       chsp = container_of(scan, struct cpuset_hotplug_scanner, scan);
-       cgroup_attach_task(chsp->to, tsk);
+       cgroup_attach_task(new_cgroup, tsk);
 }
 
 /**
@@ -1784,21 +1973,21 @@ static void cpuset_do_move_task(struct task_struct *tsk,
  */
 static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
 {
-       struct cpuset_hotplug_scanner scan;
+       struct cgroup_scanner scan;
 
-       scan.scan.cg = from->css.cgroup;
-       scan.scan.test_task = NULL; /* select all tasks in cgroup */
-       scan.scan.process_task = cpuset_do_move_task;
-       scan.scan.heap = NULL;
-       scan.to = to->css.cgroup;
+       scan.cg = from->css.cgroup;
+       scan.test_task = NULL; /* select all tasks in cgroup */
+       scan.process_task = cpuset_do_move_task;
+       scan.heap = NULL;
+       scan.data = to->css.cgroup;
 
-       if (cgroup_scan_tasks((struct cgroup_scanner *)&scan))
+       if (cgroup_scan_tasks(&scan))
                printk(KERN_ERR "move_member_tasks_to_cpuset: "
                                "cgroup_scan_tasks failed\n");
 }
 
 /*
- * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
+ * If CPU and/or memory hotplug handlers, below, unplug any CPUs
  * or memory nodes, we need to walk over the cpuset hierarchy,
  * removing that CPU or node from all cpusets.  If this removes the
  * last CPU or node from a cpuset, then move the tasks in the empty
@@ -1824,7 +2013,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
         * has online cpus, so can't be empty).
         */
        parent = cs->parent;
-       while (cpus_empty(parent->cpus_allowed) ||
+       while (cpumask_empty(parent->cpus_allowed) ||
                        nodes_empty(parent->mems_allowed))
                parent = parent->parent;
 
@@ -1846,74 +2035,50 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
  * that has tasks along with an empty 'mems'.  But if we did see such
  * a cpuset, we'd handle it just like we do if its 'cpus' was empty.
  */
-static void scan_for_empty_cpusets(const struct cpuset *root)
+static void scan_for_empty_cpusets(struct cpuset *root)
 {
+       LIST_HEAD(queue);
        struct cpuset *cp;      /* scans cpusets being updated */
        struct cpuset *child;   /* scans child cpusets of cp */
-       struct list_head queue;
        struct cgroup *cont;
-
-       INIT_LIST_HEAD(&queue);
+       static nodemask_t oldmems;      /* protected by cgroup_mutex */
 
        list_add_tail((struct list_head *)&root->stack_list, &queue);
 
        while (!list_empty(&queue)) {
-               cp = container_of(queue.next, struct cpuset, stack_list);
+               cp = list_first_entry(&queue, struct cpuset, stack_list);
                list_del(queue.next);
                list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
                        child = cgroup_cs(cont);
                        list_add_tail(&child->stack_list, &queue);
                }
-               cont = cp->css.cgroup;
 
                /* Continue past cpusets with all cpus, mems online */
-               if (cpus_subset(cp->cpus_allowed, cpu_online_map) &&
+               if (cpumask_subset(cp->cpus_allowed, cpu_active_mask) &&
                    nodes_subset(cp->mems_allowed, node_states[N_HIGH_MEMORY]))
                        continue;
 
+               oldmems = cp->mems_allowed;
+
                /* Remove offline cpus and mems from this cpuset. */
                mutex_lock(&callback_mutex);
-               cpus_and(cp->cpus_allowed, cp->cpus_allowed, cpu_online_map);
+               cpumask_and(cp->cpus_allowed, cp->cpus_allowed,
+                           cpu_active_mask);
                nodes_and(cp->mems_allowed, cp->mems_allowed,
                                                node_states[N_HIGH_MEMORY]);
                mutex_unlock(&callback_mutex);
 
                /* Move tasks from the empty cpuset to a parent */
-               if (cpus_empty(cp->cpus_allowed) ||
+               if (cpumask_empty(cp->cpus_allowed) ||
                     nodes_empty(cp->mems_allowed))
                        remove_tasks_in_empty_cpuset(cp);
+               else {
+                       update_tasks_cpumask(cp, NULL);
+                       update_tasks_nodemask(cp, &oldmems, NULL);
+               }
        }
 }
 
-/*
- * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
- * cpu_online_map and node_states[N_HIGH_MEMORY].  Force the top cpuset to
- * track what's online after any CPU or memory node hotplug or unplug event.
- *
- * Since there are two callers of this routine, one for CPU hotplug
- * events and one for memory node hotplug events, we could have coded
- * two separate routines here.  We code it as a single common routine
- * in order to minimize text size.
- */
-
-static void common_cpu_mem_hotplug_unplug(int rebuild_sd)
-{
-       cgroup_lock();
-
-       top_cpuset.cpus_allowed = cpu_online_map;
-       top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
-       scan_for_empty_cpusets(&top_cpuset);
-
-       /*
-        * Scheduler destroys domains on hotplug events.
-        * Rebuild them based on the current settings.
-        */
-       if (rebuild_sd)
-               rebuild_sched_domains();
-
-       cgroup_unlock();
-}
-
 /*
  * The top_cpuset tracks what CPUs and Memory Nodes are online,
  * period.  This is necessary in order to make cpusets transparent
@@ -1921,41 +2086,62 @@ static void common_cpu_mem_hotplug_unplug(int rebuild_sd)
  * but making no active use of cpusets.
  *
  * This routine ensures that top_cpuset.cpus_allowed tracks
- * cpu_online_map on each CPU hotplug (cpuhp) event.
+ * cpu_active_mask on each CPU hotplug (cpuhp) event.
+ *
+ * Called within get_online_cpus().  Needs to call cgroup_lock()
+ * before calling generate_sched_domains().
  */
+void cpuset_update_active_cpus(void)
+{
+       struct sched_domain_attr *attr;
+       cpumask_var_t *doms;
+       int ndoms;
 
-static int cpuset_handle_cpuhp(struct notifier_block *unused_nb,
-                               unsigned long phase, void *unused_cpu)
-{
-       switch (phase) {
-       case CPU_UP_CANCELED:
-       case CPU_UP_CANCELED_FROZEN:
-       case CPU_DOWN_FAILED:
-       case CPU_DOWN_FAILED_FROZEN:
-       case CPU_ONLINE:
-       case CPU_ONLINE_FROZEN:
-       case CPU_DEAD:
-       case CPU_DEAD_FROZEN:
-               common_cpu_mem_hotplug_unplug(1);
-               break;
-       default:
-               return NOTIFY_DONE;
-       }
+       cgroup_lock();
+       mutex_lock(&callback_mutex);
+       cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
+       mutex_unlock(&callback_mutex);
+       scan_for_empty_cpusets(&top_cpuset);
+       ndoms = generate_sched_domains(&doms, &attr);
+       cgroup_unlock();
 
-       return NOTIFY_OK;
+       /* Have scheduler rebuild the domains */
+       partition_sched_domains(ndoms, doms, attr);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * Keep top_cpuset.mems_allowed tracking node_states[N_HIGH_MEMORY].
- * Call this routine anytime after you change
- * node_states[N_HIGH_MEMORY].
- * See also the previous routine cpuset_handle_cpuhp().
+ * Call this routine anytime after node_states[N_HIGH_MEMORY] changes.
+ * See also the previous routine cpuset_track_online_cpus().
  */
-
-void cpuset_track_online_nodes(void)
+static int cpuset_track_online_nodes(struct notifier_block *self,
+                               unsigned long action, void *arg)
 {
-       common_cpu_mem_hotplug_unplug(0);
+       static nodemask_t oldmems;      /* protected by cgroup_mutex */
+
+       cgroup_lock();
+       switch (action) {
+       case MEM_ONLINE:
+               oldmems = top_cpuset.mems_allowed;
+               mutex_lock(&callback_mutex);
+               top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
+               mutex_unlock(&callback_mutex);
+               update_tasks_nodemask(&top_cpuset, &oldmems, NULL);
+               break;
+       case MEM_OFFLINE:
+               /*
+                * needn't update top_cpuset.mems_allowed explicitly because
+                * scan_for_empty_cpusets() will update it.
+                */
+               scan_for_empty_cpusets(&top_cpuset);
+               break;
+       default:
+               break;
+       }
+       cgroup_unlock();
+
+       return NOTIFY_OK;
 }
 #endif
 
@@ -1967,40 +2153,75 @@ void cpuset_track_online_nodes(void)
 
 void __init cpuset_init_smp(void)
 {
-       top_cpuset.cpus_allowed = cpu_online_map;
+       cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
        top_cpuset.mems_allowed = node_states[N_HIGH_MEMORY];
 
-       hotcpu_notifier(cpuset_handle_cpuhp, 0);
+       hotplug_memory_notifier(cpuset_track_online_nodes, 10);
+
+       cpuset_wq = create_singlethread_workqueue("cpuset");
+       BUG_ON(!cpuset_wq);
 }
 
 /**
-
  * cpuset_cpus_allowed - return cpus_allowed mask from a tasks cpuset.
  * @tsk: pointer to task_struct from which to obtain cpuset->cpus_allowed.
- * @pmask: pointer to cpumask_t variable to receive cpus_allowed set.
+ * @pmask: pointer to struct cpumask variable to receive cpus_allowed set.
  *
- * Description: Returns the cpumask_t cpus_allowed of the cpuset
+ * Description: Returns the cpumask_var_t cpus_allowed of the cpuset
  * attached to the specified @tsk.  Guaranteed to return some non-empty
  * subset of cpu_online_map, even if this means going outside the
  * tasks cpuset.
  **/
 
-void cpuset_cpus_allowed(struct task_struct *tsk, cpumask_t *pmask)
+void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
 {
        mutex_lock(&callback_mutex);
-       cpuset_cpus_allowed_locked(tsk, pmask);
+       task_lock(tsk);
+       guarantee_online_cpus(task_cs(tsk), pmask);
+       task_unlock(tsk);
        mutex_unlock(&callback_mutex);
 }
 
-/**
- * cpuset_cpus_allowed_locked - return cpus_allowed mask from a tasks cpuset.
- * Must be called with callback_mutex held.
- **/
-void cpuset_cpus_allowed_locked(struct task_struct *tsk, cpumask_t *pmask)
+int cpuset_cpus_allowed_fallback(struct task_struct *tsk)
 {
-       task_lock(tsk);
-       guarantee_online_cpus(task_cs(tsk), pmask);
-       task_unlock(tsk);
+       const struct cpuset *cs;
+       int cpu;
+
+       rcu_read_lock();
+       cs = task_cs(tsk);
+       if (cs)
+               do_set_cpus_allowed(tsk, cs->cpus_allowed);
+       rcu_read_unlock();
+
+       /*
+        * We own tsk->cpus_allowed, nobody can change it under us.
+        *
+        * But we used cs && cs->cpus_allowed lockless and thus can
+        * race with cgroup_attach_task() or update_cpumask() and get
+        * the wrong tsk->cpus_allowed. However, both cases imply the
+        * subsequent cpuset_change_cpumask()->set_cpus_allowed_ptr()
+        * which takes task_rq_lock().
+        *
+        * If we are called after it dropped the lock we must see all
+        * changes in tsk_cs()->cpus_allowed. Otherwise we can temporary
+        * set any mask even if it is not right from task_cs() pov,
+        * the pending set_cpus_allowed_ptr() will fix things.
+        */
+
+       cpu = cpumask_any_and(&tsk->cpus_allowed, cpu_active_mask);
+       if (cpu >= nr_cpu_ids) {
+               /*
+                * Either tsk->cpus_allowed is wrong (see above) or it
+                * is actually empty. The latter case is only possible
+                * if we are racing with remove_tasks_in_empty_cpuset().
+                * Like above we can temporary set any mask and rely on
+                * set_cpus_allowed_ptr() as synchronization point.
+                */
+               do_set_cpus_allowed(tsk, cpu_possible_mask);
+               cpu = cpumask_any(cpu_active_mask);
+       }
+
+       return cpu;
 }
 
 void cpuset_init_current_mems_allowed(void)
@@ -2056,26 +2277,24 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
 }
 
 /**
- * cpuset_zone_allowed_softwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_softwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.  If
- * __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.  If it's not a
- * __GFP_HARDWALL request and this zone's nodes is in the nearest
- * hardwalled cpuset ancestor to this tasks cpuset, yes.
- * If the task has been OOM killed and has access to memory reserves
- * as specified by the TIF_MEMDIE flag, yes.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If it's not a __GFP_HARDWALL request and this node is in the nearest
+ * hardwalled cpuset ancestor to this task's cpuset, yes.  If the task has been
+ * OOM killed and has access to memory reserves as specified by the TIF_MEMDIE
+ * flag, yes.
  * Otherwise, no.
  *
- * If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
- * reduces to cpuset_zone_allowed_hardwall().  Otherwise,
- * cpuset_zone_allowed_softwall() might sleep, and might allow a zone
- * from an enclosing cpuset.
+ * If __GFP_HARDWALL is set, cpuset_node_allowed_softwall() reduces to
+ * cpuset_node_allowed_hardwall().  Otherwise, cpuset_node_allowed_softwall()
+ * might sleep, and might allow a node from an enclosing cpuset.
  *
- * cpuset_zone_allowed_hardwall() only handles the simpler case of
- * hardwall cpusets, and never sleeps.
+ * cpuset_node_allowed_hardwall() only handles the simpler case of hardwall
+ * cpusets, and never sleeps.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2114,20 +2333,17 @@ static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
  *     GFP_USER     - only nodes in current tasks mems allowed ok.
  *
  * Rule:
- *    Don't call cpuset_zone_allowed_softwall if you can't sleep, unless you
+ *    Don't call cpuset_node_allowed_softwall if you can't sleep, unless you
  *    pass in the __GFP_HARDWALL flag set in gfp_flag, which disables
  *    the code that might scan up ancestor cpusets and sleep.
  */
-
-int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
        const struct cpuset *cs;        /* current cpuset ancestors */
        int allowed;                    /* is allocation in zone z allowed? */
 
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
        if (node_isset(node, current->mems_allowed))
                return 1;
@@ -2156,15 +2372,15 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
 }
 
 /*
- * cpuset_zone_allowed_hardwall - Can we allocate on zone z's memory node?
- * @z: is this zone on an allowed node?
+ * cpuset_node_allowed_hardwall - Can we allocate on a memory node?
+ * @node: is this an allowed node?
  * @gfp_mask: memory allocation flags
  *
- * If we're in interrupt, yes, we can always allocate.
- * If __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.   If the task has been
- * OOM killed and has access to memory reserves as specified by the
- * TIF_MEMDIE flag, yes.  Otherwise, no.
+ * If we're in interrupt, yes, we can always allocate.  If __GFP_THISNODE is
+ * set, yes, we can always allocate.  If node is in our task's mems_allowed,
+ * yes.  If the task has been OOM killed and has access to memory reserves as
+ * specified by the TIF_MEMDIE flag, yes.
+ * Otherwise, no.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2172,20 +2388,16 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
  * any node on the zonelist except the first.  By the time any such
  * calls get to this routine, we should just shut up and say 'yes'.
  *
- * Unlike the cpuset_zone_allowed_softwall() variant, above,
- * this variant requires that the zone be in the current tasks
+ * Unlike the cpuset_node_allowed_softwall() variant, above,
+ * this variant requires that the node be in the current task's
  * mems_allowed or that we're in interrupt.  It does not scan up the
  * cpuset hierarchy for the nearest enclosing mem_exclusive cpuset.
  * It never sleeps.
  */
-
-int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
+int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
 {
-       int node;                       /* node that zone z is on */
-
        if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
                return 1;
-       node = zone_to_nid(z);
        if (node_isset(node, current->mems_allowed))
                return 1;
        /*
@@ -2197,22 +2409,6 @@ int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
        return 0;
 }
 
-/**
- * cpuset_lock - lock out any changes to cpuset structures
- *
- * The out of memory (oom) code needs to mutex_lock cpusets
- * from being changed while it scans the tasklist looking for a
- * task in an overlapping cpuset.  Expose callback_mutex via this
- * cpuset_lock() routine, so the oom code can lock it, before
- * locking the task list.  The tasklist_lock is a spinlock, so
- * must be taken inside callback_mutex.
- */
-
-void cpuset_lock(void)
-{
-       mutex_lock(&callback_mutex);
-}
-
 /**
  * cpuset_unlock - release lock on cpuset changes
  *
@@ -2225,7 +2421,8 @@ void cpuset_unlock(void)
 }
 
 /**
- * cpuset_mem_spread_node() - On which node to begin search for a page
+ * cpuset_mem_spread_node() - On which node to begin search for a file page
+ * cpuset_slab_spread_node() - On which node to begin search for a slab page
  *
  * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for
  * tasks in a cpuset with is_spread_page or is_spread_slab set),
@@ -2250,16 +2447,35 @@ void cpuset_unlock(void)
  * See kmem_cache_alloc_node().
  */
 
-int cpuset_mem_spread_node(void)
+static int cpuset_spread_node(int *rotor)
 {
        int node;
 
-       node = next_node(current->cpuset_mem_spread_rotor, current->mems_allowed);
+       node = next_node(*rotor, current->mems_allowed);
        if (node == MAX_NUMNODES)
                node = first_node(current->mems_allowed);
-       current->cpuset_mem_spread_rotor = node;
+       *rotor = node;
        return node;
 }
+
+int cpuset_mem_spread_node(void)
+{
+       if (current->cpuset_mem_spread_rotor == NUMA_NO_NODE)
+               current->cpuset_mem_spread_rotor =
+                       node_random(&current->mems_allowed);
+
+       return cpuset_spread_node(&current->cpuset_mem_spread_rotor);
+}
+
+int cpuset_slab_spread_node(void)
+{
+       if (current->cpuset_slab_spread_rotor == NUMA_NO_NODE)
+               current->cpuset_slab_spread_rotor =
+                       node_random(&current->mems_allowed);
+
+       return cpuset_spread_node(&current->cpuset_slab_spread_rotor);
+}
+
 EXPORT_SYMBOL_GPL(cpuset_mem_spread_node);
 
 /**
@@ -2279,6 +2495,29 @@ int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
        return nodes_intersects(tsk1->mems_allowed, tsk2->mems_allowed);
 }
 
+/**
+ * cpuset_print_task_mems_allowed - prints task's cpuset and mems_allowed
+ * @task: pointer to task_struct of some task.
+ *
+ * Description: Prints @task's name, cpuset name, and cached copy of its
+ * mems_allowed to the kernel log.  Must hold task_lock(task) to allow
+ * dereferencing task_cs(task).
+ */
+void cpuset_print_task_mems_allowed(struct task_struct *tsk)
+{
+       struct dentry *dentry;
+
+       dentry = task_cs(tsk)->css.cgroup->dentry;
+       spin_lock(&cpuset_buffer_lock);
+       snprintf(cpuset_name, CPUSET_NAME_LEN,
+                dentry ? (const char *)dentry->d_name.name : "/");
+       nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN,
+                          tsk->mems_allowed);
+       printk(KERN_INFO "%s cpuset=%s mems_allowed=%s\n",
+              tsk->comm, cpuset_name, cpuset_nodelist);
+       spin_unlock(&cpuset_buffer_lock);
+}
+
 /*
  * Collection of memory_pressure is suppressed unless
  * this flag is enabled by writing "1" to the special
@@ -2372,23 +2611,13 @@ const struct file_operations proc_cpuset_operations = {
 };
 #endif /* CONFIG_PROC_PID_CPUSET */
 
-/* Display task cpus_allowed, mems_allowed in /proc/<pid>/status file. */
+/* Display task mems_allowed in /proc/<pid>/status file. */
 void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task)
 {
-       seq_printf(m, "Cpus_allowed:\t");
-       m->count += cpumask_scnprintf(m->buf + m->count, m->size - m->count,
-                                       task->cpus_allowed);
-       seq_printf(m, "\n");
-       seq_printf(m, "Cpus_allowed_list:\t");
-       m->count += cpulist_scnprintf(m->buf + m->count, m->size - m->count,
-                                       task->cpus_allowed);
-       seq_printf(m, "\n");
        seq_printf(m, "Mems_allowed:\t");
-       m->count += nodemask_scnprintf(m->buf + m->count, m->size - m->count,
-                                       task->mems_allowed);
+       seq_nodemask(m, &task->mems_allowed);
        seq_printf(m, "\n");
        seq_printf(m, "Mems_allowed_list:\t");
-       m->count += nodelist_scnprintf(m->buf + m->count, m->size - m->count,
-                                       task->mems_allowed);
+       seq_nodemask_list(m, &task->mems_allowed);
        seq_printf(m, "\n");
 }