blk-throttle: ignore cgroup without io queued in blk_throtl_cancel_bios
authorKemeng Shi <shikemeng@huawei.com>
Mon, 5 Dec 2022 11:57:03 +0000 (19:57 +0800)
committerJens Axboe <axboe@kernel.dk>
Mon, 5 Dec 2022 20:44:34 +0000 (13:44 -0700)
Ignore cgroup without io queued in blk_throtl_cancel_bios for two
reasons:
1. Save cpu cycle for trying to dispatch cgroup which is no io queued.
2. Avoid non-consistent state that cgroup is inserted to service queue
without THROTL_TG_PENDING set as tg_update_disptime will unconditional
re-insert cgroup to service queue. If we are on the default hierarchy,
IO dispatched from child in tg_dispatch_one_bio will trigger inserting
cgroup to service queue without erase first and ruin the tree.

Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Kemeng Shi <shikemeng@huawei.com>
Link: https://lore.kernel.org/r/20221205115709.251489-4-shikemeng@huaweicloud.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-throttle.c

index 2444ebf..7501011 100644 (file)
@@ -1738,7 +1738,18 @@ void blk_throtl_cancel_bios(struct gendisk *disk)
                 * Set the flag to make sure throtl_pending_timer_fn() won't
                 * stop until all throttled bios are dispatched.
                 */
-               blkg_to_tg(blkg)->flags |= THROTL_TG_CANCELING;
+               tg->flags |= THROTL_TG_CANCELING;
+
+               /*
+                * Do not dispatch cgroup without THROTL_TG_PENDING or cgroup
+                * will be inserted to service queue without THROTL_TG_PENDING
+                * set in tg_update_disptime below. Then IO dispatched from
+                * child in tg_dispatch_one_bio will trigger double insertion
+                * and corrupt the tree.
+                */
+               if (!(tg->flags & THROTL_TG_PENDING))
+                       continue;
+
                /*
                 * Update disptime after setting the above flag to make sure
                 * throtl_select_dispatch() won't exit without dispatching.