linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
To: lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org,
	mhocko-AlSwsSmVLrQ@public.gmane.org,
	rjw-KKrjLPT3xs0@public.gmane.org
Cc: linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	fweisbec-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: [PATCH 3/9] cgroup: implement generic child / descendant walk macros
Date: Sat,  3 Nov 2012 01:38:29 -0700	[thread overview]
Message-ID: <1351931915-1701-4-git-send-email-tj@kernel.org> (raw)
In-Reply-To: <1351931915-1701-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Currently, cgroup doesn't provide any generic helper for walking a
given cgroup's children or descendants.  This patch adds the following
three macros.

* cgroup_for_each_child() - walk immediate children of a cgroup.

* cgroup_for_each_descendant_pre() - visit all descendants of a cgroup
  in pre-order tree traversal.

* cgroup_for_each_descendant_post() - visit all descendants of a
  cgroup in post-order tree traversal.

All three only require the user to hold RCU read lock during
traversal.  Verifying that each iterated cgroup is online is the
responsibility of the user.  When used with proper synchronization,
cgroup_for_each_descendant_pre() can be used to propagate config
updates to descendants in reliable way.  See comments for details.

Signed-off-by: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 include/linux/cgroup.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/cgroup.c        | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 90c33eb..0020329 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -534,6 +534,88 @@ 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
+ * configuration of its ancestors.
+ *
+ * my_post_create(@cgrp)
+ * {
+ *	Lock @cgrp->parent and @cgrp;
+ *	Inherit config from @cgrp->parent;
+ *	Unlock both.
+ * }
+ *
+ * my_update_config(@cgrp)
+ * {
+ *	Lock @cgrp;
+ *	Update @cgrp's config;
+ *	Unlock @cgrp;
+ *
+ *	cgroup_for_each_descendant_pre(@pos, @cgrp) {
+ *		Lock @pos;
+ *		Verify @pos is alive and inherit config from @pos->parent;
+ *		Unlock @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;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index cc5d2a0..8bd662c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2985,6 +2985,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)
 {
-- 
1.7.11.7

  parent reply	other threads:[~2012-11-03  8:38 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-03  8:38 [PATCHSET cgroup/for-3.8] cgroup_freezer: implement proper hierarchy support Tejun Heo
     [not found] ` <1351931915-1701-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-03  8:38   ` [PATCH 1/9] cgroup: add cgroup_subsys->post_create() Tejun Heo
     [not found]     ` <1351931915-1701-2-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-05 13:42       ` Glauber Costa
     [not found]         ` <5097C23B.3040808-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-11-05 18:02           ` [RFC] cgroup: deprecate clone_children Tejun Heo
     [not found]             ` <20121105180213.GB19354-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-05 19:17               ` Serge Hallyn
2012-11-05 19:26                 ` Tejun Heo
2012-11-07 15:25       ` [PATCH 1/9] cgroup: add cgroup_subsys->post_create() Michal Hocko
     [not found]         ` <20121107152516.GA4131-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-07 17:02           ` Tejun Heo
2012-11-07 17:15       ` [PATCH 1/9 v2] " Tejun Heo
     [not found]         ` <20121107171508.GF2660-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-07 17:40           ` Michal Hocko
2012-11-08  2:59           ` Kamezawa Hiroyuki
2012-11-08 19:07     ` [PATCH 1/9 v3] " Tejun Heo
2012-11-09  9:09       ` Li Zefan
     [not found]       ` <20121108190715.GD9672-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-09  9:09         ` Li Zefan
2012-11-09 11:09         ` Daniel Wagner
     [not found]           ` <509CE472.9040504-kQCPcA+X3s7YtjvyW6yDsg@public.gmane.org>
2012-11-09 17:22             ` Tejun Heo
     [not found]               ` <20121109172211.GB2711-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-10  1:35                 ` Glauber Costa
2012-11-12 13:04               ` Daniel Wagner
2012-11-03  8:38   ` [PATCH 2/9] cgroup: Use rculist ops for cgroup->children Tejun Heo
2012-11-07 15:30     ` Michal Hocko
     [not found]     ` <1351931915-1701-3-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  3:01       ` Kamezawa Hiroyuki
2012-11-09  9:10       ` Li Zefan
2012-11-03  8:38   ` Tejun Heo [this message]
2012-11-06 20:31     ` [PATCH 3/9] cgroup: implement generic child / descendant walk macros Tejun Heo
     [not found]       ` <20121106203154.GV30069-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-07 15:38         ` Michal Hocko
2012-11-07 16:54     ` Michal Hocko
     [not found]       ` <20121107165457.GD4131-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-07 17:01         ` Tejun Heo
     [not found]           ` <20121107170118.GD2660-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-07 17:49             ` Michal Hocko
     [not found]     ` <1351931915-1701-4-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  3:21       ` Kamezawa Hiroyuki
2012-11-08  9:50       ` Michal Hocko
2012-11-08 17:15         ` Tejun Heo
2012-11-08 17:59     ` [PATCH 3/9 v2] " Tejun Heo
     [not found]       ` <20121108175946.GA9672-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-09  9:13         ` Li Zefan
2012-11-03  8:38   ` [PATCH 4/9] cgroup_freezer: trivial cleanups Tejun Heo
     [not found]     ` <1351931915-1701-5-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  3:24       ` Kamezawa Hiroyuki
2012-11-08  9:53       ` Michal Hocko
2012-11-03  8:38   ` [PATCH 5/9] cgroup_freezer: prepare freezer_change_state() for full hierarchy support Tejun Heo
     [not found]     ` <1351931915-1701-6-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  4:25       ` Kamezawa Hiroyuki
2012-11-08  9:56     ` Michal Hocko
2012-11-03  8:38   ` [PATCH 6/9] cgroup_freezer: make freezer->state mask of flags Tejun Heo
     [not found]     ` <1351931915-1701-7-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  4:37       ` Kamezawa Hiroyuki
     [not found]         ` <509B371E.9050005-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
2012-11-08  4:42           ` Tejun Heo
     [not found]             ` <20121108044255.GG2660-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-08  5:00               ` Kamezawa Hiroyuki
2012-11-08 14:38                 ` Tejun Heo
2012-11-08 10:39       ` Michal Hocko
     [not found]         ` <20121108103928.GD31821-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-08 14:39           ` Tejun Heo
     [not found]             ` <20121108143952.GD12973-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-08 14:47               ` Michal Hocko
2012-11-03  8:38   ` [PATCH 7/9] cgroup_freezer: introduce CGROUP_FREEZING_[SELF|PARENT] Tejun Heo
     [not found]     ` <1351931915-1701-8-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  4:42       ` Kamezawa Hiroyuki
     [not found]         ` <509B382E.4030707-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
2012-11-08  4:45           ` Tejun Heo
2012-11-08  4:56             ` Kamezawa Hiroyuki
     [not found]               ` <509B3B94.1070407-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
2012-11-08 14:41                 ` Tejun Heo
2012-11-08 12:47     ` Michal Hocko
2012-11-08 14:42       ` Tejun Heo
2012-11-03  8:38   ` [PATCH 8/9] cgroup_freezer: add ->post_create() and ->pre_destroy() and track online state Tejun Heo
     [not found]     ` <1351931915-1701-9-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-08  4:48       ` Kamezawa Hiroyuki
     [not found]         ` <509B3999.6060505-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
2012-11-08 15:41           ` Tejun Heo
2012-11-08 13:23     ` Michal Hocko
     [not found]       ` <20121108132306.GH31821-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-08 17:17         ` Tejun Heo
2012-11-03  8:38   ` [PATCH 9/9] cgroup_freezer: implement proper hierarchy support Tejun Heo
2012-11-07 11:00     ` Michal Hocko
2012-11-07 16:31       ` Tejun Heo
     [not found]     ` <1351931915-1701-10-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-11-07 16:39       ` [PATCH 9/9 v2] " Tejun Heo
     [not found]         ` <20121107163919.GC2660-9pTldWuhBndy/B6EtB590w@public.gmane.org>
2012-11-08 14:08           ` Michal Hocko
     [not found]             ` <20121108140852.GI31821-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-08 14:18               ` Tejun Heo
2012-11-08 15:20                 ` Michal Hocko
     [not found]                   ` <20121108152039.GL31821-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-08 15:29                     ` Tejun Heo
2012-11-08 15:57                       ` Michal Hocko
2012-11-08 17:57       ` [PATCH 9/9 v3] " Tejun Heo
     [not found]         ` <20121108175750.GK12973-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-08 18:02           ` Michal Hocko
     [not found]             ` <20121108180246.GA17415-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
2012-11-08 18:04               ` Tejun Heo
     [not found]                 ` <20121108180417.GC9672-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org>
2012-11-08 18:08                   ` Michal Hocko
2012-11-09 17:15   ` [PATCHSET cgroup/for-3.8] " Tejun Heo
2012-11-08 18:01 ` Tejun Heo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1351931915-1701-4-git-send-email-tj@kernel.org \
    --to=tj-dgejt+ai2ygdnm+yrofe0a@public.gmane.org \
    --cc=cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
    --cc=fweisbec-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-pm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org \
    --cc=mhocko-AlSwsSmVLrQ@public.gmane.org \
    --cc=rjw-KKrjLPT3xs0@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).