summaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-05-24 10:55:38 +0900
committerTejun Heo <tj@kernel.org>2013-05-24 10:55:38 +0900
commit75501a6d59e989e5c286716e5b3b66ace4660e83 (patch)
tree087af4f93bba2257ae139c5e4a0f3b850954ed81 /kernel/cgroup.c
parent53fa5261747a90746531e8a1c81eeb78fedc2f71 (diff)
downloadlinux-75501a6d59e989e5c286716e5b3b66ace4660e83.tar.gz
linux-75501a6d59e989e5c286716e5b3b66ace4660e83.tar.xz
cgroup: update iterators to use cgroup_next_sibling()
This patch converts cgroup_for_each_child(), cgroup_next_descendant_pre/post() and thus cgroup_for_each_descendant_pre/post() to use cgroup_next_sibling() instead of manually dereferencing ->sibling.next. The only reason the iterators couldn't allow dropping RCU read lock while iteration is in progress was because they couldn't determine the next sibling safely once RCU read lock is dropped. Using cgroup_next_sibling() removes that problem and enables all iterators to allow dropping RCU read lock in the middle. Comments are updated accordingly. This makes the iterators easier to use and will simplify controllers. Note that @cgroup argument is renamed to @cgrp in cgroup_for_each_child() because it conflicts with "struct cgroup" used in the new macro body. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com> Reviewed-by: Michal Hocko <mhocko@suse.cz>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index b87c7a5a5497..fefc41c1a147 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -3031,6 +3031,11 @@ EXPORT_SYMBOL_GPL(cgroup_next_sibling);
*
* To be used by cgroup_for_each_descendant_pre(). Find the next
* descendant to visit for pre-order traversal of @cgroup's descendants.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section. This
+ * function will return the correct next descendant as long as both @pos
+ * and @cgroup are accessible and @pos is a descendant of @cgroup.
*/
struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
struct cgroup *cgroup)
@@ -3050,11 +3055,9 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
/* no child, visit my or the closest ancestor's next sibling */
while (pos != cgroup) {
- next = list_entry_rcu(pos->sibling.next, struct cgroup,
- sibling);
- if (&next->sibling != &pos->parent->children)
+ next = cgroup_next_sibling(pos);
+ if (next)
return next;
-
pos = pos->parent;
}
@@ -3069,6 +3072,11 @@ EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);
* Return the rightmost descendant of @pos. If there's no descendant,
* @pos is returned. This can be used during pre-order traversal to skip
* subtree of @pos.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section. This
+ * function will return the correct rightmost descendant as long as @pos is
+ * accessible.
*/
struct cgroup *cgroup_rightmost_descendant(struct cgroup *pos)
{
@@ -3108,6 +3116,11 @@ static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
*
* To be used by cgroup_for_each_descendant_post(). Find the next
* descendant to visit for post-order traversal of @cgroup's descendants.
+ *
+ * While this function requires RCU read locking, it doesn't require the
+ * whole traversal to be contained in a single RCU critical section. This
+ * function will return the correct next descendant as long as both @pos
+ * and @cgroup are accessible and @pos is a descendant of @cgroup.
*/
struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
struct cgroup *cgroup)
@@ -3123,8 +3136,8 @@ struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
}
/* 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)
+ next = cgroup_next_sibling(pos);
+ if (next)
return cgroup_leftmost_descendant(next);
/* no sibling left, visit parent */