|
@@ -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);
|
|
|
|