diff options
| author | Ritesh Harjani <riteshh@codeaurora.org> | 2016-02-15 14:20:21 +0530 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:28:12 -0700 |
| commit | 284f0655519f1a81a470bb5df396b151b207b6a4 (patch) | |
| tree | be562d0282e278e9843a2e953deccefa6cdd4314 | |
| parent | cc6df31db6b39446b338b61932b0fc8f614baf89 (diff) | |
mmc: queue: Fix queue_lock spinlock bug from CMDQ shutdown path
CMDQ shutdown path calls blk_cleanup_queue, which changes queue_lock
from driver lock to it's original request_queue lock.
Hence during above shutdown process if below sequence is exercised
as well then may see below spinlock bug.
a) Some process say iozoneA has already acquired queue_lock (which
is md->lock).
b) adb reboot has been issued and CMDQ driver has completed calling
blk_cleanup_queue which switches the queue_lock from md->lock to
q->__queue_lock.
c) ProcessA tries to release queue_lock but finds an unbalance that
the lock is already released
Hence remove blk_cleanup_queue and instead make sure there are no
active_reqs in flight by mmccmdqd before this kthread is exited.
Callstack:
<6> BUG: spinlock already unlocked on CPU#6, iozone/4391
<6> lock: 0xffffffc06ab8be80, .magic: dead4ead,
.owner: <none>/-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
CRs-fixed: 953541
Change-Id: I769cc25c14b6d873f64a898d6b73f33cc59d9c5d
Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
| -rw-r--r-- | drivers/mmc/card/block.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c | 25 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.h | 1 |
3 files changed, 26 insertions, 3 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 02f2d323704e..97fcd1cf82b6 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3307,6 +3307,9 @@ 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 5c90d46fb65d..75a51bd2fc0b 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -97,7 +97,8 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, * 4. cmdq state shouldn't be in error state. * 5. free tag available to process the new request. */ - wait_event(ctx->wait, mmc_peek_request(mq) && + wait_event(ctx->wait, kthread_should_stop() + || (mmc_peek_request(mq) && !((mq->cmdq_req_peeked->cmd_flags & (REQ_FLUSH | REQ_DISCARD)) && test_bit(CMDQ_STATE_DCMD_ACTIVE, &ctx->curr_state)) && !(!host->card->part_curr && !mmc_card_suspended(host->card) @@ -105,7 +106,7 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host, && !(!host->card->part_curr && mmc_host_cq_disable(host) && !mmc_card_suspended(host->card)) && !test_bit(CMDQ_STATE_ERR, &ctx->curr_state) - && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked)); + && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked))); } static int mmc_cmdq_thread(void *d) @@ -122,6 +123,8 @@ static int mmc_cmdq_thread(void *d) int ret = 0; mmc_cmdq_ready_wait(host, mq); + if (kthread_should_stop()) + break; ret = mq->cmdq_issue_fn(mq, mq->cmdq_req_peeked); /* @@ -662,6 +665,7 @@ 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); @@ -718,7 +722,22 @@ int mmc_queue_suspend(struct mmc_queue *mq, int wait) goto out; if (wait) { - blk_cleanup_queue(q); + + /* + * After blk_stop_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); + + if (host->cmdq_ctx.active_reqs) + wait_for_completion( + &mq->cmdq_shutdown_complete); + kthread_stop(mq->thread); mq->cmdq_shutdown(mq); } else { spin_lock_irqsave(q->queue_lock, flags); diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 964262f0eb79..d8a33ac55c91 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -72,6 +72,7 @@ struct mmc_queue { struct work_struct cmdq_err_work; struct completion cmdq_pending_req_done; + struct completion cmdq_shutdown_complete; struct request *cmdq_req_peeked; int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *); void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *); |
