From e550a9b12fe8eb7fe3fe4ea0b4beeb0feae1100d Mon Sep 17 00:00:00 2001 From: Yu Kuai Date: Thu, 9 Dec 2021 20:56:51 +0800 Subject: [PATCH] blk-mq: use the new flag to quiesce/unquiesce queue in block layer hulk inclusion category: bugfix bugzilla: 173974 CVE: NA --------------------------- Our test report a null-ptr-def problem: [89470.197765] kasan: GPF could be caused by NULL-ptr deref or user memory access [89470.198896] general protection fault: 0000 [#1] SMP KASAN [89470.199706] CPU: 2 PID: 17722 Comm: kworker/u8:3 Not tainted 4.19.195-01446-gb2a62977d3e4 #1 [89470.200935] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 [89470.202247] Workqueue: nvme-reset-wq nvme_reset_work [89470.203009] RIP: 0010:kyber_has_work+0x60/0xf0 [89470.203665] Code: 8b a3 18 01 00 00 49 bd 00 00 00 00 00 fc ff df 49 8d 5c 24 08 49 8d 6c 24 48 49 83 c4 38 e8 27 1c 1a ff 48 89 d8 48 c1 e8 03 <42> 80 3c 28 00 75 68 48 3b 1b 75 50 e8 0f 1c 1a ff 48 8d 7b 08 48 [89470.206331] RSP: 0018:ffff888004c379c8 EFLAGS: 00010202 [89470.207096] RAX: 0000000000000001 RBX: 0000000000000008 RCX: ffffffffb5238989 [89470.208138] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff888101ff0be0 [89470.209206] RBP: 0000000000000048 R08: ffffed1020653380 R09: ffffed1020653380 [89470.210250] R10: 0000000000000001 R11: ffffed102065337f R12: 0000000000000038 [89470.211276] R13: dffffc0000000000 R14: 0000000000000000 R15: ffff888101ff0be8 [89470.220344] FS: 0000000000000000(0000) GS:ffff88810ed00000(0000) knlGS:0000000000000000 [89470.221184] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [89470.221775] CR2: 00007f70134c2770 CR3: 00000000b6e0e000 CR4: 00000000000006e0 [89470.222521] Call Trace: [89470.222811] ? kyber_read_lat_show+0x80/0x80 [89470.223223] blk_mq_run_hw_queue+0x26b/0x2f0 [89470.223631] blk_mq_run_hw_queues+0xe8/0x160 [89470.224064] nvme_start_queues+0x6c/0xb0 [89470.224460] nvme_start_ctrl+0x155/0x300 [89470.224864] ? down_read+0xf/0x80 [89470.225186] ? nvme_set_queue_count+0x1f0/0x1f0 [89470.225803] ? nvme_change_ctrl_state+0x83/0x2e0 [89470.226285] nvme_reset_work+0x2fd2/0x4ee0 [89470.226699] ? rb_erase_cached+0x8f8/0x19d0 [89470.227103] ? nvme_alloc_queue+0xbf0/0xbf0 [89470.227758] ? set_next_entity+0x248/0x730 [89470.228174] ? pick_next_entity+0x199/0x400 [89470.228592] ? put_prev_entity+0x4f/0x350 [89470.228976] ? pick_next_task_fair+0x7c9/0x1500 [89470.229424] ? account_entity_dequeue+0x30b/0x580 [89470.229874] ? dequeue_entity+0x29b/0xf70 [89470.230352] ? __switch_to+0x17b/0xb60 [89470.230936] ? compat_start_thread+0x80/0x80 [89470.231447] ? dequeue_task_fair+0xe4/0x1d60 [89470.231871] ? tty_ldisc_receive_buf+0xaa/0x170 [89470.232501] ? read_word_at_a_time+0xe/0x20 [89470.233195] ? strscpy+0x96/0x300 [89470.233761] process_one_work+0x706/0x1270 [89470.234438] worker_thread+0x91/0xc80 [89470.235038] ? process_one_work+0x1270/0x1270 [89470.235749] kthread+0x305/0x3c0 [89470.236292] ? kthread_park+0x1c0/0x1c0 [89470.236944] ret_from_fork+0x1f/0x30 [89470.237543] Modules linked in: [89470.238179] ---[ end trace 4ed415cdb7eafdd4 ]--- This is because blk_mq_quiesce_queue() is called concurently from driver and block layer: t1: driver t2: block layer blk_mq_quiesce_queue ... elevator_switch blk_mq_quiesce_queue elevator_exit blk_mq_unquiesce_queue blk_queue_flag_clear(QUEUE_FLAG_QUIESCED, q); blk_mq_run_hw_queue blk_queue_quiesced blk_mq_hctx_has_pending blk_mq_sched_has_work -> elevator is not ready Mainline fix this problem by commit e70feb8b3e68 ("blk-mq: support concurrent queue quiesce/unquiesce"), however this rely on the calls to quiesce and unquiesce queue to be balanced in all the drivers, which is hard to ensure considering out or tree modules. Fix the problem by using a separate flag for block layer, thus quiesce queue in block layer won't affect drivers. Signed-off-by: Yu Kuai Reviewed-by: Hou Tao Signed-off-by: Yang Yingliang --- block/blk-core.c | 2 +- block/blk-mq.c | 4 ++-- block/blk-sysfs.c | 4 ++-- block/elevator.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index bb4d3da762b1..41d0b09e9a67 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -812,7 +812,7 @@ void blk_cleanup_queue(struct request_queue *q) */ if (q->mq_ops && (blk_queue_init_done(q) || test_bit(QUEUE_FLAG_FORECE_QUIESCE, &q->queue_flags))) - blk_mq_quiesce_queue(q); + blk_mq_quiesce_queue_internal(q); /* for synchronous bio-based driver finish in-flight integrity i/o */ blk_flush_integrity(); diff --git a/block/blk-mq.c b/block/blk-mq.c index 8bf3da9b7178..0732bcc65f88 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -3125,7 +3125,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr) return -EINVAL; blk_mq_freeze_queue(q); - blk_mq_quiesce_queue(q); + blk_mq_quiesce_queue_internal(q); ret = 0; queue_for_each_hw_ctx(q, hctx, i) { @@ -3151,7 +3151,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr) if (!ret) q->nr_requests = nr; - blk_mq_unquiesce_queue(q); + blk_mq_unquiesce_queue_internal(q); blk_mq_unfreeze_queue(q); return ret; diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 4167f6a5c3f8..7ce092ab0f05 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -461,7 +461,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page, */ if (q->mq_ops) { blk_mq_freeze_queue(q); - blk_mq_quiesce_queue(q); + blk_mq_quiesce_queue_internal(q); } else blk_queue_bypass_start(q); @@ -469,7 +469,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page, wbt_update_limits(q); if (q->mq_ops) { - blk_mq_unquiesce_queue(q); + blk_mq_unquiesce_queue_internal(q); blk_mq_unfreeze_queue(q); } else blk_queue_bypass_end(q); diff --git a/block/elevator.c b/block/elevator.c index 34ff47fd913e..70ea9f3e64d7 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -1021,11 +1021,11 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) if (q->mq_ops) { blk_mq_freeze_queue(q); - blk_mq_quiesce_queue(q); + blk_mq_quiesce_queue_internal(q); err = elevator_switch_mq(q, new_e); - blk_mq_unquiesce_queue(q); + blk_mq_unquiesce_queue_internal(q); blk_mq_unfreeze_queue(q); return err; -- GitLab