From 4923b2f8d6b84ad1419993b2ae662338d35b40ca Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Tue, 25 Oct 2016 15:57:01 +0530 Subject: [PATCH] mmc: card: use blk_cleanup_queue() during shutdown/reboot It is preferred to use blk_cleanup_queue() instead of blk_stop_queue() during reboot/shutdown due to these reasons - 1. blk_cleanup_queue() marks the queue as dying/dead which prevents the new requests from getting inserted into the queue after MMC driver shutdown. If we just use blk_stop_queue(), the requests are still allowed into the request_queue but are not dispatched to the low level MMC driver as the queue is marked as stopped. This may result into deadlock/hang issue during shutdown, if FS (as part of emergency remount) is waiting for the queued request to be completed without relinquishing the CPU. If some CPU bound workqueues related to shutdown are pending on that CPU, then shutdown may hang. 2. blk_cleanup_queue() also drains the queue completely by processing all the pending requests from the elevator queue even though those are not yet dispatched to request_queue and also waits for the completion of all those requests. Also, do not override the queue_lock in request_queue structure with md->lock as this will cause below problem when using blk_cleanup_queue() in shutdown. This happens because blk_cleanup_queue() changes queue_lock from driver md->lock to it's original request_queue lock. Callstack: <6> BUG: spinlock already unlocked on CPU#6, iozone/4391 <6> lock: 0xffffffc06ab8be80, .magic: dead4ead, .owner: /-1, .owner_cpu: -1 [ffffffc0420e3b28] __delay at ffffffc00031a328 [ffffffc0420e3b38] __const_udelay at ffffffc00031a304 [ffffffc0420e3b58] msm_trigger_wdog_bite at ffffffc0004476cc [ffffffc0420e3b68] spin_bug at ffffffc0000e4554 [ffffffc0420e3b98] do_raw_spin_unlock at ffffffc0000e47a0 [ffffffc0420e3bc8] _raw_spin_unlock_irq at ffffffc000db3ee0 [ffffffc0420e3be8] blk_queue_bio at ffffffc0002ff1e4 [ffffffc0420e3bf8] generic_make_request at ffffffc0002fd210 [ffffffc0420e3c58] submit_bio at ffffffc0002fd328 [ffffffc0420e3ca8] submit_bio_wait at ffffffc0002f5768 [ffffffc0420e3d00] compat_sys_call_table at ffffffc00008e000 [ffffffc0420e3d18] submit_bio_wait at ffffffc0002f574c [ffffffc0420e3d38] __blkdev_issue_flush at ffffffc00030043c [ffffffc0420e3da8] blkdev_issue_flush at ffffffc000300494 [ffffffc0420e3dd8] ext4_sync_fs at ffffffc0002597a4 Change-Id: Iaa26944ccc6c279390215869f5003156400840ed Signed-off-by: Sahitya Tummala --- drivers/mmc/card/block.c | 2 +- drivers/mmc/card/queue.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 5743588aa52b..efbecb6e1dd0 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -4068,7 +4068,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, INIT_LIST_HEAD(&md->part); md->usage = 1; - ret = mmc_init_queue(&md->queue, card, &md->lock, subname, area_type); + ret = mmc_init_queue(&md->queue, card, NULL, subname, area_type); if (ret) goto err_putdisk; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 75a51bd2fc0b..f5dbb67ba929 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -724,15 +724,13 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) if (wait) { /* - * After blk_stop_queue is called, wait for all + * After blk_cleanup_queue is called, wait for all * active_reqs to complete. * Then wait for cmdq thread to exit before calling * cmdq shutdown to avoid race between issuing * requests and shutdown of cmdq. */ - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(q); if (host->cmdq_ctx.active_reqs) wait_for_completion( @@ -757,9 +755,15 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) } if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) { - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + if (!wait) { + /* suspend/stop the queue in case of suspend */ + spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + } else { + /* shutdown the queue in case of shutdown/reboot */ + blk_cleanup_queue(q); + } rc = down_trylock(&mq->thread_sem); if (rc && !wait) {