Skip to content

Commit 2a427b4

Browse files
htejunaxboe
authored andcommitted
blk-iocost: Fix an UBSAN shift-out-of-bounds warning
When iocg_kick_delay() is called from a CPU different than the one which set the delay, @now may be in the past of @iocg->delay_at leading to the following warning: UBSAN: shift-out-of-bounds in block/blk-iocost.c:1359:23 shift exponent 18446744073709 is too large for 64-bit type 'u64' (aka 'unsigned long long') ... Call Trace: <TASK> dump_stack_lvl+0x79/0xc0 __ubsan_handle_shift_out_of_bounds+0x2ab/0x300 iocg_kick_delay+0x222/0x230 ioc_rqos_merge+0x1d7/0x2c0 __rq_qos_merge+0x2c/0x80 bio_attempt_back_merge+0x83/0x190 blk_attempt_plug_merge+0x101/0x150 blk_mq_submit_bio+0x2b1/0x720 submit_bio_noacct_nocheck+0x320/0x3e0 __swap_writepage+0x2ab/0x9d0 The underflow itself doesn't really affect the behavior in any meaningful way; however, the past timestamp may exaggerate the delay amount calculated later in the code, which shouldn't be a material problem given the nature of the delay mechanism. If @now is in the past, this CPU is racing another CPU which recently set up the delay and there's nothing this CPU can contribute w.r.t. the delay. Let's bail early from iocg_kick_delay() in such cases. Reported-by: Breno Leitão <leitao@debian.org> Signed-off-by: Tejun Heo <tj@kernel.org> Fixes: 5160a5a ("blk-iocost: implement delay adjustment hysteresis") Link: https://lore.kernel.org/r/ZVvc9L_CYk5LO1fT@slm.duckdns.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent f814bdd commit 2a427b4

File tree

1 file changed

+7
-0
lines changed

1 file changed

+7
-0
lines changed

block/blk-iocost.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,13 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
13531353

13541354
lockdep_assert_held(&iocg->waitq.lock);
13551355

1356+
/*
1357+
* If the delay is set by another CPU, we may be in the past. No need to
1358+
* change anything if so. This avoids decay calculation underflow.
1359+
*/
1360+
if (time_before64(now->now, iocg->delay_at))
1361+
return false;
1362+
13561363
/* calculate the current delay in effect - 1/2 every second */
13571364
tdelta = now->now - iocg->delay_at;
13581365
if (iocg->delay)

0 commit comments

Comments
 (0)