aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-11-20 15:55:52 -0500
committerTejun Heo <tj@kernel.org>2015-11-20 15:55:52 -0500
commitb11cfb5807e30333b36c02701382b820b7dcf0d5 (patch)
treeaaa95e1c7d936e722fd3d9f9cbf72fe1b0890787
parent8005c49d9aea74d382f474ce11afbbc7d7130bec (diff)
cgroup: record ancestor IDs and reimplement cgroup_is_descendant() using it
cgroup_is_descendant() currently walks up the hierarchy and compares each ancestor to the cgroup in question. While enough for cgroup core usages, this can't be used in hot paths to test cgroup membership. This patch adds cgroup->ancestor_ids[] which records the IDs of all ancestors including self and cgroup->level for the nesting level. This allows testing whether a given cgroup is a descendant of another in three finite steps - testing whether the two belong to the same hierarchy, whether the descendant candidate is at the same or a higher level than the ancestor and comparing the recorded ancestor_id at the matching level. cgroup_is_descendant() is accordingly reimplmented and made inline. Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--include/linux/cgroup-defs.h14
-rw-r--r--include/linux/cgroup.h18
-rw-r--r--kernel/cgroup.c32
3 files changed, 41 insertions, 23 deletions
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 60d44b26276d..504d8591b6d3 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -235,6 +235,14 @@ struct cgroup {
235 int id; 235 int id;
236 236
237 /* 237 /*
238 * The depth this cgroup is at. The root is at depth zero and each
239 * step down the hierarchy increments the level. This along with
240 * ancestor_ids[] can determine whether a given cgroup is a
241 * descendant of another without traversing the hierarchy.
242 */
243 int level;
244
245 /*
238 * Each non-empty css_set associated with this cgroup contributes 246 * Each non-empty css_set associated with this cgroup contributes
239 * one to populated_cnt. All children with non-zero popuplated_cnt 247 * one to populated_cnt. All children with non-zero popuplated_cnt
240 * of their own contribute one. The count is zero iff there's no 248 * of their own contribute one. The count is zero iff there's no
@@ -289,6 +297,9 @@ struct cgroup {
289 297
290 /* used to schedule release agent */ 298 /* used to schedule release agent */
291 struct work_struct release_agent_work; 299 struct work_struct release_agent_work;
300
301 /* ids of the ancestors at each level including self */
302 int ancestor_ids[];
292}; 303};
293 304
294/* 305/*
@@ -308,6 +319,9 @@ struct cgroup_root {
308 /* The root cgroup. Root is destroyed on its release. */ 319 /* The root cgroup. Root is destroyed on its release. */
309 struct cgroup cgrp; 320 struct cgroup cgrp;
310 321
322 /* for cgrp->ancestor_ids[0] */
323 int cgrp_ancestor_id_storage;
324
311 /* Number of cgroups in the hierarchy, used only for /proc/cgroups */ 325 /* Number of cgroups in the hierarchy, used only for /proc/cgroups */
312 atomic_t nr_cgrps; 326 atomic_t nr_cgrps;
313 327
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 22e3754f89c5..b5ee2c4210f9 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -81,7 +81,6 @@ struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgroup,
81struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry, 81struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
82 struct cgroup_subsys *ss); 82 struct cgroup_subsys *ss);
83 83
84bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
85int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); 84int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
86int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); 85int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
87 86
@@ -459,6 +458,23 @@ static inline struct cgroup *task_cgroup(struct task_struct *task,
459 return task_css(task, subsys_id)->cgroup; 458 return task_css(task, subsys_id)->cgroup;
460} 459}
461 460
461/**
462 * cgroup_is_descendant - test ancestry
463 * @cgrp: the cgroup to be tested
464 * @ancestor: possible ancestor of @cgrp
465 *
466 * Test whether @cgrp is a descendant of @ancestor. It also returns %true
467 * if @cgrp == @ancestor. This function is safe to call as long as @cgrp
468 * and @ancestor are accessible.
469 */
470static inline bool cgroup_is_descendant(struct cgroup *cgrp,
471 struct cgroup *ancestor)
472{
473 if (cgrp->root != ancestor->root || cgrp->level < ancestor->level)
474 return false;
475 return cgrp->ancestor_ids[ancestor->level] == ancestor->id;
476}
477
462/* no synchronization, the result can only be used as a hint */ 478/* no synchronization, the result can only be used as a hint */
463static inline bool cgroup_is_populated(struct cgroup *cgrp) 479static inline bool cgroup_is_populated(struct cgroup *cgrp)
464{ 480{
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f1603c153890..3190040792c8 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -459,25 +459,6 @@ struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
459} 459}
460EXPORT_SYMBOL_GPL(of_css); 460EXPORT_SYMBOL_GPL(of_css);
461 461
462/**
463 * cgroup_is_descendant - test ancestry
464 * @cgrp: the cgroup to be tested
465 * @ancestor: possible ancestor of @cgrp
466 *
467 * Test whether @cgrp is a descendant of @ancestor. It also returns %true
468 * if @cgrp == @ancestor. This function is safe to call as long as @cgrp
469 * and @ancestor are accessible.
470 */
471bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor)
472{
473 while (cgrp) {
474 if (cgrp == ancestor)
475 return true;
476 cgrp = cgroup_parent(cgrp);
477 }
478 return false;
479}
480
481static int notify_on_release(const struct cgroup *cgrp) 462static int notify_on_release(const struct cgroup *cgrp)
482{ 463{
483 return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); 464 return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -1903,6 +1884,7 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)
1903 if (ret < 0) 1884 if (ret < 0)
1904 goto out; 1885 goto out;
1905 root_cgrp->id = ret; 1886 root_cgrp->id = ret;
1887 root_cgrp->ancestor_ids[0] = ret;
1906 1888
1907 ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0, 1889 ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,
1908 GFP_KERNEL); 1890 GFP_KERNEL);
@@ -4846,11 +4828,11 @@ err_free_css:
4846static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, 4828static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
4847 umode_t mode) 4829 umode_t mode)
4848{ 4830{
4849 struct cgroup *parent, *cgrp; 4831 struct cgroup *parent, *cgrp, *tcgrp;
4850 struct cgroup_root *root; 4832 struct cgroup_root *root;
4851 struct cgroup_subsys *ss; 4833 struct cgroup_subsys *ss;
4852 struct kernfs_node *kn; 4834 struct kernfs_node *kn;
4853 int ssid, ret; 4835 int level, ssid, ret;
4854 4836
4855 /* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable. 4837 /* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
4856 */ 4838 */
@@ -4861,9 +4843,11 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
4861 if (!parent) 4843 if (!parent)
4862 return -ENODEV; 4844 return -ENODEV;
4863 root = parent->root; 4845 root = parent->root;
4846 level = parent->level + 1;
4864 4847
4865 /* allocate the cgroup and its ID, 0 is reserved for the root */ 4848 /* allocate the cgroup and its ID, 0 is reserved for the root */
4866 cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL); 4849 cgrp = kzalloc(sizeof(*cgrp) +
4850 sizeof(cgrp->ancestor_ids[0]) * (level + 1), GFP_KERNEL);
4867 if (!cgrp) { 4851 if (!cgrp) {
4868 ret = -ENOMEM; 4852 ret = -ENOMEM;
4869 goto out_unlock; 4853 goto out_unlock;
@@ -4887,6 +4871,10 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
4887 4871
4888 cgrp->self.parent = &parent->self; 4872 cgrp->self.parent = &parent->self;
4889 cgrp->root = root; 4873 cgrp->root = root;
4874 cgrp->level = level;
4875
4876 for (tcgrp = cgrp; tcgrp; tcgrp = cgroup_parent(tcgrp))
4877 cgrp->ancestor_ids[tcgrp->level] = tcgrp->id;
4890 4878
4891 if (notify_on_release(parent)) 4879 if (notify_on_release(parent))
4892 set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags); 4880 set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);