cpuset: pin down cpus and mems while a task is being attached
[~shefty/rdma-dev.git] / kernel / cpuset.c
index a7bb547786d7813782598823db6742976722bf2c..4334576f5d6a55077b3f41f026b69e3d1e433b4d 100644 (file)
@@ -91,6 +91,12 @@ struct cpuset {
 
        struct fmeter fmeter;           /* memory_pressure filter */
 
 
        struct fmeter fmeter;           /* memory_pressure filter */
 
+       /*
+        * Tasks are being attached to this cpuset.  Used to prevent
+        * zeroing cpus/mems_allowed between ->can_attach() and ->attach().
+        */
+       int attach_in_progress;
+
        /* partition number for rebuild_sched_domains() */
        int pn;
 
        /* partition number for rebuild_sched_domains() */
        int pn;
 
@@ -468,9 +474,12 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
                        goto out;
        }
 
                        goto out;
        }
 
-       /* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
+       /*
+        * Cpusets with tasks - existing or newly being attached - can't
+        * have empty cpus_allowed or mems_allowed.
+        */
        ret = -ENOSPC;
        ret = -ENOSPC;
-       if (cgroup_task_count(cur->css.cgroup) &&
+       if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress) &&
            (cpumask_empty(trial->cpus_allowed) ||
             nodes_empty(trial->mems_allowed)))
                goto out;
            (cpumask_empty(trial->cpus_allowed) ||
             nodes_empty(trial->mems_allowed)))
                goto out;
@@ -1386,9 +1395,21 @@ static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
                        return ret;
        }
 
                        return ret;
        }
 
+       /*
+        * Mark attach is in progress.  This makes validate_change() fail
+        * changes which zero cpus/mems_allowed.
+        */
+       cs->attach_in_progress++;
+
        return 0;
 }
 
        return 0;
 }
 
+static void cpuset_cancel_attach(struct cgroup *cgrp,
+                                struct cgroup_taskset *tset)
+{
+       cgroup_cs(cgrp)->attach_in_progress--;
+}
+
 /*
  * Protected by cgroup_mutex.  cpus_attach is used only by cpuset_attach()
  * but we can't allocate it dynamically there.  Define it global and
 /*
  * Protected by cgroup_mutex.  cpus_attach is used only by cpuset_attach()
  * but we can't allocate it dynamically there.  Define it global and
@@ -1441,6 +1462,8 @@ static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
                                          &cpuset_attach_nodemask_to);
                mmput(mm);
        }
                                          &cpuset_attach_nodemask_to);
                mmput(mm);
        }
+
+       cs->attach_in_progress--;
 }
 
 /* The various types of files and directories in a cpuset file system */
 }
 
 /* The various types of files and directories in a cpuset file system */
@@ -1908,6 +1931,7 @@ struct cgroup_subsys cpuset_subsys = {
        .css_offline = cpuset_css_offline,
        .css_free = cpuset_css_free,
        .can_attach = cpuset_can_attach,
        .css_offline = cpuset_css_offline,
        .css_free = cpuset_css_free,
        .can_attach = cpuset_can_attach,
+       .cancel_attach = cpuset_cancel_attach,
        .attach = cpuset_attach,
        .subsys_id = cpuset_subsys_id,
        .base_cftypes = files,
        .attach = cpuset_attach,
        .subsys_id = cpuset_subsys_id,
        .base_cftypes = files,