diff options
-rw-r--r-- | block/blk-cgroup.c | 45 | ||||
-rw-r--r-- | kernel/cgroup_freezer.c | 14 | ||||
-rw-r--r-- | kernel/cpuset.c | 70 | ||||
-rw-r--r-- | kernel/events/core.c | 13 | ||||
-rw-r--r-- | kernel/sched.c | 31 |
5 files changed, 91 insertions, 82 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 8f630cec906e..b8c143d68ee0 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -30,8 +30,10 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup); | |||
30 | 30 | ||
31 | static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *, | 31 | static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *, |
32 | struct cgroup *); | 32 | struct cgroup *); |
33 | static int blkiocg_can_attach_task(struct cgroup *, struct task_struct *); | 33 | static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *, |
34 | static void blkiocg_attach_task(struct cgroup *, struct task_struct *); | 34 | struct cgroup_taskset *); |
35 | static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *, | ||
36 | struct cgroup_taskset *); | ||
35 | static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *); | 37 | static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *); |
36 | static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); | 38 | static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); |
37 | 39 | ||
@@ -44,8 +46,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *); | |||
44 | struct cgroup_subsys blkio_subsys = { | 46 | struct cgroup_subsys blkio_subsys = { |
45 | .name = "blkio", | 47 | .name = "blkio", |
46 | .create = blkiocg_create, | 48 | .create = blkiocg_create, |
47 | .can_attach_task = blkiocg_can_attach_task, | 49 | .can_attach = blkiocg_can_attach, |
48 | .attach_task = blkiocg_attach_task, | 50 | .attach = blkiocg_attach, |
49 | .destroy = blkiocg_destroy, | 51 | .destroy = blkiocg_destroy, |
50 | .populate = blkiocg_populate, | 52 | .populate = blkiocg_populate, |
51 | #ifdef CONFIG_BLK_CGROUP | 53 | #ifdef CONFIG_BLK_CGROUP |
@@ -1626,30 +1628,39 @@ done: | |||
1626 | * of the main cic data structures. For now we allow a task to change | 1628 | * of the main cic data structures. For now we allow a task to change |
1627 | * its cgroup only if it's the only owner of its ioc. | 1629 | * its cgroup only if it's the only owner of its ioc. |
1628 | */ | 1630 | */ |
1629 | static int blkiocg_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 1631 | static int blkiocg_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
1632 | struct cgroup_taskset *tset) | ||
1630 | { | 1633 | { |
1634 | struct task_struct *task; | ||
1631 | struct io_context *ioc; | 1635 | struct io_context *ioc; |
1632 | int ret = 0; | 1636 | int ret = 0; |
1633 | 1637 | ||
1634 | /* task_lock() is needed to avoid races with exit_io_context() */ | 1638 | /* task_lock() is needed to avoid races with exit_io_context() */ |
1635 | task_lock(tsk); | 1639 | cgroup_taskset_for_each(task, cgrp, tset) { |
1636 | ioc = tsk->io_context; | 1640 | task_lock(task); |
1637 | if (ioc && atomic_read(&ioc->nr_tasks) > 1) | 1641 | ioc = task->io_context; |
1638 | ret = -EINVAL; | 1642 | if (ioc && atomic_read(&ioc->nr_tasks) > 1) |
1639 | task_unlock(tsk); | 1643 | ret = -EINVAL; |
1640 | 1644 | task_unlock(task); | |
1645 | if (ret) | ||
1646 | break; | ||
1647 | } | ||
1641 | return ret; | 1648 | return ret; |
1642 | } | 1649 | } |
1643 | 1650 | ||
1644 | static void blkiocg_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 1651 | static void blkiocg_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
1652 | struct cgroup_taskset *tset) | ||
1645 | { | 1653 | { |
1654 | struct task_struct *task; | ||
1646 | struct io_context *ioc; | 1655 | struct io_context *ioc; |
1647 | 1656 | ||
1648 | task_lock(tsk); | 1657 | cgroup_taskset_for_each(task, cgrp, tset) { |
1649 | ioc = tsk->io_context; | 1658 | task_lock(task); |
1650 | if (ioc) | 1659 | ioc = task->io_context; |
1651 | ioc->cgroup_changed = 1; | 1660 | if (ioc) |
1652 | task_unlock(tsk); | 1661 | ioc->cgroup_changed = 1; |
1662 | task_unlock(task); | ||
1663 | } | ||
1653 | } | 1664 | } |
1654 | 1665 | ||
1655 | void blkio_policy_register(struct blkio_policy_type *blkiop) | 1666 | void blkio_policy_register(struct blkio_policy_type *blkiop) |
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index e95c6fb65cc0..0e748059ba87 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -162,10 +162,14 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
162 | struct cgroup_taskset *tset) | 162 | struct cgroup_taskset *tset) |
163 | { | 163 | { |
164 | struct freezer *freezer; | 164 | struct freezer *freezer; |
165 | struct task_struct *task; | ||
165 | 166 | ||
166 | /* | 167 | /* |
167 | * Anything frozen can't move or be moved to/from. | 168 | * Anything frozen can't move or be moved to/from. |
168 | */ | 169 | */ |
170 | cgroup_taskset_for_each(task, new_cgroup, tset) | ||
171 | if (cgroup_freezing(task)) | ||
172 | return -EBUSY; | ||
169 | 173 | ||
170 | freezer = cgroup_freezer(new_cgroup); | 174 | freezer = cgroup_freezer(new_cgroup); |
171 | if (freezer->state != CGROUP_THAWED) | 175 | if (freezer->state != CGROUP_THAWED) |
@@ -174,11 +178,6 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
174 | return 0; | 178 | return 0; |
175 | } | 179 | } |
176 | 180 | ||
177 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | ||
178 | { | ||
179 | return cgroup_freezing(tsk) ? -EBUSY : 0; | ||
180 | } | ||
181 | |||
182 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | 181 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) |
183 | { | 182 | { |
184 | struct freezer *freezer; | 183 | struct freezer *freezer; |
@@ -374,10 +373,5 @@ struct cgroup_subsys freezer_subsys = { | |||
374 | .populate = freezer_populate, | 373 | .populate = freezer_populate, |
375 | .subsys_id = freezer_subsys_id, | 374 | .subsys_id = freezer_subsys_id, |
376 | .can_attach = freezer_can_attach, | 375 | .can_attach = freezer_can_attach, |
377 | .can_attach_task = freezer_can_attach_task, | ||
378 | .pre_attach = NULL, | ||
379 | .attach_task = NULL, | ||
380 | .attach = NULL, | ||
381 | .fork = freezer_fork, | 376 | .fork = freezer_fork, |
382 | .exit = NULL, | ||
383 | }; | 377 | }; |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 512bd59e8627..9a8a61301524 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -1375,33 +1375,34 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | |||
1375 | struct cgroup_taskset *tset) | 1375 | struct cgroup_taskset *tset) |
1376 | { | 1376 | { |
1377 | struct cpuset *cs = cgroup_cs(cgrp); | 1377 | struct cpuset *cs = cgroup_cs(cgrp); |
1378 | struct task_struct *task; | ||
1379 | int ret; | ||
1378 | 1380 | ||
1379 | if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)) | 1381 | if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)) |
1380 | return -ENOSPC; | 1382 | return -ENOSPC; |
1381 | 1383 | ||
1382 | /* | 1384 | cgroup_taskset_for_each(task, cgrp, tset) { |
1383 | * Kthreads bound to specific cpus cannot be moved to a new cpuset; we | 1385 | /* |
1384 | * cannot change their cpu affinity and isolating such threads by their | 1386 | * Kthreads bound to specific cpus cannot be moved to a new |
1385 | * set of allowed nodes is unnecessary. Thus, cpusets are not | 1387 | * cpuset; we cannot change their cpu affinity and |
1386 | * applicable for such threads. This prevents checking for success of | 1388 | * isolating such threads by their set of allowed nodes is |
1387 | * set_cpus_allowed_ptr() on all attached tasks before cpus_allowed may | 1389 | * unnecessary. Thus, cpusets are not applicable for such |
1388 | * be changed. | 1390 | * threads. This prevents checking for success of |
1389 | */ | 1391 | * set_cpus_allowed_ptr() on all attached tasks before |
1390 | if (cgroup_taskset_first(tset)->flags & PF_THREAD_BOUND) | 1392 | * cpus_allowed may be changed. |
1391 | return -EINVAL; | 1393 | */ |
1392 | 1394 | if (task->flags & PF_THREAD_BOUND) | |
1395 | return -EINVAL; | ||
1396 | if ((ret = security_task_setscheduler(task))) | ||
1397 | return ret; | ||
1398 | } | ||
1393 | return 0; | 1399 | return 0; |
1394 | } | 1400 | } |
1395 | 1401 | ||
1396 | static int cpuset_can_attach_task(struct cgroup *cgrp, struct task_struct *task) | ||
1397 | { | ||
1398 | return security_task_setscheduler(task); | ||
1399 | } | ||
1400 | |||
1401 | /* | 1402 | /* |
1402 | * Protected by cgroup_lock. The nodemasks must be stored globally because | 1403 | * Protected by cgroup_lock. The nodemasks must be stored globally because |
1403 | * dynamically allocating them is not allowed in pre_attach, and they must | 1404 | * dynamically allocating them is not allowed in pre_attach, and they must |
1404 | * persist among pre_attach, attach_task, and attach. | 1405 | * persist among pre_attach, and attach. |
1405 | */ | 1406 | */ |
1406 | static cpumask_var_t cpus_attach; | 1407 | static cpumask_var_t cpus_attach; |
1407 | static nodemask_t cpuset_attach_nodemask_from; | 1408 | static nodemask_t cpuset_attach_nodemask_from; |
@@ -1420,39 +1421,34 @@ static void cpuset_pre_attach(struct cgroup *cont) | |||
1420 | guarantee_online_mems(cs, &cpuset_attach_nodemask_to); | 1421 | guarantee_online_mems(cs, &cpuset_attach_nodemask_to); |
1421 | } | 1422 | } |
1422 | 1423 | ||
1423 | /* Per-thread attachment work. */ | ||
1424 | static void cpuset_attach_task(struct cgroup *cont, struct task_struct *tsk) | ||
1425 | { | ||
1426 | int err; | ||
1427 | struct cpuset *cs = cgroup_cs(cont); | ||
1428 | |||
1429 | /* | ||
1430 | * can_attach beforehand should guarantee that this doesn't fail. | ||
1431 | * TODO: have a better way to handle failure here | ||
1432 | */ | ||
1433 | err = set_cpus_allowed_ptr(tsk, cpus_attach); | ||
1434 | WARN_ON_ONCE(err); | ||
1435 | |||
1436 | cpuset_change_task_nodemask(tsk, &cpuset_attach_nodemask_to); | ||
1437 | cpuset_update_task_spread_flag(cs, tsk); | ||
1438 | } | ||
1439 | |||
1440 | static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | 1424 | static void cpuset_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
1441 | struct cgroup_taskset *tset) | 1425 | struct cgroup_taskset *tset) |
1442 | { | 1426 | { |
1443 | struct mm_struct *mm; | 1427 | struct mm_struct *mm; |
1444 | struct task_struct *tsk = cgroup_taskset_first(tset); | 1428 | struct task_struct *task; |
1429 | struct task_struct *leader = cgroup_taskset_first(tset); | ||
1445 | struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset); | 1430 | struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset); |
1446 | struct cpuset *cs = cgroup_cs(cgrp); | 1431 | struct cpuset *cs = cgroup_cs(cgrp); |
1447 | struct cpuset *oldcs = cgroup_cs(oldcgrp); | 1432 | struct cpuset *oldcs = cgroup_cs(oldcgrp); |
1448 | 1433 | ||
1434 | cgroup_taskset_for_each(task, cgrp, tset) { | ||
1435 | /* | ||
1436 | * can_attach beforehand should guarantee that this doesn't | ||
1437 | * fail. TODO: have a better way to handle failure here | ||
1438 | */ | ||
1439 | WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach)); | ||
1440 | |||
1441 | cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to); | ||
1442 | cpuset_update_task_spread_flag(cs, task); | ||
1443 | } | ||
1444 | |||
1449 | /* | 1445 | /* |
1450 | * Change mm, possibly for multiple threads in a threadgroup. This is | 1446 | * Change mm, possibly for multiple threads in a threadgroup. This is |
1451 | * expensive and may sleep. | 1447 | * expensive and may sleep. |
1452 | */ | 1448 | */ |
1453 | cpuset_attach_nodemask_from = oldcs->mems_allowed; | 1449 | cpuset_attach_nodemask_from = oldcs->mems_allowed; |
1454 | cpuset_attach_nodemask_to = cs->mems_allowed; | 1450 | cpuset_attach_nodemask_to = cs->mems_allowed; |
1455 | mm = get_task_mm(tsk); | 1451 | mm = get_task_mm(leader); |
1456 | if (mm) { | 1452 | if (mm) { |
1457 | mpol_rebind_mm(mm, &cpuset_attach_nodemask_to); | 1453 | mpol_rebind_mm(mm, &cpuset_attach_nodemask_to); |
1458 | if (is_memory_migrate(cs)) | 1454 | if (is_memory_migrate(cs)) |
@@ -1908,9 +1904,7 @@ struct cgroup_subsys cpuset_subsys = { | |||
1908 | .create = cpuset_create, | 1904 | .create = cpuset_create, |
1909 | .destroy = cpuset_destroy, | 1905 | .destroy = cpuset_destroy, |
1910 | .can_attach = cpuset_can_attach, | 1906 | .can_attach = cpuset_can_attach, |
1911 | .can_attach_task = cpuset_can_attach_task, | ||
1912 | .pre_attach = cpuset_pre_attach, | 1907 | .pre_attach = cpuset_pre_attach, |
1913 | .attach_task = cpuset_attach_task, | ||
1914 | .attach = cpuset_attach, | 1908 | .attach = cpuset_attach, |
1915 | .populate = cpuset_populate, | 1909 | .populate = cpuset_populate, |
1916 | .post_clone = cpuset_post_clone, | 1910 | .post_clone = cpuset_post_clone, |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 0e8457da6f95..3b8e0edbe693 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -7044,10 +7044,13 @@ static int __perf_cgroup_move(void *info) | |||
7044 | return 0; | 7044 | return 0; |
7045 | } | 7045 | } |
7046 | 7046 | ||
7047 | static void | 7047 | static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
7048 | perf_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *task) | 7048 | struct cgroup_taskset *tset) |
7049 | { | 7049 | { |
7050 | task_function_call(task, __perf_cgroup_move, task); | 7050 | struct task_struct *task; |
7051 | |||
7052 | cgroup_taskset_for_each(task, cgrp, tset) | ||
7053 | task_function_call(task, __perf_cgroup_move, task); | ||
7051 | } | 7054 | } |
7052 | 7055 | ||
7053 | static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, | 7056 | static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, |
@@ -7061,7 +7064,7 @@ static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, | |||
7061 | if (!(task->flags & PF_EXITING)) | 7064 | if (!(task->flags & PF_EXITING)) |
7062 | return; | 7065 | return; |
7063 | 7066 | ||
7064 | perf_cgroup_attach_task(cgrp, task); | 7067 | task_function_call(task, __perf_cgroup_move, task); |
7065 | } | 7068 | } |
7066 | 7069 | ||
7067 | struct cgroup_subsys perf_subsys = { | 7070 | struct cgroup_subsys perf_subsys = { |
@@ -7070,6 +7073,6 @@ struct cgroup_subsys perf_subsys = { | |||
7070 | .create = perf_cgroup_create, | 7073 | .create = perf_cgroup_create, |
7071 | .destroy = perf_cgroup_destroy, | 7074 | .destroy = perf_cgroup_destroy, |
7072 | .exit = perf_cgroup_exit, | 7075 | .exit = perf_cgroup_exit, |
7073 | .attach_task = perf_cgroup_attach_task, | 7076 | .attach = perf_cgroup_attach, |
7074 | }; | 7077 | }; |
7075 | #endif /* CONFIG_CGROUP_PERF */ | 7078 | #endif /* CONFIG_CGROUP_PERF */ |
diff --git a/kernel/sched.c b/kernel/sched.c index 0e9344a71be3..161184da7b81 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -9127,24 +9127,31 @@ cpu_cgroup_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) | |||
9127 | sched_destroy_group(tg); | 9127 | sched_destroy_group(tg); |
9128 | } | 9128 | } |
9129 | 9129 | ||
9130 | static int | 9130 | static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
9131 | cpu_cgroup_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 9131 | struct cgroup_taskset *tset) |
9132 | { | 9132 | { |
9133 | struct task_struct *task; | ||
9134 | |||
9135 | cgroup_taskset_for_each(task, cgrp, tset) { | ||
9133 | #ifdef CONFIG_RT_GROUP_SCHED | 9136 | #ifdef CONFIG_RT_GROUP_SCHED |
9134 | if (!sched_rt_can_attach(cgroup_tg(cgrp), tsk)) | 9137 | if (!sched_rt_can_attach(cgroup_tg(cgrp), task)) |
9135 | return -EINVAL; | 9138 | return -EINVAL; |
9136 | #else | 9139 | #else |
9137 | /* We don't support RT-tasks being in separate groups */ | 9140 | /* We don't support RT-tasks being in separate groups */ |
9138 | if (tsk->sched_class != &fair_sched_class) | 9141 | if (task->sched_class != &fair_sched_class) |
9139 | return -EINVAL; | 9142 | return -EINVAL; |
9140 | #endif | 9143 | #endif |
9144 | } | ||
9141 | return 0; | 9145 | return 0; |
9142 | } | 9146 | } |
9143 | 9147 | ||
9144 | static void | 9148 | static void cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, |
9145 | cpu_cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 9149 | struct cgroup_taskset *tset) |
9146 | { | 9150 | { |
9147 | sched_move_task(tsk); | 9151 | struct task_struct *task; |
9152 | |||
9153 | cgroup_taskset_for_each(task, cgrp, tset) | ||
9154 | sched_move_task(task); | ||
9148 | } | 9155 | } |
9149 | 9156 | ||
9150 | static void | 9157 | static void |
@@ -9480,8 +9487,8 @@ struct cgroup_subsys cpu_cgroup_subsys = { | |||
9480 | .name = "cpu", | 9487 | .name = "cpu", |
9481 | .create = cpu_cgroup_create, | 9488 | .create = cpu_cgroup_create, |
9482 | .destroy = cpu_cgroup_destroy, | 9489 | .destroy = cpu_cgroup_destroy, |
9483 | .can_attach_task = cpu_cgroup_can_attach_task, | 9490 | .can_attach = cpu_cgroup_can_attach, |
9484 | .attach_task = cpu_cgroup_attach_task, | 9491 | .attach = cpu_cgroup_attach, |
9485 | .exit = cpu_cgroup_exit, | 9492 | .exit = cpu_cgroup_exit, |
9486 | .populate = cpu_cgroup_populate, | 9493 | .populate = cpu_cgroup_populate, |
9487 | .subsys_id = cpu_cgroup_subsys_id, | 9494 | .subsys_id = cpu_cgroup_subsys_id, |