From 3b0520abdd56e26dd3cf26f09083a0d3dc60fa2a Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 27 Oct 2015 15:43:11 -0700 Subject: [PATCH] mmc: card: fix race with shutdown handler There could be 2 different race conditions possible with current shutdown handler: 1. Shutdown handler sees that there is no request in queue but mmc-cmdqd might have fetched the request from queue and about to issue it to driver. 2. Shutdown handler keeps looping in the while(1) loop as it sees request being pending in the request queue. But mmc-cmdqd thread doesn't wake up to fetch the requests from the request queue. mmc-cmdqd thread isn't waking up because shutdown path has stopped queue and request came into the queue after that. Once queue is stopped, block layer won't invoke the queue's ->request_fn() callback to notify driver about pending request. Remedy to fix both these race condition is simple. In shutdown handler, make sure that we drain (& complete) all the outstanding requests from the queue and then don't allow any new requests to be queued. Block layer API blk_cleanup_queue() precisely does what we want and this change basically use the same API in shutdown handler. Change-Id: I761ba6a2e2974d955bb72ff993b1cc2c32c9ec29 Signed-off-by: Subhash Jadavani --- drivers/mmc/card/block.c | 2 -- drivers/mmc/card/queue.c | 37 ++++++------------------------------- drivers/mmc/card/queue.h | 1 - 3 files changed, 6 insertions(+), 34 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1ca30a1bb75d..bfd877cdb6e2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3204,8 +3204,6 @@ out: if (!ctx_info->active_reqs) wake_up_interruptible(&host->cmdq_ctx.queue_empty_wq); - if (blk_queue_stopped(mq->queue) && !ctx_info->active_reqs) - complete(&mq->cmdq_shutdown_complete); return; } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 05f456b0d1c1..fdbfdc0f4e3a 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -655,7 +655,6 @@ int mmc_cmdq_init(struct mmc_queue *mq, struct mmc_card *card) blk_queue_softirq_done(mq->queue, mmc_cmdq_softirq_done); INIT_WORK(&mq->cmdq_err_work, mmc_cmdq_error_work); - init_completion(&mq->cmdq_shutdown_complete); init_completion(&mq->cmdq_pending_req_done); blk_queue_rq_timed_out(mq->queue, mmc_cmdq_rq_timed_out); @@ -704,7 +703,6 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) int rc = 0; struct mmc_card *card = mq->card; struct request *req; - #define SLEEP_TIME_BETWEEN_BLK_REQ_CHECK 100 /* microseconds */ if (card->cmdq_init && blk_queue_tagged(q)) { struct mmc_host *host = card->host; @@ -712,44 +710,21 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) if (test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags)) goto out; - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - wake_up(&host->cmdq_ctx.wait); - if (wait) { - while (1) { - spin_lock_irqsave(q->queue_lock, flags); - req = blk_peek_request(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - if (!req) - break; - - /* sleep for some time before rechecking */ - usleep_range(SLEEP_TIME_BETWEEN_BLK_REQ_CHECK, - SLEEP_TIME_BETWEEN_BLK_REQ_CHECK + 10); - } - - /* Wait for already issued requests to complete */ - if (host->cmdq_ctx.active_reqs) - wait_for_completion( - &mq->cmdq_shutdown_complete); - + blk_cleanup_queue(q); mq->cmdq_shutdown(mq); } else { spin_lock_irqsave(q->queue_lock, flags); + blk_stop_queue(q); + wake_up(&host->cmdq_ctx.wait); req = blk_peek_request(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - if (req || host->cmdq_ctx.active_reqs) { + if (req || mq->cmdq_req_peeked || + host->cmdq_ctx.active_reqs) { clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags); - spin_lock_irqsave(q->queue_lock, flags); blk_start_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); rc = -EBUSY; } + spin_unlock_irqrestore(q->queue_lock, flags); } goto out; diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index e67d0546346a..964262f0eb79 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -70,7 +70,6 @@ struct mmc_queue { int num_wr_reqs_to_start_packing; bool no_pack_for_random; struct work_struct cmdq_err_work; - struct completion cmdq_shutdown_complete; struct completion cmdq_pending_req_done; struct request *cmdq_req_peeked;