blkg_free() may be called in atomic context, either spin lock is held, or run in rcu callback. Meantime either request queue's release handler or ->pd_free_fn can sleep. Fix the issue by scheduling work function for freeing blkcg_gq instance. Cc: Tejun Heo <tj@xxxxxxxxxx> Fixes: 0a9a25ca7843 ("block: let blkcg_gq grab request queue's refcnt") Reported-by: Christoph Hellwig <hch@xxxxxx> Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- block/blk-cgroup.c | 14 +++++++++++++- include/linux/blk-cgroup.h | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index d53b0d69dd73..89a976d3ab74 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -71,8 +71,10 @@ static bool blkcg_policy_enabled(struct request_queue *q, * * Free @blkg which may be partially allocated. */ -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; if (!blkg) @@ -89,6 +91,16 @@ static void blkg_free(struct blkcg_gq *blkg) kfree(blkg); } +static void blkg_free(struct blkcg_gq *blkg) +{ + /* + * 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) { struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head); diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index f2ad8ed8f777..652cd05b0924 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h @@ -95,7 +95,10 @@ struct blkcg_gq { spinlock_t async_bio_lock; struct bio_list async_bios; - struct work_struct async_bio_work; + union { + struct work_struct async_bio_work; + struct work_struct free_work; + }; atomic_t use_delay; atomic64_t delay_nsec; -- 2.31.1