]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - block/blk-cgroup.c
cgroup: unexport cgroup_css()
[mirror_ubuntu-artful-kernel.git] / block / blk-cgroup.c
index e8918ffaf96d4a0a2dacf75838b5d8a89e5e8ca3..54ad00292edf1b0385b94bfde5e71cb84253ff22 100644 (file)
@@ -32,26 +32,6 @@ EXPORT_SYMBOL_GPL(blkcg_root);
 
 static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
 
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
-                                     struct request_queue *q, bool update_hint);
-
-/**
- * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
- * @d_blkg: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
- * @p_blkg: target blkg to walk descendants of
- *
- * Walk @c_blkg through the descendants of @p_blkg.  Must be used with RCU
- * read locked.  If called under either blkcg or queue lock, the iteration
- * is guaranteed to include all and only online blkgs.  The caller may
- * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
- * subtree.
- */
-#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg)         \
-       cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
-               if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
-                                             (p_blkg)->q, false)))
-
 static bool blkcg_policy_enabled(struct request_queue *q,
                                 const struct blkcg_policy *pol)
 {
@@ -71,18 +51,8 @@ static void blkg_free(struct blkcg_gq *blkg)
        if (!blkg)
                return;
 
-       for (i = 0; i < BLKCG_MAX_POLS; i++) {
-               struct blkcg_policy *pol = blkcg_policy[i];
-               struct blkg_policy_data *pd = blkg->pd[i];
-
-               if (!pd)
-                       continue;
-
-               if (pol && pol->pd_exit_fn)
-                       pol->pd_exit_fn(blkg);
-
-               kfree(pd);
-       }
+       for (i = 0; i < BLKCG_MAX_POLS; i++)
+               kfree(blkg->pd[i]);
 
        blk_exit_rl(&blkg->rl);
        kfree(blkg);
@@ -134,10 +104,6 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
                blkg->pd[i] = pd;
                pd->blkg = blkg;
                pd->plid = i;
-
-               /* invoke per-policy init */
-               if (pol->pd_init_fn)
-                       pol->pd_init_fn(blkg);
        }
 
        return blkg;
@@ -158,8 +124,8 @@ err_free:
  * @q's bypass state.  If @update_hint is %true, the caller should be
  * holding @q->queue_lock and lookup hint is updated on success.
  */
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
-                                     struct request_queue *q, bool update_hint)
+struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, struct request_queue *q,
+                              bool update_hint)
 {
        struct blkcg_gq *blkg;
 
@@ -234,16 +200,25 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
        }
        blkg = new_blkg;
 
-       /* link parent and insert */
+       /* link parent */
        if (blkcg_parent(blkcg)) {
                blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
                if (WARN_ON_ONCE(!blkg->parent)) {
-                       blkg = ERR_PTR(-EINVAL);
+                       ret = -EINVAL;
                        goto err_put_css;
                }
                blkg_get(blkg->parent);
        }
 
+       /* invoke per-policy init */
+       for (i = 0; i < BLKCG_MAX_POLS; i++) {
+               struct blkcg_policy *pol = blkcg_policy[i];
+
+               if (blkg->pd[i] && pol->pd_init_fn)
+                       pol->pd_init_fn(blkg);
+       }
+
+       /* insert */
        spin_lock(&blkcg->lock);
        ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg);
        if (likely(!ret)) {
@@ -394,30 +369,38 @@ static void blkg_destroy_all(struct request_queue *q)
        q->root_rl.blkg = NULL;
 }
 
-static void blkg_rcu_free(struct rcu_head *rcu_head)
+/*
+ * A group is RCU protected, 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 accesses to only values
+ * local to groups like group stats and group rate limits.
+ */
+void __blkg_release_rcu(struct rcu_head *rcu_head)
 {
-       blkg_free(container_of(rcu_head, struct blkcg_gq, rcu_head));
-}
+       struct blkcg_gq *blkg = container_of(rcu_head, struct blkcg_gq, rcu_head);
+       int i;
+
+       /* tell policies that this one is being freed */
+       for (i = 0; i < BLKCG_MAX_POLS; i++) {
+               struct blkcg_policy *pol = blkcg_policy[i];
+
+               if (blkg->pd[i] && pol->pd_exit_fn)
+                       pol->pd_exit_fn(blkg);
+       }
 
-void __blkg_release(struct blkcg_gq *blkg)
-{
        /* release the blkcg and parent blkg refs this blkg has been holding */
        css_put(&blkg->blkcg->css);
-       if (blkg->parent)
+       if (blkg->parent) {
+               spin_lock_irq(blkg->q->queue_lock);
                blkg_put(blkg->parent);
+               spin_unlock_irq(blkg->q->queue_lock);
+       }
 
-       /*
-        * 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);
+       blkg_free(blkg);
 }
-EXPORT_SYMBOL_GPL(__blkg_release);
+EXPORT_SYMBOL_GPL(__blkg_release_rcu);
 
 /*
  * The next function used by blk_queue_for_each_rl().  It's a bit tricky
@@ -454,10 +437,10 @@ struct request_list *__blk_queue_next_rl(struct request_list *rl,
        return &blkg->rl;
 }
 
-static int blkcg_reset_stats(struct cgroup *cgroup, struct cftype *cftype,
-                            u64 val)
+static int blkcg_reset_stats(struct cgroup_subsys_state *css,
+                            struct cftype *cftype, u64 val)
 {
-       struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+       struct blkcg *blkcg = css_to_blkcg(css);
        struct blkcg_gq *blkg;
        int i;
 
@@ -631,7 +614,7 @@ u64 blkg_stat_recursive_sum(struct blkg_policy_data *pd, int off)
 {
        struct blkcg_policy *pol = blkcg_policy[pd->plid];
        struct blkcg_gq *pos_blkg;
-       struct cgroup *pos_cgrp;
+       struct cgroup_subsys_state *pos_css;
        u64 sum;
 
        lockdep_assert_held(pd->blkg->q->queue_lock);
@@ -639,7 +622,7 @@ u64 blkg_stat_recursive_sum(struct blkg_policy_data *pd, int off)
        sum = blkg_stat_read((void *)pd + off);
 
        rcu_read_lock();
-       blkg_for_each_descendant_pre(pos_blkg, pos_cgrp, pd_to_blkg(pd)) {
+       blkg_for_each_descendant_pre(pos_blkg, pos_css, pd_to_blkg(pd)) {
                struct blkg_policy_data *pos_pd = blkg_to_pd(pos_blkg, pol);
                struct blkg_stat *stat = (void *)pos_pd + off;
 
@@ -666,7 +649,7 @@ struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkg_policy_data *pd,
 {
        struct blkcg_policy *pol = blkcg_policy[pd->plid];
        struct blkcg_gq *pos_blkg;
-       struct cgroup *pos_cgrp;
+       struct cgroup_subsys_state *pos_css;
        struct blkg_rwstat sum;
        int i;
 
@@ -675,7 +658,7 @@ struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkg_policy_data *pd,
        sum = blkg_rwstat_read((void *)pd + off);
 
        rcu_read_lock();
-       blkg_for_each_descendant_pre(pos_blkg, pos_cgrp, pd_to_blkg(pd)) {
+       blkg_for_each_descendant_pre(pos_blkg, pos_css, pd_to_blkg(pd)) {
                struct blkg_policy_data *pos_pd = blkg_to_pd(pos_blkg, pol);
                struct blkg_rwstat *rwstat = (void *)pos_pd + off;
                struct blkg_rwstat tmp;
@@ -782,18 +765,18 @@ struct cftype blkcg_files[] = {
 
 /**
  * blkcg_css_offline - cgroup css_offline callback
- * @cgroup: cgroup of interest
+ * @css: css of interest
  *
- * This function is called when @cgroup is about to go away and responsible
- * for shooting down all blkgs associated with @cgroup.  blkgs should be
+ * This function is called when @css is about to go away and responsible
+ * for shooting down all blkgs associated with @css.  blkgs should be
  * removed while holding both q and blkcg locks.  As blkcg lock is nested
  * inside q lock, this function performs reverse double lock dancing.
  *
  * This is the blkcg counterpart of ioc_release_fn().
  */
-static void blkcg_css_offline(struct cgroup *cgroup)
+static void blkcg_css_offline(struct cgroup_subsys_state *css)
 {
-       struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+       struct blkcg *blkcg = css_to_blkcg(css);
 
        spin_lock_irq(&blkcg->lock);
 
@@ -815,21 +798,21 @@ static void blkcg_css_offline(struct cgroup *cgroup)
        spin_unlock_irq(&blkcg->lock);
 }
 
-static void blkcg_css_free(struct cgroup *cgroup)
+static void blkcg_css_free(struct cgroup_subsys_state *css)
 {
-       struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+       struct blkcg *blkcg = css_to_blkcg(css);
 
        if (blkcg != &blkcg_root)
                kfree(blkcg);
 }
 
-static struct cgroup_subsys_state *blkcg_css_alloc(struct cgroup *cgroup)
+static struct cgroup_subsys_state *
+blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
 {
        static atomic64_t id_seq = ATOMIC64_INIT(0);
        struct blkcg *blkcg;
-       struct cgroup *parent = cgroup->parent;
 
-       if (!parent) {
+       if (!parent_css) {
                blkcg = &blkcg_root;
                goto done;
        }
@@ -900,14 +883,15 @@ void blkcg_exit_queue(struct request_queue *q)
  * of the main cic data structures.  For now we allow a task to change
  * its cgroup only if it's the only owner of its ioc.
  */
-static int blkcg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static int blkcg_can_attach(struct cgroup_subsys_state *css,
+                           struct cgroup_taskset *tset)
 {
        struct task_struct *task;
        struct io_context *ioc;
        int ret = 0;
 
        /* task_lock() is needed to avoid races with exit_io_context() */
-       cgroup_taskset_for_each(task, cgrp, tset) {
+       cgroup_taskset_for_each(task, css, tset) {
                task_lock(task);
                ioc = task->io_context;
                if (ioc && atomic_read(&ioc->nr_tasks) > 1)
@@ -928,14 +912,6 @@ struct cgroup_subsys blkio_subsys = {
        .subsys_id = blkio_subsys_id,
        .base_cftypes = blkcg_files,
        .module = THIS_MODULE,
-
-       /*
-        * blkio subsystem is utterly broken in terms of hierarchy support.
-        * It treats all cgroups equally regardless of where they're
-        * located in the hierarchy - all cgroups are treated as if they're
-        * right below the root.  Fix it and remove the following.
-        */
-       .broken_hierarchy = true,
 };
 EXPORT_SYMBOL_GPL(blkio_subsys);
 
@@ -1152,7 +1128,7 @@ void blkcg_policy_unregister(struct blkcg_policy *pol)
 
        /* kill the intf files first */
        if (pol->cftypes)
-               cgroup_rm_cftypes(&blkio_subsys, pol->cftypes);
+               cgroup_rm_cftypes(pol->cftypes);
 
        /* unregister and update blkgs */
        blkcg_policy[pol->plid] = NULL;