Skip to content

Commit

Permalink
cgroup: convert cgroup_next_sibling() to cgroup_next_child()
Browse files Browse the repository at this point in the history
cgroup is transitioning to using css (cgroup_subsys_state) as the main
subsys interface handle instead of cgroup and the iterators will be
updated to use css too.  The iterators need to walk the cgroup
hierarchy and return the css's matching the origin css, which is a bit
cumbersome to open code.

This patch converts cgroup_next_sibling() to cgroup_next_child() so
that it can handle all steps of direct child iteration.  This will be
used to update iterators to take @css instead of @cgrp.  In addition
to the new iteration init handling, cgroup_next_child() is
restructured so that the different branches share the end of iteration
condition check.

This patch doesn't change any behavior.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
  • Loading branch information
Tejun Heo committed Aug 9, 2013
1 parent 182446d commit 3b287a5
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 31 deletions.
4 changes: 2 additions & 2 deletions include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ static inline struct cgroup *cgroup_from_id(struct cgroup_subsys *ss, int id)
return idr_find(&ss->root->cgroup_idr, id);
}

struct cgroup *cgroup_next_sibling(struct cgroup *pos);
struct cgroup *cgroup_next_child(struct cgroup *pos, struct cgroup *cgrp);

/**
* cgroup_for_each_child - iterate through children of a cgroup
Expand All @@ -802,7 +802,7 @@ struct cgroup *cgroup_next_sibling(struct cgroup *pos);
#define cgroup_for_each_child(pos, cgrp) \
for ((pos) = list_first_or_null_rcu(&(cgrp)->children, \
struct cgroup, sibling); \
(pos); (pos) = cgroup_next_sibling((pos)))
(pos); (pos) = cgroup_next_child((pos), (cgrp)))

struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
struct cgroup *cgroup);
Expand Down
59 changes: 30 additions & 29 deletions kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -3037,15 +3037,16 @@ static void cgroup_enable_task_cg_lists(void)
}

/**
* cgroup_next_sibling - find the next sibling of a given cgroup
* @pos: the current cgroup
* cgroup_next_child - find the next child of a given cgroup
* @pos: the current position (%NULL to initiate traversal)
* @cgrp: cgroup whose descendants to walk
*
* This function returns the next sibling of @pos and should be called
* under RCU read lock. The only requirement is that @pos is accessible.
* The next sibling is guaranteed to be returned regardless of @pos's
* state.
* This function returns the next child of @cgrp and should be called under
* RCU read lock. The only requirement is that @cgrp and @pos are
* accessible. The next sibling is guaranteed to be returned regardless of
* their states.
*/
struct cgroup *cgroup_next_sibling(struct cgroup *pos)
struct cgroup *cgroup_next_child(struct cgroup *pos, struct cgroup *cgrp)
{
struct cgroup *next;

Expand All @@ -3061,30 +3062,30 @@ struct cgroup *cgroup_next_sibling(struct cgroup *pos)
* safe to dereference from this RCU critical section. If
* ->sibling.next is inaccessible, cgroup_is_dead() is guaranteed
* to be visible as %true here.
*
* If @pos is dead, its next pointer can't be dereferenced;
* however, as each cgroup is given a monotonically increasing
* unique serial number and always appended to the sibling list,
* the next one can be found by walking the parent's children until
* we see a cgroup with higher serial number than @pos's. While
* this path can be slower, it's taken only when either the current
* cgroup is removed or iteration and removal race.
*/
if (likely(!cgroup_is_dead(pos))) {
if (!pos) {
next = list_entry_rcu(cgrp->children.next, struct cgroup, sibling);
} else if (likely(!cgroup_is_dead(pos))) {
next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
if (&next->sibling != &pos->parent->children)
return next;
return NULL;
} else {
list_for_each_entry_rcu(next, &cgrp->children, sibling)
if (next->serial_nr > pos->serial_nr)
break;
}

/*
* Can't dereference the next pointer. Each cgroup is given a
* monotonically increasing unique serial number and always
* appended to the sibling list, so the next one can be found by
* walking the parent's children until we see a cgroup with higher
* serial number than @pos's.
*
* While this path can be slow, it's taken only when either the
* current cgroup is removed or iteration and removal race.
*/
list_for_each_entry_rcu(next, &pos->parent->children, sibling)
if (next->serial_nr > pos->serial_nr)
return next;
if (&next->sibling != &cgrp->children)
return next;
return NULL;
}
EXPORT_SYMBOL_GPL(cgroup_next_sibling);
EXPORT_SYMBOL_GPL(cgroup_next_child);

/**
* cgroup_next_descendant_pre - find the next descendant for pre-order walk
Expand Down Expand Up @@ -3117,7 +3118,7 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,

/* no child, visit my or the closest ancestor's next sibling */
while (pos != cgroup) {
next = cgroup_next_sibling(pos);
next = cgroup_next_child(pos, pos->parent);
if (next)
return next;
pos = pos->parent;
Expand Down Expand Up @@ -3198,7 +3199,7 @@ struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
}

/* if there's an unvisited sibling, visit its leftmost descendant */
next = cgroup_next_sibling(pos);
next = cgroup_next_child(pos, pos->parent);
if (next)
return cgroup_leftmost_descendant(next);

Expand Down Expand Up @@ -4549,9 +4550,9 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
/*
* Mark @cgrp dead. This prevents further task migration and child
* creation by disabling cgroup_lock_live_group(). Note that
* CGRP_DEAD assertion is depended upon by cgroup_next_sibling() to
* CGRP_DEAD assertion is depended upon by cgroup_next_child() to
* resume iteration after dropping RCU read lock. See
* cgroup_next_sibling() for details.
* cgroup_next_child() for details.
*/
set_bit(CGRP_DEAD, &cgrp->flags);

Expand Down

0 comments on commit 3b287a5

Please sign in to comment.