From e808b3c219d4febc73a4ff5f6c2ef14f0f5397fd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 10 Sep 2019 09:15:25 -0700 Subject: [PATCH] blk-iocost: Fix incorrect operation order during iocg free commit e036c4cabaa8d24375262ced3a191819a8077b74 upstream. ioc_pd_free() first cancels the hrtimers and then deactivates the iocg. However, the iocg timer can run inbetween and reschedule the hrtimers which will end up running after the iocg is freed leading to crashes like the following. general protection fault: 0000 [#1] SMP ... RIP: 0010:iocg_kick_delay+0xbe/0x1b0 RSP: 0018:ffffc90003598ea0 EFLAGS: 00010046 RAX: 1cee00fd69512b54 RBX: ffff8881bba48400 RCX: 00000000000003e8 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8881bba48400 RBP: 0000000000004e20 R08: 0000000000000002 R09: 00000000000003e8 R10: 0000000000000000 R11: 0000000000000000 R12: ffffc90003598ef0 R13: 00979f3810ad461f R14: ffff8881bba4b400 R15: 25439f950d26e1d1 FS: 0000000000000000(0000) GS:ffff88885f800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f64328c7e40 CR3: 0000000002409005 CR4: 00000000003606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: iocg_delay_timer_fn+0x3d/0x60 __hrtimer_run_queues+0xfe/0x270 hrtimer_interrupt+0xf4/0x210 smp_apic_timer_interrupt+0x5e/0x120 apic_timer_interrupt+0xf/0x20 Fix it by canceling hrtimers after deactivating the iocg. Fixes: 7caa47151ab2 ("blkcg: implement blk-iocost") Reported-by: Dave Jones Signed-off-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Joseph Qi Signed-off-by: Jiufei Xue Reviewed-by: Joseph Qi --- block/blk-iocost.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 7bb43ca3666e..7867879467e2 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1957,15 +1957,15 @@ static void ioc_pd_free(struct blkg_policy_data *pd) struct ioc *ioc = iocg->ioc; if (ioc) { - hrtimer_cancel(&iocg->waitq_timer); - hrtimer_cancel(&iocg->delay_timer); - spin_lock(&ioc->lock); if (!list_empty(&iocg->active_list)) { propagate_active_weight(iocg, 0, 0); list_del_init(&iocg->active_list); } spin_unlock(&ioc->lock); + + hrtimer_cancel(&iocg->waitq_timer); + hrtimer_cancel(&iocg->delay_timer); } kfree(iocg); } -- GitLab