mmc: block: bypass the queue even if usage is present for hotplug
The commit
304419d8a7e9 ("mmc: core: Allocate per-request data using the
block layer core") refactored mechanism of queue handling caused
mmc_init_request() can be called just after mmc_cleanup_queue() caused null
pointer dereference.
Another commit
bbdc74dc19e0 ("mmc: block: Prevent new req entering queue
after its cleanup") tried to fix the problem. However it actually miss one
corner case.
We could still reproduce the issue mentioned with these steps:
(1) insert a SD card and mount it
(2) hotplug it, so it will leave md->usage still be counted
(3) reboot the system which will sync data and umount the card
[Unable to handle kernel NULL pointer dereference at virtual address
00000000
[user pgtable: 4k pages, 48-bit VAs, pgd =
ffff80007bab3000
[[
0000000000000000] *pgd=
000000007a828003, *pud=
0000000078dce003,
*pmd=
000000007aab6003, *pte=
0000000000000000
[Internal error: Oops:
96000007 [#1] PREEMPT SMP
[Modules linked in:
[CPU: 3 PID: 3507 Comm: umount Tainted: G W
4.13.0-rc1-next-20170720-00012-g9d9bf45 #33
[Hardware name: Firefly-RK3399 Board (DT)
[task:
ffff80007a1de200 task.stack:
ffff80007a01c000
[PC is at mmc_init_request+0x14/0xc4
[LR is at alloc_request_size+0x4c/0x74
[pc : [<
ffff0000087d7150>] lr : [<
ffff000008378fe0>] pstate:
600001c5
[sp :
ffff80007a01f8f0
....
[[<
ffff0000087d7150>] mmc_init_request+0x14/0xc4
[[<
ffff000008378fe0>] alloc_request_size+0x4c/0x74
[[<
ffff00000817ac28>] mempool_create_node+0xb8/0x17c
[[<
ffff00000837aadc>] blk_init_rl+0x9c/0x120
[[<
ffff000008396580>] blkg_alloc+0x110/0x234
[[<
ffff000008396ac8>] blkg_create+0x424/0x468
[[<
ffff00000839877c>] blkg_lookup_create+0xd8/0x14c
[[<
ffff0000083796bc>] generic_make_request_checks+0x368/0x3b0
[[<
ffff00000837b050>] generic_make_request+0x1c/0x240
So mmc_blk_put wouldn't calling blk_cleanup_queue which actually the
QUEUE_FLAG_DYING and QUEUE_FLAG_BYPASS should stay. Block core expect
blk_queue_bypass_{start, end} internally to bypass/drain the queue before
actually dying the queue, so it didn't expose API to set the queue bypass.
I think we should set QUEUE_FLAG_BYPASS whenever queue is removed, although
the md->usage is still counted, as no dispatch queue could be found then.
Fixes:
304419d8a7e9 ("mmc: core: Allocate per-request data using the block layer core")
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>