aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
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{