aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-05-14 16:52:31 -0400
committerTejun Heo <tj@kernel.org>2013-05-14 16:52:31 -0400
commitdb61367038dcd222476881cb09fd54661b3cd508 (patch)
tree2c13a848bc64d34175ab7abbd0774b816a41f20e /block/blk-cgroup.c
parentaa539cb38f4f1365ad52fed6a857b25f8b4dc06c (diff)
blkcg: invoke blkcg_policy->pd_init() after parent is linked
Currently, when creating a new blkcg_gq, each policy's pd_init_fn() is invoked in blkg_alloc() before the parent is linked. This makes it difficult for policies to perform initializations which are dependent on the parent. This patch moves pd_init_fn() invocations to blkg_create() after the parent blkg is linked where the new blkg is fully initialized. As this means that blkg_free() can't assume that pd's are initialized, pd_exit_fn() invocations are moved to __blkg_release(). This guarantees that pd_exit_fn() is also invoked with fully initialized blkgs with valid parent pointers. This will help implementing hierarchy support in blk-throttle. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Vivek Goyal <vgoyal@redhat.com>
Diffstat (limited to 'block/blk-cgroup.c')
-rw-r--r--block/blk-cgroup.c39
1 files changed, 22 insertions, 17 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index b950306838ad..6bbe0a939596 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -51,18 +51,8 @@ static void blkg_free(struct blkcg_gq *blkg)
51 if (!blkg) 51 if (!blkg)
52 return; 52 return;
53 53
54 for (i = 0; i < BLKCG_MAX_POLS; i++) { 54 for (i = 0; i < BLKCG_MAX_POLS; i++)
55 struct blkcg_policy *pol = blkcg_policy[i]; 55 kfree(blkg->pd[i]);
56 struct blkg_policy_data *pd = blkg->pd[i];
57
58 if (!pd)
59 continue;
60
61 if (pol && pol->pd_exit_fn)
62 pol->pd_exit_fn(blkg);
63
64 kfree(pd);
65 }
66 56
67 blk_exit_rl(&blkg->rl); 57 blk_exit_rl(&blkg->rl);
68 kfree(blkg); 58 kfree(blkg);
@@ -114,10 +104,6 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
114 blkg->pd[i] = pd; 104 blkg->pd[i] = pd;
115 pd->blkg = blkg; 105 pd->blkg = blkg;
116 pd->plid = i; 106 pd->plid = i;
117
118 /* invoke per-policy init */
119 if (pol->pd_init_fn)
120 pol->pd_init_fn(blkg);
121 } 107 }
122 108
123 return blkg; 109 return blkg;
@@ -214,7 +200,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
214 } 200 }
215 blkg = new_blkg; 201 blkg = new_blkg;
216 202
217 /* link parent and insert */ 203 /* link parent */
218 if (blkcg_parent(blkcg)) { 204 if (blkcg_parent(blkcg)) {
219 blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false); 205 blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
220 if (WARN_ON_ONCE(!blkg->parent)) { 206 if (WARN_ON_ONCE(!blkg->parent)) {
@@ -224,6 +210,15 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
224 blkg_get(blkg->parent); 210 blkg_get(blkg->parent);
225 } 211 }
226 212
213 /* invoke per-policy init */
214 for (i = 0; i < BLKCG_MAX_POLS; i++) {
215 struct blkcg_policy *pol = blkcg_policy[i];
216
217 if (blkg->pd[i] && pol->pd_init_fn)
218 pol->pd_init_fn(blkg);
219 }
220
221 /* insert */
227 spin_lock(&blkcg->lock); 222 spin_lock(&blkcg->lock);
228 ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg); 223 ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg);
229 if (likely(!ret)) { 224 if (likely(!ret)) {
@@ -381,6 +376,16 @@ static void blkg_rcu_free(struct rcu_head *rcu_head)
381 376
382void __blkg_release(struct blkcg_gq *blkg) 377void __blkg_release(struct blkcg_gq *blkg)
383{ 378{
379 int i;
380
381 /* tell policies that this one is being freed */
382 for (i = 0; i < BLKCG_MAX_POLS; i++) {
383 struct blkcg_policy *pol = blkcg_policy[i];
384
385 if (blkg->pd[i] && pol->pd_exit_fn)
386 pol->pd_exit_fn(blkg);
387 }
388
384 /* release the blkcg and parent blkg refs this blkg has been holding */ 389 /* release the blkcg and parent blkg refs this blkg has been holding */
385 css_put(&blkg->blkcg->css); 390 css_put(&blkg->blkcg->css);
386 if (blkg->parent) 391 if (blkg->parent)