[PATCH] block/blk-iocost: fix KCSAN data-race on iocg->cursor
Tao Cui <[email protected]> Fri, 31 Jul 2026 21:40:00 +0800
| Newsgroups | org.kernel.vger.cgroups,org.kernel.vger.linux-block,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Tao Cui <[email protected]> iocg->cursor is read in calc_vtime_cost_builtin() and written per-bio in ioc_rqos_throttle()/ioc_rqos_merge() without a lock, which trips KCSAN: BUG: KCSAN: data-race in calc_vtime_cost_builtin / ioc_rqos_throttle Found via KCSAN (null_blk + sustained IO under CONFIG_KCSAN). The races are intentional: cursor is a best-effort randio detector, so stale values only add minor cost-estimate noise. Mark the accesses with READ_ONCE()/WRITE_ONCE(), consistent with other racy iocost fields (active, inuse, abs_vdebt). Signed-off-by: Tao Cui <[email protected]> --- block/blk-iocost.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 8b2aeba2e1e3..ae0d34609144 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -2552,9 +2552,13 @@ static void calc_vtime_cost_builtin(struct bio *bio, struct ioc_gq *iocg, goto out; } - if (iocg->cursor) { - seek_pages = abs(bio->bi_iter.bi_sector - iocg->cursor); - seek_pages >>= IOC_SECT_TO_PAGE_SHIFT; + { + sector_t cursor = READ_ONCE(iocg->cursor); + + if (cursor) { + seek_pages = abs(bio->bi_iter.bi_sector - cursor); + seek_pages >>= IOC_SECT_TO_PAGE_SHIFT; + } } if (!is_merge) { @@ -2708,7 +2712,7 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio) if (!iocg_activate(iocg, &now)) return; - iocg->cursor = bio_end_sector(bio); + WRITE_ONCE(iocg->cursor, bio_end_sector(bio)); vtime = atomic64_read(&iocg->vtime); cost = adjust_inuse_and_calc_cost(iocg, vtime, abs_cost, &now); @@ -2797,8 +2801,8 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq, /* update cursor if backmerging into the request at the cursor */ if (blk_rq_pos(rq) < bio_end && - blk_rq_pos(rq) + blk_rq_sectors(rq) == iocg->cursor) - iocg->cursor = bio_end; + blk_rq_pos(rq) + blk_rq_sectors(rq) == READ_ONCE(iocg->cursor)) + WRITE_ONCE(iocg->cursor, bio_end); /* * Charge if there's enough vtime budget and the existing request has -- 2.43.0