diff options
author | Tejun Heo <tj@kernel.org> | 2013-08-08 20:11:23 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-08-08 20:11:23 -0400 |
commit | 6387698699afd72d6304566fb6ccf84bffe07c56 (patch) | |
tree | 9440e96fa8e5adce62409a5b0e40984dfedaada3 | |
parent | a7c6d554aa01236ac2a9f851ab0f75704f76dfa2 (diff) |
cgroup: add css_parent()
Currently, controllers have to explicitly follow the cgroup hierarchy
to find the parent of a given css. cgroup is moving towards using
cgroup_subsys_state as the main controller interface construct, so
let's provide a way to climb the hierarchy using just csses.
This patch implements css_parent() which, given a css, returns its
parent. The function is guarnateed to valid non-NULL parent css as
long as the target css is not at the top of the hierarchy.
freezer, cpuset, cpu, cpuacct, hugetlb, memory, net_cls and devices
are converted to use css_parent() instead of accessing cgroup->parent
directly.
* __parent_ca() is dropped from cpuacct and its usage is replaced with
parent_ca(). The only difference between the two was NULL test on
cgroup->parent which is now embedded in css_parent() making the
distinction moot. Note that eventually a css->parent field will be
added to css and the NULL check in css_parent() will go away.
This patch shouldn't cause any behavior differences.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
-rw-r--r-- | block/blk-cgroup.h | 4 | ||||
-rw-r--r-- | include/linux/cgroup.h | 15 | ||||
-rw-r--r-- | kernel/cgroup_freezer.c | 8 | ||||
-rw-r--r-- | kernel/cpuset.c | 6 | ||||
-rw-r--r-- | kernel/sched/core.c | 9 | ||||
-rw-r--r-- | kernel/sched/cpuacct.c | 11 | ||||
-rw-r--r-- | mm/hugetlb_cgroup.c | 6 | ||||
-rw-r--r-- | mm/memcontrol.c | 39 | ||||
-rw-r--r-- | net/sched/cls_cgroup.c | 8 | ||||
-rw-r--r-- | security/device_cgroup.c | 18 |
10 files changed, 46 insertions, 78 deletions
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index 8e5863e900bf..b6802c46d68f 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h | |||
@@ -209,9 +209,7 @@ static inline struct blkcg *bio_blkcg(struct bio *bio) | |||
209 | */ | 209 | */ |
210 | static inline struct blkcg *blkcg_parent(struct blkcg *blkcg) | 210 | static inline struct blkcg *blkcg_parent(struct blkcg *blkcg) |
211 | { | 211 | { |
212 | struct cgroup *pcg = blkcg->css.cgroup->parent; | 212 | return css_to_blkcg(css_parent(&blkcg->css)); |
213 | |||
214 | return pcg ? cgroup_to_blkcg(pcg) : NULL; | ||
215 | } | 213 | } |
216 | 214 | ||
217 | /** | 215 | /** |
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 821678aae4db..18112a3bb12b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -647,6 +647,21 @@ struct cgroup_subsys { | |||
647 | #undef SUBSYS | 647 | #undef SUBSYS |
648 | 648 | ||
649 | /** | 649 | /** |
650 | * css_parent - find the parent css | ||
651 | * @css: the target cgroup_subsys_state | ||
652 | * | ||
653 | * Return the parent css of @css. This function is guaranteed to return | ||
654 | * non-NULL parent as long as @css isn't the root. | ||
655 | */ | ||
656 | static inline | ||
657 | struct cgroup_subsys_state *css_parent(struct cgroup_subsys_state *css) | ||
658 | { | ||
659 | struct cgroup *parent_cgrp = css->cgroup->parent; | ||
660 | |||
661 | return parent_cgrp ? parent_cgrp->subsys[css->ss->subsys_id] : NULL; | ||
662 | } | ||
663 | |||
664 | /** | ||
650 | * cgroup_css - obtain a cgroup's css for the specified subsystem | 665 | * cgroup_css - obtain a cgroup's css for the specified subsystem |
651 | * @cgrp: the cgroup of interest | 666 | * @cgrp: the cgroup of interest |
652 | * @subsys_id: the subsystem of interest | 667 | * @subsys_id: the subsystem of interest |
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 1db686e47a22..657a73cd44c4 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -62,11 +62,7 @@ static inline struct freezer *task_freezer(struct task_struct *task) | |||
62 | 62 | ||
63 | static struct freezer *parent_freezer(struct freezer *freezer) | 63 | static struct freezer *parent_freezer(struct freezer *freezer) |
64 | { | 64 | { |
65 | struct cgroup *pcg = freezer->css.cgroup->parent; | 65 | return css_freezer(css_parent(&freezer->css)); |
66 | |||
67 | if (pcg) | ||
68 | return cgroup_freezer(pcg); | ||
69 | return NULL; | ||
70 | } | 66 | } |
71 | 67 | ||
72 | bool cgroup_freezing(struct task_struct *task) | 68 | bool cgroup_freezing(struct task_struct *task) |
@@ -234,7 +230,7 @@ static void freezer_fork(struct task_struct *task) | |||
234 | * The root cgroup is non-freezable, so we can skip the | 230 | * The root cgroup is non-freezable, so we can skip the |
235 | * following check. | 231 | * following check. |
236 | */ | 232 | */ |
237 | if (!freezer->css.cgroup->parent) | 233 | if (!parent_freezer(freezer)) |
238 | goto out; | 234 | goto out; |
239 | 235 | ||
240 | spin_lock_irq(&freezer->lock); | 236 | spin_lock_irq(&freezer->lock); |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 6e9cbdde25bd..259a4af37e69 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
@@ -133,11 +133,7 @@ static inline struct cpuset *task_cs(struct task_struct *task) | |||
133 | 133 | ||
134 | static inline struct cpuset *parent_cs(struct cpuset *cs) | 134 | static inline struct cpuset *parent_cs(struct cpuset *cs) |
135 | { | 135 | { |
136 | struct cgroup *pcgrp = cs->css.cgroup->parent; | 136 | return css_cs(css_parent(&cs->css)); |
137 | |||
138 | if (pcgrp) | ||
139 | return cgroup_cs(pcgrp); | ||
140 | return NULL; | ||
141 | } | 137 | } |
142 | 138 | ||
143 | #ifdef CONFIG_NUMA | 139 | #ifdef CONFIG_NUMA |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 5bccb0277129..7a10742b389a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -7114,13 +7114,10 @@ static struct cgroup_subsys_state *cpu_cgroup_css_alloc(struct cgroup *cgrp) | |||
7114 | static int cpu_cgroup_css_online(struct cgroup *cgrp) | 7114 | static int cpu_cgroup_css_online(struct cgroup *cgrp) |
7115 | { | 7115 | { |
7116 | struct task_group *tg = cgroup_tg(cgrp); | 7116 | struct task_group *tg = cgroup_tg(cgrp); |
7117 | struct task_group *parent; | 7117 | struct task_group *parent = css_tg(css_parent(&tg->css)); |
7118 | 7118 | ||
7119 | if (!cgrp->parent) | 7119 | if (parent) |
7120 | return 0; | 7120 | sched_online_group(tg, parent); |
7121 | |||
7122 | parent = cgroup_tg(cgrp->parent); | ||
7123 | sched_online_group(tg, parent); | ||
7124 | return 0; | 7121 | return 0; |
7125 | } | 7122 | } |
7126 | 7123 | ||
diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 8ccfa10cc89f..f6926a149a71 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c | |||
@@ -50,16 +50,9 @@ static inline struct cpuacct *task_ca(struct task_struct *tsk) | |||
50 | return css_ca(task_css(tsk, cpuacct_subsys_id)); | 50 | return css_ca(task_css(tsk, cpuacct_subsys_id)); |
51 | } | 51 | } |
52 | 52 | ||
53 | static inline struct cpuacct *__parent_ca(struct cpuacct *ca) | ||
54 | { | ||
55 | return cgroup_ca(ca->css.cgroup->parent); | ||
56 | } | ||
57 | |||
58 | static inline struct cpuacct *parent_ca(struct cpuacct *ca) | 53 | static inline struct cpuacct *parent_ca(struct cpuacct *ca) |
59 | { | 54 | { |
60 | if (!ca->css.cgroup->parent) | 55 | return css_ca(css_parent(&ca->css)); |
61 | return NULL; | ||
62 | return cgroup_ca(ca->css.cgroup->parent); | ||
63 | } | 56 | } |
64 | 57 | ||
65 | static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage); | 58 | static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage); |
@@ -284,7 +277,7 @@ void cpuacct_account_field(struct task_struct *p, int index, u64 val) | |||
284 | while (ca != &root_cpuacct) { | 277 | while (ca != &root_cpuacct) { |
285 | kcpustat = this_cpu_ptr(ca->cpustat); | 278 | kcpustat = this_cpu_ptr(ca->cpustat); |
286 | kcpustat->cpustat[index] += val; | 279 | kcpustat->cpustat[index] += val; |
287 | ca = __parent_ca(ca); | 280 | ca = parent_ca(ca); |
288 | } | 281 | } |
289 | rcu_read_unlock(); | 282 | rcu_read_unlock(); |
290 | } | 283 | } |
diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c index 95585a0b9c8d..57ecb5d2513f 100644 --- a/mm/hugetlb_cgroup.c +++ b/mm/hugetlb_cgroup.c | |||
@@ -59,11 +59,7 @@ static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg) | |||
59 | static inline struct hugetlb_cgroup * | 59 | static inline struct hugetlb_cgroup * |
60 | parent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg) | 60 | parent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg) |
61 | { | 61 | { |
62 | struct cgroup *parent = h_cg->css.cgroup->parent; | 62 | return hugetlb_cgroup_from_css(css_parent(&h_cg->css)); |
63 | |||
64 | if (!parent) | ||
65 | return NULL; | ||
66 | return hugetlb_cgroup_from_cgroup(parent); | ||
67 | } | 63 | } |
68 | 64 | ||
69 | static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg) | 65 | static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg) |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 11d659e3b08e..69b3e520f921 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1524,10 +1524,8 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg) | |||
1524 | 1524 | ||
1525 | int mem_cgroup_swappiness(struct mem_cgroup *memcg) | 1525 | int mem_cgroup_swappiness(struct mem_cgroup *memcg) |
1526 | { | 1526 | { |
1527 | struct cgroup *cgrp = memcg->css.cgroup; | ||
1528 | |||
1529 | /* root ? */ | 1527 | /* root ? */ |
1530 | if (cgrp->parent == NULL) | 1528 | if (!css_parent(&memcg->css)) |
1531 | return vm_swappiness; | 1529 | return vm_swappiness; |
1532 | 1530 | ||
1533 | return memcg->swappiness; | 1531 | return memcg->swappiness; |
@@ -5026,11 +5024,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft, | |||
5026 | { | 5024 | { |
5027 | int retval = 0; | 5025 | int retval = 0; |
5028 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); | 5026 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
5029 | struct cgroup *parent = cont->parent; | 5027 | struct mem_cgroup *parent_memcg = mem_cgroup_from_css(css_parent(&memcg->css)); |
5030 | struct mem_cgroup *parent_memcg = NULL; | ||
5031 | |||
5032 | if (parent) | ||
5033 | parent_memcg = mem_cgroup_from_cont(parent); | ||
5034 | 5028 | ||
5035 | mutex_lock(&memcg_create_mutex); | 5029 | mutex_lock(&memcg_create_mutex); |
5036 | 5030 | ||
@@ -5282,18 +5276,15 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft, | |||
5282 | static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg, | 5276 | static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg, |
5283 | unsigned long long *mem_limit, unsigned long long *memsw_limit) | 5277 | unsigned long long *mem_limit, unsigned long long *memsw_limit) |
5284 | { | 5278 | { |
5285 | struct cgroup *cgroup; | ||
5286 | unsigned long long min_limit, min_memsw_limit, tmp; | 5279 | unsigned long long min_limit, min_memsw_limit, tmp; |
5287 | 5280 | ||
5288 | min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT); | 5281 | min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT); |
5289 | min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT); | 5282 | min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT); |
5290 | cgroup = memcg->css.cgroup; | ||
5291 | if (!memcg->use_hierarchy) | 5283 | if (!memcg->use_hierarchy) |
5292 | goto out; | 5284 | goto out; |
5293 | 5285 | ||
5294 | while (cgroup->parent) { | 5286 | while (css_parent(&memcg->css)) { |
5295 | cgroup = cgroup->parent; | 5287 | memcg = mem_cgroup_from_css(css_parent(&memcg->css)); |
5296 | memcg = mem_cgroup_from_cont(cgroup); | ||
5297 | if (!memcg->use_hierarchy) | 5288 | if (!memcg->use_hierarchy) |
5298 | break; | 5289 | break; |
5299 | tmp = res_counter_read_u64(&memcg->res, RES_LIMIT); | 5290 | tmp = res_counter_read_u64(&memcg->res, RES_LIMIT); |
@@ -5523,16 +5514,11 @@ static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft, | |||
5523 | u64 val) | 5514 | u64 val) |
5524 | { | 5515 | { |
5525 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); | 5516 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); |
5526 | struct mem_cgroup *parent; | 5517 | struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(&memcg->css)); |
5527 | |||
5528 | if (val > 100) | ||
5529 | return -EINVAL; | ||
5530 | 5518 | ||
5531 | if (cgrp->parent == NULL) | 5519 | if (val > 100 || !parent) |
5532 | return -EINVAL; | 5520 | return -EINVAL; |
5533 | 5521 | ||
5534 | parent = mem_cgroup_from_cont(cgrp->parent); | ||
5535 | |||
5536 | mutex_lock(&memcg_create_mutex); | 5522 | mutex_lock(&memcg_create_mutex); |
5537 | 5523 | ||
5538 | /* If under hierarchy, only empty-root can set this value */ | 5524 | /* If under hierarchy, only empty-root can set this value */ |
@@ -5861,14 +5847,12 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp, | |||
5861 | struct cftype *cft, u64 val) | 5847 | struct cftype *cft, u64 val) |
5862 | { | 5848 | { |
5863 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); | 5849 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); |
5864 | struct mem_cgroup *parent; | 5850 | struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(&memcg->css)); |
5865 | 5851 | ||
5866 | /* cannot set to root cgroup and only 0 and 1 are allowed */ | 5852 | /* cannot set to root cgroup and only 0 and 1 are allowed */ |
5867 | if (!cgrp->parent || !((val == 0) || (val == 1))) | 5853 | if (!parent || !((val == 0) || (val == 1))) |
5868 | return -EINVAL; | 5854 | return -EINVAL; |
5869 | 5855 | ||
5870 | parent = mem_cgroup_from_cont(cgrp->parent); | ||
5871 | |||
5872 | mutex_lock(&memcg_create_mutex); | 5856 | mutex_lock(&memcg_create_mutex); |
5873 | /* oom-kill-disable is a flag for subhierarchy. */ | 5857 | /* oom-kill-disable is a flag for subhierarchy. */ |
5874 | if ((parent->use_hierarchy) || memcg_has_children(memcg)) { | 5858 | if ((parent->use_hierarchy) || memcg_has_children(memcg)) { |
@@ -6266,15 +6250,14 @@ free_out: | |||
6266 | static int | 6250 | static int |
6267 | mem_cgroup_css_online(struct cgroup *cont) | 6251 | mem_cgroup_css_online(struct cgroup *cont) |
6268 | { | 6252 | { |
6269 | struct mem_cgroup *memcg, *parent; | 6253 | struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); |
6254 | struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(&memcg->css)); | ||
6270 | int error = 0; | 6255 | int error = 0; |
6271 | 6256 | ||
6272 | if (!cont->parent) | 6257 | if (!parent) |
6273 | return 0; | 6258 | return 0; |
6274 | 6259 | ||
6275 | mutex_lock(&memcg_create_mutex); | 6260 | mutex_lock(&memcg_create_mutex); |
6276 | memcg = mem_cgroup_from_cont(cont); | ||
6277 | parent = mem_cgroup_from_cont(cont->parent); | ||
6278 | 6261 | ||
6279 | memcg->use_hierarchy = parent->use_hierarchy; | 6262 | memcg->use_hierarchy = parent->use_hierarchy; |
6280 | memcg->oom_kill_disable = parent->oom_kill_disable; | 6263 | memcg->oom_kill_disable = parent->oom_kill_disable; |
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index af412ab2b477..9e6b75e5efce 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c | |||
@@ -50,9 +50,11 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp) | |||
50 | 50 | ||
51 | static int cgrp_css_online(struct cgroup *cgrp) | 51 | static int cgrp_css_online(struct cgroup *cgrp) |
52 | { | 52 | { |
53 | if (cgrp->parent) | 53 | struct cgroup_cls_state *cs = cgrp_cls_state(cgrp); |
54 | cgrp_cls_state(cgrp)->classid = | 54 | struct cgroup_cls_state *parent = css_cls_state(css_parent(&cs->css)); |
55 | cgrp_cls_state(cgrp->parent)->classid; | 55 | |
56 | if (parent) | ||
57 | cs->classid = parent->classid; | ||
56 | return 0; | 58 | return 0; |
57 | } | 59 | } |
58 | 60 | ||
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 90953648c643..635a49db005d 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
@@ -198,13 +198,11 @@ static inline bool is_devcg_online(const struct dev_cgroup *devcg) | |||
198 | */ | 198 | */ |
199 | static int devcgroup_online(struct cgroup *cgroup) | 199 | static int devcgroup_online(struct cgroup *cgroup) |
200 | { | 200 | { |
201 | struct dev_cgroup *dev_cgroup, *parent_dev_cgroup = NULL; | 201 | struct dev_cgroup *dev_cgroup = cgroup_to_devcgroup(cgroup); |
202 | struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css_parent(&dev_cgroup->css)); | ||
202 | int ret = 0; | 203 | int ret = 0; |
203 | 204 | ||
204 | mutex_lock(&devcgroup_mutex); | 205 | mutex_lock(&devcgroup_mutex); |
205 | dev_cgroup = cgroup_to_devcgroup(cgroup); | ||
206 | if (cgroup->parent) | ||
207 | parent_dev_cgroup = cgroup_to_devcgroup(cgroup->parent); | ||
208 | 206 | ||
209 | if (parent_dev_cgroup == NULL) | 207 | if (parent_dev_cgroup == NULL) |
210 | dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW; | 208 | dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW; |
@@ -394,12 +392,10 @@ static bool may_access(struct dev_cgroup *dev_cgroup, | |||
394 | static int parent_has_perm(struct dev_cgroup *childcg, | 392 | static int parent_has_perm(struct dev_cgroup *childcg, |
395 | struct dev_exception_item *ex) | 393 | struct dev_exception_item *ex) |
396 | { | 394 | { |
397 | struct cgroup *pcg = childcg->css.cgroup->parent; | 395 | struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css)); |
398 | struct dev_cgroup *parent; | ||
399 | 396 | ||
400 | if (!pcg) | 397 | if (!parent) |
401 | return 1; | 398 | return 1; |
402 | parent = cgroup_to_devcgroup(pcg); | ||
403 | return may_access(parent, ex, childcg->behavior); | 399 | return may_access(parent, ex, childcg->behavior); |
404 | } | 400 | } |
405 | 401 | ||
@@ -524,15 +520,11 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
524 | char temp[12]; /* 11 + 1 characters needed for a u32 */ | 520 | char temp[12]; /* 11 + 1 characters needed for a u32 */ |
525 | int count, rc = 0; | 521 | int count, rc = 0; |
526 | struct dev_exception_item ex; | 522 | struct dev_exception_item ex; |
527 | struct cgroup *p = devcgroup->css.cgroup; | 523 | struct dev_cgroup *parent = css_to_devcgroup(css_parent(&devcgroup->css)); |
528 | struct dev_cgroup *parent = NULL; | ||
529 | 524 | ||
530 | if (!capable(CAP_SYS_ADMIN)) | 525 | if (!capable(CAP_SYS_ADMIN)) |
531 | return -EPERM; | 526 | return -EPERM; |
532 | 527 | ||
533 | if (p->parent) | ||
534 | parent = cgroup_to_devcgroup(p->parent); | ||
535 | |||
536 | memset(&ex, 0, sizeof(ex)); | 528 | memset(&ex, 0, sizeof(ex)); |
537 | b = buffer; | 529 | b = buffer; |
538 | 530 | ||