Merge tag 'char-misc-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-block.git] / block / blk-cgroup.c
index 9faafcd10e1775dd124a2b15e653e46ac2790847..4a42ea2972ad85693480c5e9c0e9599923c73ccf 100644 (file)
@@ -1511,7 +1511,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
 retry:
        spin_lock_irq(&q->queue_lock);
 
-       /* blkg_list is pushed at the head, reverse walk to allocate parents first */
+       /* blkg_list is pushed at the head, reverse walk to initialize parents first */
        list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) {
                struct blkg_policy_data *pd;
 
@@ -1549,21 +1549,20 @@ retry:
                                goto enomem;
                }
 
-               blkg->pd[pol->plid] = pd;
+               spin_lock(&blkg->blkcg->lock);
+
                pd->blkg = blkg;
                pd->plid = pol->plid;
-               pd->online = false;
-       }
+               blkg->pd[pol->plid] = pd;
 
-       /* all allocated, init in the same order */
-       if (pol->pd_init_fn)
-               list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
-                       pol->pd_init_fn(blkg->pd[pol->plid]);
+               if (pol->pd_init_fn)
+                       pol->pd_init_fn(pd);
 
-       list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) {
                if (pol->pd_online_fn)
-                       pol->pd_online_fn(blkg->pd[pol->plid]);
-               blkg->pd[pol->plid]->online = true;
+                       pol->pd_online_fn(pd);
+               pd->online = true;
+
+               spin_unlock(&blkg->blkcg->lock);
        }
 
        __set_bit(pol->plid, q->blkcg_pols);
@@ -1580,14 +1579,19 @@ out:
        return ret;
 
 enomem:
-       /* alloc failed, nothing's initialized yet, free everything */
+       /* alloc failed, take down everything */
        spin_lock_irq(&q->queue_lock);
        list_for_each_entry(blkg, &q->blkg_list, q_node) {
                struct blkcg *blkcg = blkg->blkcg;
+               struct blkg_policy_data *pd;
 
                spin_lock(&blkcg->lock);
-               if (blkg->pd[pol->plid]) {
-                       pol->pd_free_fn(blkg->pd[pol->plid]);
+               pd = blkg->pd[pol->plid];
+               if (pd) {
+                       if (pd->online && pol->pd_offline_fn)
+                               pol->pd_offline_fn(pd);
+                       pd->online = false;
+                       pol->pd_free_fn(pd);
                        blkg->pd[pol->plid] = NULL;
                }
                spin_unlock(&blkcg->lock);