diff options
-rw-r--r-- | block/blk-cgroup.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index d8fe607138b9..935028912e7a 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -114,8 +114,10 @@ static bool blkcg_policy_enabled(struct gendisk *disk, return pol && test_bit(pol->plid, disk->blkcg_pols); } -static void blkg_free(struct blkcg_gq *blkg) +static void blkg_free_workfn(struct work_struct *work) { + struct blkcg_gq *blkg = container_of(work, struct blkcg_gq, + free_work); int i; /* @@ -140,9 +142,23 @@ static void blkg_free(struct blkcg_gq *blkg) kfree(blkg); } -static void blkg_free_workfn(struct work_struct *work) +/** + * blkg_free - free a blkg + * @blkg: blkg to free + * + * Free @blkg which may be partially allocated. + */ +static void blkg_free(struct blkcg_gq *blkg) { - blkg_free(container_of(work, struct blkcg_gq, free_work)); + if (!blkg) + return; + + /* + * Both ->pd_free_fn() and request queue's release handler may + * sleep, so free us by scheduling one work func + */ + INIT_WORK(&blkg->free_work, blkg_free_workfn); + schedule_work(&blkg->free_work); } static void __blkg_release(struct rcu_head *rcu) @@ -153,10 +169,7 @@ static void __blkg_release(struct rcu_head *rcu) /* release the blkcg and parent blkg refs this blkg has been holding */ css_put(&blkg->blkcg->css); - - /* ->pd_free_fn() may sleep, so free from a work queue */ - INIT_WORK(&blkg->free_work, blkg_free_workfn); - schedule_work(&blkg->free_work); + blkg_free(blkg); } /* |