cpuset: let hotplug propagation work wait for task attaching
[platform/adaptation/renesas_rcar/renesas_kernel.git] / kernel / cpuset.c
index 535dce6..e902473 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 #include <linux/cgroup.h>
+#include <linux/wait.h>
 
 /*
  * Tracks how many cpusets are currently defined in system.
@@ -275,6 +276,8 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
 
 static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
 
+static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
+
 /*
  * This is ugly, but preserves the userspace API for existing cpuset
  * users. If someone tries to mount the "cpuset" filesystem, we
@@ -1436,14 +1439,8 @@ static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
        }
 
        cs->attach_in_progress--;
-
-       /*
-        * We may have raced with CPU/memory hotunplug.  Trigger hotplug
-        * propagation if @cs doesn't have any CPU or memory.  It will move
-        * the newly added tasks to the nearest parent which can execute.
-        */
-       if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
-               schedule_cpuset_propagate_hotplug(cs);
+       if (!cs->attach_in_progress)
+               wake_up(&cpuset_attach_wq);
 
        mutex_unlock(&cpuset_mutex);
 }
@@ -1555,10 +1552,6 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
         * resources, wait for the previously scheduled operations before
         * proceeding, so that we don't end up keep removing tasks added
         * after execution capability is restored.
-        *
-        * Flushing cpuset_hotplug_work is enough to synchronize against
-        * hotplug hanlding; however, cpuset_attach() may schedule
-        * propagation work directly.  Flush the workqueue too.
         */
        flush_work(&cpuset_hotplug_work);
        flush_workqueue(cpuset_propagate_hotplug_wq);
@@ -2005,8 +1998,20 @@ static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
        struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
        bool is_empty;
 
+retry:
+       wait_event(cpuset_attach_wq, cs->attach_in_progress == 0);
+
        mutex_lock(&cpuset_mutex);
 
+       /*
+        * We have raced with task attaching. We wait until attaching
+        * is finished, so we won't attach a task to an empty cpuset.
+        */
+       if (cs->attach_in_progress) {
+               mutex_unlock(&cpuset_mutex);
+               goto retry;
+       }
+
        cpumask_andnot(&off_cpus, cs->cpus_allowed, top_cpuset.cpus_allowed);
        nodes_andnot(off_mems, cs->mems_allowed, top_cpuset.mems_allowed);