From e4db6c1c1e08d50bfa203961e196f3e42b28c330 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Sat, 12 Jun 2021 09:08:49 +0800 Subject: [PATCH 2924/2944] alinux: use spin_lock_irqsave instead in ioc_rqos_throttle() fix #34995459 We encounter a hard lockup when running iocost testcase: [ 2409.519288] RIP: 0010:ioc_rqos_throttle+0x2d5/0x850 [ 2409.519289] Code: 00 00 48 89 84 24 98 00 00 00 48 89 5d 00 48 8b 74 24 10 4c 89 ff e8 2a c5 ff ff 41 c6 87 90 00 00 00 00 fb 66 0f 1f 44 00 00 <65> 48 8b 1c 25 c0 5b 01 00 48 c7 44 24 58 02 00 00 00 48 8b 44 24 [ 2409.519289] RSP: 0018:ffffbccf68e27670 EFLAGS: 00000286 ORIG_RAX: ffffffffffffffde [ 2409.519290] RAX: ffff9eb63f9dd3c0 RBX: ffffbccf68e27708 RCX: 00000000000006e0 [ 2409.519290] RDX: 00000000000af5df RSI: 0000000000000083 RDI: 0000000000000083 [ 2409.519290] RBP: ffff9eb634e15298 R08: 000002230f932079 R09: ffffbccf68e276f0 [ 2409.519291] R10: 0000000000315c6c R11: 000000000000ebb6 R12: ffff9e962cabe524 [ 2409.519291] R13: 0000000000324822 R14: ffff9eb634e15260 R15: ffff9eb634e15200 [ 2409.519291] rq_qos_throttle+0x31/0x40 [ 2409.519292] blk_queue_bio+0xb0/0x3d0 [ 2409.519292] generic_make_request+0x16f/0x350 [ 2409.519293] submit_bio+0x9e/0x170 [ 2409.519293] submit_bh_wbc+0x157/0x190 [ 2409.519294] ll_rw_block+0x6b/0xb0 [ 2409.519294] __breadahead+0x30/0x50 [ 2409.519294] __ext4_get_inode_loc+0x3dd/0x490 [ 2409.519294] __ext4_iget+0x104/0xd80 [ 2409.519295] ext4_lookup+0xb7/0x1c0 [ 2409.519296] __lookup_slow+0x80/0x130 [ 2409.519296] lookup_slow+0x35/0x50 [ 2409.519296] lookup_one_len_unlocked+0x40/0x50 [ 2409.519296] lookup_positive_unlocked+0xa/0x30 [ 2409.519297] ovl_lookup_single+0x2c/0x260 [overlay] [ 2409.519297] ovl_lookup_layer+0x115/0x170 [overlay] [ 2409.519297] ovl_lookup+0x213/0xa10 [overlay] [ 2409.519298] __lookup_slow+0x80/0x130 [ 2409.519299] lookup_slow+0x35/0x50 [ 2409.519299] walk_component+0x15e/0x280 [ 2409.519299] link_path_walk+0x181/0x500 [ 2409.519300] path_openat+0x95/0x240 [ 2409.519300] do_filp_open+0x7e/0xd0 [ 2409.519302] do_sys_openat2+0x1b6/0x260 [ 2409.519302] do_sys_open+0x4a/0x50 [ 2409.519302] do_syscall_64+0x5b/0x1b0 [ 2409.519303] entry_SYSCALL_64_after_hwframe+0x44/0xa9 This is because it locks q->queue_lock with spin_lock_irq in blk_queue_bio(), and then locks/unlocks iocg->waitq.lock with spin_lock_irq/spin_unlock_irq in rq_qos_throttle(). So use spin_lock_irqsave/spin_unlock_irqrestore primitives instead. Tested-by: Jeffle Xu Signed-off-by: Joseph Qi Acked-by: Xiaoguang Wang --- block/blk-iocost.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 896eb31..3d2b9f7 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1028,6 +1028,7 @@ static bool iocg_activate(struct ioc_gq *iocg, struct ioc_now *now) u64 last_period, cur_period, max_period_delta; u64 vtime, vmargin, vmin; int i; + unsigned long flags; /* * If seem to be already active, just update the stamp to tell the @@ -1045,7 +1046,7 @@ static bool iocg_activate(struct ioc_gq *iocg, struct ioc_now *now) if (iocg->child_active_sum) return false; - spin_lock_irq(&ioc->lock); + spin_lock_irqsave(&ioc->lock, flags); ioc_now(ioc, now); @@ -1103,11 +1104,11 @@ static bool iocg_activate(struct ioc_gq *iocg, struct ioc_now *now) } succeed_unlock: - spin_unlock_irq(&ioc->lock); + spin_unlock_irqrestore(&ioc->lock, flags); return true; fail_unlock: - spin_unlock_irq(&ioc->lock); + spin_unlock_irqrestore(&ioc->lock, flags); return false; } @@ -1732,6 +1733,7 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio, spinlock_t * struct iocg_wait wait; u32 hw_active, hw_inuse; u64 abs_cost, cost, vtime; + unsigned long flags; /* bypass IOs if disabled */ if (!ioc->enabled) @@ -1781,9 +1783,9 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio, spinlock_t * time_after_eq64(vtime + ioc->inuse_margin_vtime, now.vnow)) { TRACE_IOCG_PATH(inuse_reset, iocg, &now, iocg->inuse, iocg->weight, hw_inuse, hw_active); - spin_lock_irq(&ioc->lock); + spin_lock_irqsave(&ioc->lock, flags); propagate_active_weight(iocg, iocg->weight, iocg->weight); - spin_unlock_irq(&ioc->lock); + spin_unlock_irqrestore(&ioc->lock, flags); current_hweight(iocg, &hw_active, &hw_inuse); } @@ -1806,10 +1808,10 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio, spinlock_t * * as we're waiting or has debt, so we're good if we're activated * here. In the unlikely case that we aren't, just issue the IO. */ - spin_lock_irq(&iocg->waitq.lock); + spin_lock_irqsave(&iocg->waitq.lock, flags); if (unlikely(list_empty(&iocg->active_list))) { - spin_unlock_irq(&iocg->waitq.lock); + spin_unlock_irqrestore(&iocg->waitq.lock, flags); iocg_commit_bio(iocg, bio, cost); return; } @@ -1836,7 +1838,7 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio, spinlock_t * if (iocg_kick_delay(iocg, &now)) blkcg_schedule_throttle(rqos->q, (bio->bi_opf & REQ_SWAP) == REQ_SWAP); - spin_unlock_irq(&iocg->waitq.lock); + spin_unlock_irqrestore(&iocg->waitq.lock, flags); return; } @@ -1862,7 +1864,7 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio, spinlock_t * __add_wait_queue_entry_tail(&iocg->waitq, &wait.wait); iocg_kick_waitq(iocg, &now); - spin_unlock_irq(&iocg->waitq.lock); + spin_unlock_irqrestore(&iocg->waitq.lock, flags); while (true) { set_current_state(TASK_UNINTERRUPTIBLE); -- 1.8.3.1