Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a61087e authored by Ritesh Harjani's avatar Ritesh Harjani Committed by Xiaonian Wang
Browse files

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: default avatarRitesh Harjani <riteshh@codeaurora.org>
[xiaonian@codeaurora.org: fixed trivial merge conflicts]
Signed-off-by: default avatarXiaonian Wang <xiaonian@codeaurora.org>
parent 08d3caf2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3610,6 +3610,9 @@ void mmc_blk_cmdq_complete_rq(struct request *rq)
	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;
}

+22 −3
Original line number Diff line number Diff line
@@ -100,7 +100,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) &&
		!(((req_op(mq->cmdq_req_peeked) == REQ_OP_FLUSH) ||
		   (req_op(mq->cmdq_req_peeked) == REQ_OP_DISCARD))
		  && test_bit(CMDQ_STATE_DCMD_ACTIVE, &ctx->curr_state))
@@ -109,7 +110,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)
@@ -127,6 +128,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);
		/*
@@ -668,6 +671,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);
@@ -724,7 +728,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);
+1 −0
Original line number Diff line number Diff line
@@ -77,6 +77,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 *);