aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-11-09 12:12:29 -0500
committerTejun Heo <tj@kernel.org>2012-11-09 12:12:29 -0500
commit574bd9f7c7c1d32f52dea5488018a6ff79031e22 (patch)
treef43657afb59dd12fe1eca329acc6caf885507727 /kernel/cgroup.c
parenteb6fd5040ee799009173daa49c3e7aa0362167c9 (diff)
cgroup: implement generic child / descendant walk macros
Currently, cgroup doesn't provide any generic helper for walking a given cgroup's children or descendants. This patch adds the following three macros. * cgroup_for_each_child() - walk immediate children of a cgroup. * cgroup_for_each_descendant_pre() - visit all descendants of a cgroup in pre-order tree traversal. * cgroup_for_each_descendant_post() - visit all descendants of a cgroup in post-order tree traversal. All three only require the user to hold RCU read lock during traversal. Verifying that each iterated cgroup is online is the responsibility of the user. When used with proper synchronization, cgroup_for_each_descendant_pre() can be used to propagate state updates to descendants in reliable way. See comments for details. v2: s/config/state/ in commit message and comments per Michal. More documentation on synchronization rules. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujisu.com> Reviewed-by: Michal Hocko <mhocko@suse.cz> Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2ed5968a04e7..0f8fa6aa371b 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2984,6 +2984,92 @@ static void cgroup_enable_task_cg_lists(void)
2984 write_unlock(&css_set_lock); 2984 write_unlock(&css_set_lock);
2985} 2985}
2986 2986
2987/**
2988 * cgroup_next_descendant_pre - find the next descendant for pre-order walk
2989 * @pos: the current position (%NULL to initiate traversal)
2990 * @cgroup: cgroup whose descendants to walk
2991 *
2992 * To be used by cgroup_for_each_descendant_pre(). Find the next
2993 * descendant to visit for pre-order traversal of @cgroup's descendants.
2994 */
2995struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
2996 struct cgroup *cgroup)
2997{
2998 struct cgroup *next;
2999
3000 WARN_ON_ONCE(!rcu_read_lock_held());
3001
3002 /* if first iteration, pretend we just visited @cgroup */
3003 if (!pos) {
3004 if (list_empty(&cgroup->children))
3005 return NULL;
3006 pos = cgroup;
3007 }
3008
3009 /* visit the first child if exists */
3010 next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling);
3011 if (next)
3012 return next;
3013
3014 /* no child, visit my or the closest ancestor's next sibling */
3015 do {
3016 next = list_entry_rcu(pos->sibling.next, struct cgroup,
3017 sibling);
3018 if (&next->sibling != &pos->parent->children)
3019 return next;
3020
3021 pos = pos->parent;
3022 } while (pos != cgroup);
3023
3024 return NULL;
3025}
3026EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);
3027
3028static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
3029{
3030 struct cgroup *last;
3031
3032 do {
3033 last = pos;
3034 pos = list_first_or_null_rcu(&pos->children, struct cgroup,
3035 sibling);
3036 } while (pos);
3037
3038 return last;
3039}
3040
3041/**
3042 * cgroup_next_descendant_post - find the next descendant for post-order walk
3043 * @pos: the current position (%NULL to initiate traversal)
3044 * @cgroup: cgroup whose descendants to walk
3045 *
3046 * To be used by cgroup_for_each_descendant_post(). Find the next
3047 * descendant to visit for post-order traversal of @cgroup's descendants.
3048 */
3049struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
3050 struct cgroup *cgroup)
3051{
3052 struct cgroup *next;
3053
3054 WARN_ON_ONCE(!rcu_read_lock_held());
3055
3056 /* if first iteration, visit the leftmost descendant */
3057 if (!pos) {
3058 next = cgroup_leftmost_descendant(cgroup);
3059 return next != cgroup ? next : NULL;
3060 }
3061
3062 /* if there's an unvisited sibling, visit its leftmost descendant */
3063 next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
3064 if (&next->sibling != &pos->parent->children)
3065 return cgroup_leftmost_descendant(next);
3066
3067 /* no sibling left, visit parent */
3068 next = pos->parent;
3069 return next != cgroup ? next : NULL;
3070}
3071EXPORT_SYMBOL_GPL(cgroup_next_descendant_post);
3072
2987void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it) 3073void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
2988 __acquires(css_set_lock) 3074 __acquires(css_set_lock)
2989{ 3075{