Skip to content

Commit e44193d

Browse files
lizf-oshtejun
authored andcommitted
cpuset: let hotplug propagation work wait for task attaching
Instead of triggering propagation work in cpuset_attach(), we make hotplug propagation work wait until there's no task attaching in progress. IMO this is more robust. We won't see empty masks in cpuset_attach(). Also it's a preparation for removing propagation work. Without asynchronous propagation we can't call move_tasks_in_empty_cpuset() in cpuset_attach(), because otherwise we'll deadlock on cgroup_mutex. tj: typo fixes. Signed-off-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent a73456f commit e44193d

File tree

1 file changed

+17
-12
lines changed

1 file changed

+17
-12
lines changed

kernel/cpuset.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include <linux/mutex.h>
6060
#include <linux/workqueue.h>
6161
#include <linux/cgroup.h>
62+
#include <linux/wait.h>
6263

6364
/*
6465
* Tracks how many cpusets are currently defined in system.
@@ -275,6 +276,8 @@ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
275276

276277
static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
277278

279+
static DECLARE_WAIT_QUEUE_HEAD(cpuset_attach_wq);
280+
278281
/*
279282
* This is ugly, but preserves the userspace API for existing cpuset
280283
* 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)
14361439
}
14371440

14381441
cs->attach_in_progress--;
1439-
1440-
/*
1441-
* We may have raced with CPU/memory hotunplug. Trigger hotplug
1442-
* propagation if @cs doesn't have any CPU or memory. It will move
1443-
* the newly added tasks to the nearest parent which can execute.
1444-
*/
1445-
if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
1446-
schedule_cpuset_propagate_hotplug(cs);
1442+
if (!cs->attach_in_progress)
1443+
wake_up(&cpuset_attach_wq);
14471444

14481445
mutex_unlock(&cpuset_mutex);
14491446
}
@@ -1555,10 +1552,6 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
15551552
* resources, wait for the previously scheduled operations before
15561553
* proceeding, so that we don't end up keep removing tasks added
15571554
* after execution capability is restored.
1558-
*
1559-
* Flushing cpuset_hotplug_work is enough to synchronize against
1560-
* hotplug hanlding; however, cpuset_attach() may schedule
1561-
* propagation work directly. Flush the workqueue too.
15621555
*/
15631556
flush_work(&cpuset_hotplug_work);
15641557
flush_workqueue(cpuset_propagate_hotplug_wq);
@@ -2005,8 +1998,20 @@ static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
20051998
struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
20061999
bool is_empty;
20072000

2001+
retry:
2002+
wait_event(cpuset_attach_wq, cs->attach_in_progress == 0);
2003+
20082004
mutex_lock(&cpuset_mutex);
20092005

2006+
/*
2007+
* We have raced with task attaching. We wait until attaching
2008+
* is finished, so we won't attach a task to an empty cpuset.
2009+
*/
2010+
if (cs->attach_in_progress) {
2011+
mutex_unlock(&cpuset_mutex);
2012+
goto retry;
2013+
}
2014+
20102015
cpumask_andnot(&off_cpus, cs->cpus_allowed, top_cpuset.cpus_allowed);
20112016
nodes_andnot(off_mems, cs->mems_allowed, top_cpuset.mems_allowed);
20122017

0 commit comments

Comments
 (0)