blkcg: move refcnt to blkcg core
[linux-2.6-block.git] / block / blk-cgroup.c
index 14367499cfedf8fe6954ea2b48d0e695afb3874b..3b6a0e1265aaff4eb3c98a9a3e026aa38874202c 100644 (file)
@@ -463,6 +463,7 @@ static struct blkio_group *blkg_alloc(struct blkio_cgroup *blkcg,
        rcu_assign_pointer(blkg->q, q);
        blkg->blkcg = blkcg;
        blkg->plid = pol->plid;
+       blkg->refcnt = 1;
        cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
 
        /* alloc per-policy data */
@@ -633,6 +634,29 @@ void blkg_destroy_all(struct request_queue *q)
        }
 }
 
+static void blkg_rcu_free(struct rcu_head *rcu_head)
+{
+       blkg_free(container_of(rcu_head, struct blkio_group, rcu_head));
+}
+
+void __blkg_release(struct blkio_group *blkg)
+{
+       /* release the extra blkcg reference this blkg has been holding */
+       css_put(&blkg->blkcg->css);
+
+       /*
+        * A group is freed in rcu manner. But having an rcu lock does not
+        * mean that one can access all the fields of blkg and assume these
+        * are valid. For example, don't try to follow throtl_data and
+        * request queue links.
+        *
+        * Having a reference to blkg under an rcu allows acess to only
+        * values local to groups like group stats and group rate limits
+        */
+       call_rcu(&blkg->rcu_head, blkg_rcu_free);
+}
+EXPORT_SYMBOL_GPL(__blkg_release);
+
 static void blkio_reset_stats_cpu(struct blkio_group *blkg)
 {
        struct blkio_group_stats_cpu *stats_cpu;