Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 339324
b: refs/heads/master
c: 574bd9f
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo committed Nov 9, 2012
1 parent 0c7bb34 commit b5ebc79
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eb6fd5040ee799009173daa49c3e7aa0362167c9
refs/heads/master: 574bd9f7c7c1d32f52dea5488018a6ff79031e22
94 changes: 94 additions & 0 deletions trunk/include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,100 @@ static inline struct cgroup* task_cgroup(struct task_struct *task,
return task_subsys_state(task, subsys_id)->cgroup;
}

/**
* cgroup_for_each_child - iterate through children of a cgroup
* @pos: the cgroup * to use as the loop cursor
* @cgroup: cgroup whose children to walk
*
* Walk @cgroup's children. Must be called under rcu_read_lock(). A child
* cgroup which hasn't finished ->post_create() or already has finished
* ->pre_destroy() may show up during traversal and it's each subsystem's
* responsibility to verify that each @pos is alive.
*
* If a subsystem synchronizes against the parent in its ->post_create()
* and before starting iterating, a cgroup which finished ->post_create()
* is guaranteed to be visible in the future iterations.
*/
#define cgroup_for_each_child(pos, cgroup) \
list_for_each_entry_rcu(pos, &(cgroup)->children, sibling)

struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
struct cgroup *cgroup);

/**
* cgroup_for_each_descendant_pre - pre-order walk of a cgroup's descendants
* @pos: the cgroup * to use as the loop cursor
* @cgroup: cgroup whose descendants to walk
*
* Walk @cgroup's descendants. Must be called under rcu_read_lock(). A
* descendant cgroup which hasn't finished ->post_create() or already has
* finished ->pre_destroy() may show up during traversal and it's each
* subsystem's responsibility to verify that each @pos is alive.
*
* If a subsystem synchronizes against the parent in its ->post_create()
* and before starting iterating, and synchronizes against @pos on each
* iteration, any descendant cgroup which finished ->post_create() is
* guaranteed to be visible in the future iterations.
*
* In other words, the following guarantees that a descendant can't escape
* state updates of its ancestors.
*
* my_post_create(@cgrp)
* {
* Lock @cgrp->parent and @cgrp;
* Inherit state from @cgrp->parent;
* Unlock both.
* }
*
* my_update_state(@cgrp)
* {
* Lock @cgrp;
* Update @cgrp's state;
* Unlock @cgrp;
*
* cgroup_for_each_descendant_pre(@pos, @cgrp) {
* Lock @pos;
* Verify @pos is alive and inherit state from @pos->parent;
* Unlock @pos;
* }
* }
*
* As long as the inheriting step, including checking the parent state, is
* enclosed inside @pos locking, double-locking the parent isn't necessary
* while inheriting. The state update to the parent is guaranteed to be
* visible by walking order and, as long as inheriting operations to the
* same @pos are atomic to each other, multiple updates racing each other
* still result in the correct state. It's guaranateed that at least one
* inheritance happens for any cgroup after the latest update to its
* parent.
*
* If checking parent's state requires locking the parent, each inheriting
* iteration should lock and unlock both @pos->parent and @pos.
*
* Alternatively, a subsystem may choose to use a single global lock to
* synchronize ->post_create() and ->pre_destroy() against tree-walking
* operations.
*/
#define cgroup_for_each_descendant_pre(pos, cgroup) \
for (pos = cgroup_next_descendant_pre(NULL, (cgroup)); (pos); \
pos = cgroup_next_descendant_pre((pos), (cgroup)))

struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
struct cgroup *cgroup);

/**
* cgroup_for_each_descendant_post - post-order walk of a cgroup's descendants
* @pos: the cgroup * to use as the loop cursor
* @cgroup: cgroup whose descendants to walk
*
* Similar to cgroup_for_each_descendant_pre() but performs post-order
* traversal instead. Note that the walk visibility guarantee described in
* pre-order walk doesn't apply the same to post-order walks.
*/
#define cgroup_for_each_descendant_post(pos, cgroup) \
for (pos = cgroup_next_descendant_post(NULL, (cgroup)); (pos); \
pos = cgroup_next_descendant_post((pos), (cgroup)))

/* A cgroup_iter should be treated as an opaque object */
struct cgroup_iter {
struct list_head *cg_link;
Expand Down
86 changes: 86 additions & 0 deletions trunk/kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2984,6 +2984,92 @@ static void cgroup_enable_task_cg_lists(void)
write_unlock(&css_set_lock);
}

/**
* cgroup_next_descendant_pre - find the next descendant for pre-order walk
* @pos: the current position (%NULL to initiate traversal)
* @cgroup: cgroup whose descendants to walk
*
* To be used by cgroup_for_each_descendant_pre(). Find the next
* descendant to visit for pre-order traversal of @cgroup's descendants.
*/
struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
struct cgroup *cgroup)
{
struct cgroup *next;

WARN_ON_ONCE(!rcu_read_lock_held());

/* if first iteration, pretend we just visited @cgroup */
if (!pos) {
if (list_empty(&cgroup->children))
return NULL;
pos = cgroup;
}

/* visit the first child if exists */
next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling);
if (next)
return next;

/* no child, visit my or the closest ancestor's next sibling */
do {
next = list_entry_rcu(pos->sibling.next, struct cgroup,
sibling);
if (&next->sibling != &pos->parent->children)
return next;

pos = pos->parent;
} while (pos != cgroup);

return NULL;
}
EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);

static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
{
struct cgroup *last;

do {
last = pos;
pos = list_first_or_null_rcu(&pos->children, struct cgroup,
sibling);
} while (pos);

return last;
}

/**
* cgroup_next_descendant_post - find the next descendant for post-order walk
* @pos: the current position (%NULL to initiate traversal)
* @cgroup: cgroup whose descendants to walk
*
* To be used by cgroup_for_each_descendant_post(). Find the next
* descendant to visit for post-order traversal of @cgroup's descendants.
*/
struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
struct cgroup *cgroup)
{
struct cgroup *next;

WARN_ON_ONCE(!rcu_read_lock_held());

/* if first iteration, visit the leftmost descendant */
if (!pos) {
next = cgroup_leftmost_descendant(cgroup);
return next != cgroup ? next : NULL;
}

/* if there's an unvisited sibling, visit its leftmost descendant */
next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
if (&next->sibling != &pos->parent->children)
return cgroup_leftmost_descendant(next);

/* no sibling left, visit parent */
next = pos->parent;
return next != cgroup ? next : NULL;
}
EXPORT_SYMBOL_GPL(cgroup_next_descendant_post);

void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
__acquires(css_set_lock)
{
Expand Down

0 comments on commit b5ebc79

Please sign in to comment.