|
@@ -266,6 +266,7 @@ static struct workqueue_struct *cpuset_propagate_hotplug_wq;
|
|
|
|
|
|
static void cpuset_hotplug_workfn(struct work_struct *work);
|
|
|
static void cpuset_propagate_hotplug_workfn(struct work_struct *work);
|
|
|
+static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
|
|
|
|
|
|
static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
|
|
|
|
|
@@ -1464,6 +1465,14 @@ 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);
|
|
|
}
|
|
|
|
|
|
/* The various types of files and directories in a cpuset file system */
|
|
@@ -1569,8 +1578,13 @@ 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);
|
|
|
|
|
|
if (!cgroup_lock_live_group(cgrp))
|
|
|
return -ENODEV;
|