提交 e550a9b1 编写于 作者: Y Yu Kuai 提交者: Yang Yingliang

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 e70feb8b ("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: NYu Kuai <yukuai3@huawei.com>
Reviewed-by: NHou Tao <houtao1@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 d6784b9f
...@@ -812,7 +812,7 @@ void blk_cleanup_queue(struct request_queue *q) ...@@ -812,7 +812,7 @@ void blk_cleanup_queue(struct request_queue *q)
*/ */
if (q->mq_ops && (blk_queue_init_done(q) || if (q->mq_ops && (blk_queue_init_done(q) ||
test_bit(QUEUE_FLAG_FORECE_QUIESCE, &q->queue_flags))) 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 */ /* for synchronous bio-based driver finish in-flight integrity i/o */
blk_flush_integrity(); blk_flush_integrity();
......
...@@ -3125,7 +3125,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr) ...@@ -3125,7 +3125,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
return -EINVAL; return -EINVAL;
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
blk_mq_quiesce_queue(q); blk_mq_quiesce_queue_internal(q);
ret = 0; ret = 0;
queue_for_each_hw_ctx(q, hctx, i) { 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) ...@@ -3151,7 +3151,7 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
if (!ret) if (!ret)
q->nr_requests = nr; q->nr_requests = nr;
blk_mq_unquiesce_queue(q); blk_mq_unquiesce_queue_internal(q);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
return ret; return ret;
......
...@@ -461,7 +461,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page, ...@@ -461,7 +461,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page,
*/ */
if (q->mq_ops) { if (q->mq_ops) {
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
blk_mq_quiesce_queue(q); blk_mq_quiesce_queue_internal(q);
} else } else
blk_queue_bypass_start(q); blk_queue_bypass_start(q);
...@@ -469,7 +469,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page, ...@@ -469,7 +469,7 @@ static ssize_t queue_wb_lat_store(struct request_queue *q, const char *page,
wbt_update_limits(q); wbt_update_limits(q);
if (q->mq_ops) { if (q->mq_ops) {
blk_mq_unquiesce_queue(q); blk_mq_unquiesce_queue_internal(q);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
} else } else
blk_queue_bypass_end(q); blk_queue_bypass_end(q);
......
...@@ -1021,11 +1021,11 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) ...@@ -1021,11 +1021,11 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
if (q->mq_ops) { if (q->mq_ops) {
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
blk_mq_quiesce_queue(q); blk_mq_quiesce_queue_internal(q);
err = elevator_switch_mq(q, new_e); err = elevator_switch_mq(q, new_e);
blk_mq_unquiesce_queue(q); blk_mq_unquiesce_queue_internal(q);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
return err; return err;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册