Skip to content

Commit 9d179b8

Browse files
htejunaxboe
authored andcommitted
blkcg: Fix multiple bugs in blkcg_activate_policy()
blkcg_activate_policy() has the following bugs. * cf09a8e ("blkcg: pass @q and @blkcg into blkcg_pol_alloc_pd_fn()") added @blkcg to ->pd_alloc_fn(); however, blkcg_activate_policy() ends up using pd's allocated for the root blkcg for all preallocations, so ->pd_init_fn() for non-root blkcgs can be passed in pd's which are allocated for the root blkcg. For blk-iocost, this means that ->pd_init_fn() can write beyond the end of the allocated object as it determines the length of the flex array at the end based on the blkcg's nesting level. * Each pd is initialized as they get allocated. If alloc fails, the policy will get freed with pd's initialized on it. * After the above partial failure, the partial pds are not freed. This patch fixes all the above issues by * Restructuring blkcg_activate_policy() so that alloc and init passes are separate. Init takes place only after all allocs succeeded and on failure all allocated pds are freed. * Unifying and fixing the cleanup of the remaining pd_prealloc. Signed-off-by: Tejun Heo <[email protected]> Fixes: cf09a8e ("blkcg: pass @q and @blkcg into blkcg_pol_alloc_pd_fn()") Signed-off-by: Jens Axboe <[email protected]>
1 parent 5da0fb1 commit 9d179b8

File tree

1 file changed

+51
-18
lines changed

1 file changed

+51
-18
lines changed

block/blk-cgroup.c

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,57 +1362,90 @@ int blkcg_activate_policy(struct request_queue *q,
13621362
const struct blkcg_policy *pol)
13631363
{
13641364
struct blkg_policy_data *pd_prealloc = NULL;
1365-
struct blkcg_gq *blkg;
1365+
struct blkcg_gq *blkg, *pinned_blkg = NULL;
13661366
int ret;
13671367

13681368
if (blkcg_policy_enabled(q, pol))
13691369
return 0;
13701370

13711371
if (queue_is_mq(q))
13721372
blk_mq_freeze_queue(q);
1373-
pd_prealloc:
1374-
if (!pd_prealloc) {
1375-
pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q, &blkcg_root);
1376-
if (!pd_prealloc) {
1377-
ret = -ENOMEM;
1378-
goto out_bypass_end;
1379-
}
1380-
}
1381-
1373+
retry:
13821374
spin_lock_irq(&q->queue_lock);
13831375

1384-
/* blkg_list is pushed at the head, reverse walk to init parents first */
1376+
/* blkg_list is pushed at the head, reverse walk to allocate parents first */
13851377
list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) {
13861378
struct blkg_policy_data *pd;
13871379

13881380
if (blkg->pd[pol->plid])
13891381
continue;
13901382

1391-
pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q, &blkcg_root);
1392-
if (!pd)
1393-
swap(pd, pd_prealloc);
1383+
/* If prealloc matches, use it; otherwise try GFP_NOWAIT */
1384+
if (blkg == pinned_blkg) {
1385+
pd = pd_prealloc;
1386+
pd_prealloc = NULL;
1387+
} else {
1388+
pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q,
1389+
blkg->blkcg);
1390+
}
1391+
13941392
if (!pd) {
1393+
/*
1394+
* GFP_NOWAIT failed. Free the existing one and
1395+
* prealloc for @blkg w/ GFP_KERNEL.
1396+
*/
1397+
if (pinned_blkg)
1398+
blkg_put(pinned_blkg);
1399+
blkg_get(blkg);
1400+
pinned_blkg = blkg;
1401+
13951402
spin_unlock_irq(&q->queue_lock);
1396-
goto pd_prealloc;
1403+
1404+
if (pd_prealloc)
1405+
pol->pd_free_fn(pd_prealloc);
1406+
pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q,
1407+
blkg->blkcg);
1408+
if (pd_prealloc)
1409+
goto retry;
1410+
else
1411+
goto enomem;
13971412
}
13981413

13991414
blkg->pd[pol->plid] = pd;
14001415
pd->blkg = blkg;
14011416
pd->plid = pol->plid;
1402-
if (pol->pd_init_fn)
1403-
pol->pd_init_fn(pd);
14041417
}
14051418

1419+
/* all allocated, init in the same order */
1420+
if (pol->pd_init_fn)
1421+
list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
1422+
pol->pd_init_fn(blkg->pd[pol->plid]);
1423+
14061424
__set_bit(pol->plid, q->blkcg_pols);
14071425
ret = 0;
14081426

14091427
spin_unlock_irq(&q->queue_lock);
1410-
out_bypass_end:
1428+
out:
14111429
if (queue_is_mq(q))
14121430
blk_mq_unfreeze_queue(q);
1431+
if (pinned_blkg)
1432+
blkg_put(pinned_blkg);
14131433
if (pd_prealloc)
14141434
pol->pd_free_fn(pd_prealloc);
14151435
return ret;
1436+
1437+
enomem:
1438+
/* alloc failed, nothing's initialized yet, free everything */
1439+
spin_lock_irq(&q->queue_lock);
1440+
list_for_each_entry(blkg, &q->blkg_list, q_node) {
1441+
if (blkg->pd[pol->plid]) {
1442+
pol->pd_free_fn(blkg->pd[pol->plid]);
1443+
blkg->pd[pol->plid] = NULL;
1444+
}
1445+
}
1446+
spin_unlock_irq(&q->queue_lock);
1447+
ret = -ENOMEM;
1448+
goto out;
14161449
}
14171450
EXPORT_SYMBOL_GPL(blkcg_activate_policy);
14181451

0 commit comments

Comments
 (0)