diff options
author | Tejun Heo <tj@kernel.org> | 2013-01-07 11:51:07 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-01-07 11:51:07 -0500 |
commit | 452477fa68c6d8ef80adebd05194c1c157ad9a53 (patch) | |
tree | 28682f4307a4e4bc2180d18ccb71a262700699df /kernel/cpuset.c | |
parent | 8d03394877ecdf87e1d694664c460747b8e05aa1 (diff) |
cpuset: pin down cpus and mems while a task is being attached
cpuset is scheduled to be decoupled from cgroup_lock which will make
configuration updates race with task migration. Any config update
will be allowed to happen between ->can_attach() and ->attach(). If
such config update removes either all cpus or mems, by the time
->attach() is called, the condition verified by ->can_attach(), that
the cpuset is capable of hosting the tasks, is no longer true.
This patch adds cpuset->attach_in_progress which is incremented from
->can_attach() and decremented when the attach operation finishes
either successfully or not. validate_change() treats cpusets w/
non-zero ->attach_in_progress like cpusets w/ tasks and refuses to
remove all cpus or mems from it.
This currently doesn't make any functional difference as everything is
protected by cgroup_mutex but enables decoupling the locking.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cpuset.c')
-rw-r--r-- | kernel/cpuset.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index a7bb547786d7..4334576f5d6a 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -91,6 +91,12 @@ struct cpuset { | |||
91 | 91 | ||
92 | struct fmeter fmeter; /* memory_pressure filter */ | 92 | struct fmeter fmeter; /* memory_pressure filter */ |
93 | 93 | ||
94 | /* | ||
95 | * Tasks are being attached to this cpuset. Used to prevent | ||
96 | * zeroing cpus/mems_allowed between ->can_attach() and ->attach(). | ||
97 | */ | ||
98 | int attach_in_progress; | ||
99 | |||
94 | /* partition number for rebuild_sched_domains() */ | 100 | /* partition number for rebuild_sched_domains() */ |
95 | int pn; | 101 | int pn; |
96 | 102 | ||
@@ -468,9 +474,12 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) | |||
468 | goto out; | 474 | goto out; |
469 | } | 475 | } |
470 | 476 | ||
471 | /* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */ | 477 | /* |
478 | * Cpusets with tasks - existing or newly being attached - can't | ||
479 | * have empty cpus_allowed or mems_allowed. | ||
480 | */ | ||
472 | ret = -ENOSPC; | 481 | ret = -ENOSPC; |
473 | if (cgroup_task_count(cur->css.cgroup) && | 482 | if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress) && |
474 | (cpumask_empty(trial->cpus_allowed) || | 483 | (cpumask_empty(trial->cpus_allowed) || |
475 | nodes_empty(trial->mems_allowed))) | 484 | nodes_empty(trial->mems_allowed))) |
476 | goto out; | 485 | goto out; |
@@ -1386,9 +1395,21 @@ static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) | |||
1386 | return ret; | 1395 | return ret; |
1387 | } | 1396 | } |
1388 | 1397 | ||
1398 | /* | ||
1399 | * Mark attach is in progress. This makes validate_change() fail | ||
1400 | * changes which zero cpus/mems_allowed. | ||
1401 | */ | ||
1402 | cs->attach_in_progress++; | ||
1403 | |||
1389 | return 0; | 1404 | return 0; |
1390 | } | 1405 | } |
1391 | 1406 | ||
1407 | static void cpuset_cancel_attach(struct cgroup *cgrp, | ||
1408 | struct cgroup_taskset *tset) | ||
1409 | { | ||
1410 | cgroup_cs(cgrp)->attach_in_progress--; | ||
1411 | } | ||
1412 | |||
1392 | /* | 1413 | /* |
1393 | * Protected by cgroup_mutex. cpus_attach is used only by cpuset_attach() | 1414 | * Protected by cgroup_mutex. cpus_attach is used only by cpuset_attach() |
1394 | * but we can't allocate it dynamically there. Define it global and | 1415 | * 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) | |||
1441 | &cpuset_attach_nodemask_to); | 1462 | &cpuset_attach_nodemask_to); |
1442 | mmput(mm); | 1463 | mmput(mm); |
1443 | } | 1464 | } |
1465 | |||
1466 | cs->attach_in_progress--; | ||
1444 | } | 1467 | } |
1445 | 1468 | ||
1446 | /* The various types of files and directories in a cpuset file system */ | 1469 | /* The various types of files and directories in a cpuset file system */ |
@@ -1908,6 +1931,7 @@ struct cgroup_subsys cpuset_subsys = { | |||
1908 | .css_offline = cpuset_css_offline, | 1931 | .css_offline = cpuset_css_offline, |
1909 | .css_free = cpuset_css_free, | 1932 | .css_free = cpuset_css_free, |
1910 | .can_attach = cpuset_can_attach, | 1933 | .can_attach = cpuset_can_attach, |
1934 | .cancel_attach = cpuset_cancel_attach, | ||
1911 | .attach = cpuset_attach, | 1935 | .attach = cpuset_attach, |
1912 | .subsys_id = cpuset_subsys_id, | 1936 | .subsys_id = cpuset_subsys_id, |
1913 | .base_cftypes = files, | 1937 | .base_cftypes = files, |