blk-cgroup: keep the old blkg while reassociating a bio

bio_associate_blkg_from_css() drops the bio's old blkg before it looks up
the new one through the css. The css is pinned by the blkg, not by the
bio, so if the cgroup is gone the bio may hold the last reference and the
blkcg can be freed under blkg_tryget_closest(). The rcu_read_lock()
around the whole thing used to cover that, until commit 457d3c4f0f
dropped it.

Put the old blkg after the new one has been looked up.

Fixes: 457d3c4f0f ("blk-cgroup: don't nest queue_lock under rcu in bio_associate_blkg()")
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Tejun Heo <tj@kernel.org>
Link: https://patch.msgid.link/20261028164415.1262013-2-axboe@kernel.dk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Josef Bacik 2026-10-28 10:41:04 -06:00 committed by Jens Axboe
parent 21b88cc8ba
commit 0e1daaf9b2

View File

@ -2139,8 +2139,7 @@ static inline struct blkcg_gq *blkg_tryget_closest(struct bio *bio,
void bio_associate_blkg_from_css(struct bio *bio,
struct cgroup_subsys_state *css)
{
if (bio->bi_blkg)
blkg_put(bio->bi_blkg);
struct blkcg_gq *old_blkg = bio->bi_blkg;
if (css && css->parent) {
bio->bi_blkg = blkg_tryget_closest(bio, css);
@ -2148,6 +2147,10 @@ void bio_associate_blkg_from_css(struct bio *bio,
blkg_get(bdev_get_queue(bio->bi_bdev)->root_blkg);
bio->bi_blkg = bdev_get_queue(bio->bi_bdev)->root_blkg;
}
/* @old_blkg may be the only thing which pins @css */
if (old_blkg)
blkg_put(old_blkg);
}
EXPORT_SYMBOL_GPL(bio_associate_blkg_from_css);