Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / kernel / cgroup.c
index 4ca928d..e9ec642 100644 (file)
@@ -3016,7 +3016,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
        unsigned long flags = (unsigned long)key;
 
        if (flags & POLLHUP) {
-               remove_wait_queue_locked(event->wqh, &event->wait);
+               __remove_wait_queue(event->wqh, &event->wait);
                spin_lock(&cgrp->event_list_lock);
                list_del(&event->list);
                spin_unlock(&cgrp->event_list_lock);
@@ -4435,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;
@@ -4445,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;
@@ -4453,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)
@@ -4561,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))