Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / kernel / cgroup.c
index 4a07d057a265f644ad73a56a7e02cac1def8cdce..e9ec642932eee62ec7f6a4c67e2503e921aebbb6 100644 (file)
@@ -1646,7 +1646,9 @@ static inline struct cftype *__d_cft(struct dentry *dentry)
 int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
 {
        char *start;
-       struct dentry *dentry = rcu_dereference(cgrp->dentry);
+       struct dentry *dentry = rcu_dereference_check(cgrp->dentry,
+                                                     rcu_read_lock_held() ||
+                                                     cgroup_lock_is_held());
 
        if (!dentry || cgrp == dummytop) {
                /*
@@ -1662,13 +1664,17 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
        *--start = '\0';
        for (;;) {
                int len = dentry->d_name.len;
+
                if ((start -= len) < buf)
                        return -ENAMETOOLONG;
-               memcpy(start, cgrp->dentry->d_name.name, len);
+               memcpy(start, dentry->d_name.name, len);
                cgrp = cgrp->parent;
                if (!cgrp)
                        break;
-               dentry = rcu_dereference(cgrp->dentry);
+
+               dentry = rcu_dereference_check(cgrp->dentry,
+                                              rcu_read_lock_held() ||
+                                              cgroup_lock_is_held());
                if (!cgrp->parent)
                        continue;
                if (--start < buf)
@@ -4429,7 +4435,15 @@ __setup("cgroup_disable=", cgroup_disable);
  */
 unsigned short css_id(struct cgroup_subsys_state *css)
 {
-       struct css_id *cssid = rcu_dereference(css->id);
+       struct css_id *cssid;
+
+       /*
+        * This css_id() can return correct value when somone has refcnt
+        * on this or this is under rcu_read_lock(). Once css->id is allocated,
+        * it's unchanged until freed.
+        */
+       cssid = rcu_dereference_check(css->id,
+                       rcu_read_lock_held() || atomic_read(&css->refcnt));
 
        if (cssid)
                return cssid->id;
@@ -4439,7 +4453,10 @@ EXPORT_SYMBOL_GPL(css_id);
 
 unsigned short css_depth(struct cgroup_subsys_state *css)
 {
-       struct css_id *cssid = rcu_dereference(css->id);
+       struct css_id *cssid;
+
+       cssid = rcu_dereference_check(css->id,
+                       rcu_read_lock_held() || atomic_read(&css->refcnt));
 
        if (cssid)
                return cssid->depth;
@@ -4447,15 +4464,36 @@ unsigned short css_depth(struct cgroup_subsys_state *css)
 }
 EXPORT_SYMBOL_GPL(css_depth);
 
+/**
+ *  css_is_ancestor - test "root" css is an ancestor of "child"
+ * @child: the css to be tested.
+ * @root: the css supporsed to be an ancestor of the child.
+ *
+ * Returns true if "root" is an ancestor of "child" in its hierarchy. Because
+ * this function reads css->id, this use rcu_dereference() and rcu_read_lock().
+ * But, considering usual usage, the csses should be valid objects after test.
+ * Assuming that the caller will do some action to the child if this returns
+ * returns true, the caller must take "child";s reference count.
+ * If "child" is valid object and this returns true, "root" is valid, too.
+ */
+
 bool css_is_ancestor(struct cgroup_subsys_state *child,
                    const struct cgroup_subsys_state *root)
 {
-       struct css_id *child_id = rcu_dereference(child->id);
-       struct css_id *root_id = rcu_dereference(root->id);
+       struct css_id *child_id;
+       struct css_id *root_id;
+       bool ret = true;
 
-       if (!child_id || !root_id || (child_id->depth < root_id->depth))
-               return false;
-       return child_id->stack[root_id->depth] == root_id->id;
+       rcu_read_lock();
+       child_id  = rcu_dereference(child->id);
+       root_id = rcu_dereference(root->id);
+       if (!child_id
+           || !root_id
+           || (child_id->depth < root_id->depth)
+           || (child_id->stack[root_id->depth] != root_id->id))
+               ret = false;
+       rcu_read_unlock();
+       return ret;
 }
 
 static void __free_css_id_cb(struct rcu_head *head)
@@ -4555,13 +4593,13 @@ static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
 {
        int subsys_id, i, depth = 0;
        struct cgroup_subsys_state *parent_css, *child_css;
-       struct css_id *child_id, *parent_id = NULL;
+       struct css_id *child_id, *parent_id;
 
        subsys_id = ss->subsys_id;
        parent_css = parent->subsys[subsys_id];
        child_css = child->subsys[subsys_id];
-       depth = css_depth(parent_css) + 1;
        parent_id = parent_css->id;
+       depth = parent_id->depth;
 
        child_id = get_new_cssid(ss, depth);
        if (IS_ERR(child_id))