diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 86 |
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 | */ | ||
2995 | struct 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 | } | ||
3026 | EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre); | ||
3027 | |||
3028 | static 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 | */ | ||
3049 | struct 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 | } | ||
3071 | EXPORT_SYMBOL_GPL(cgroup_next_descendant_post); | ||
3072 | |||
2987 | void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it) | 3073 | void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it) |
2988 | __acquires(css_set_lock) | 3074 | __acquires(css_set_lock) |
2989 | { | 3075 | { |