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

Commit 0c0f9b95 authored by Keith Busch's avatar Keith Busch
Browse files

NVMe: Fix potential corruption on sync commands



This makes all sync commands uninterruptible and schedules without timeout
so the controller either has to post a completion or the timeout recovery
fails the command. This fixes potential memory or data corruption from
a command timing out too early or woken by a signal. Previously any DMA
buffers mapped for that command would have been released even though we
don't know what the controller is planning to do with those addresses.

Signed-off-by: default avatarKeith Busch <keith.busch@intel.com>
parent 48328518
Loading
Loading
Loading
Loading
+3 −29
Original line number Diff line number Diff line
@@ -926,14 +926,6 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
	return IRQ_WAKE_THREAD;
}

static void nvme_abort_cmd_info(struct nvme_queue *nvmeq, struct nvme_cmd_info *
								cmd_info)
{
	spin_lock_irq(&nvmeq->q_lock);
	cancel_cmd_info(cmd_info, NULL);
	spin_unlock_irq(&nvmeq->q_lock);
}

struct sync_cmd_info {
	struct task_struct *task;
	u32 result;
@@ -956,7 +948,6 @@ static void sync_completion(struct nvme_queue *nvmeq, void *ctx,
static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
						u32 *result, unsigned timeout)
{
	int ret;
	struct sync_cmd_info cmdinfo;
	struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
	struct nvme_queue *nvmeq = cmd_rq->nvmeq;
@@ -968,29 +959,12 @@ static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,

	nvme_set_info(cmd_rq, &cmdinfo, sync_completion);

	set_current_state(TASK_KILLABLE);
	ret = nvme_submit_cmd(nvmeq, cmd);
	if (ret) {
		nvme_finish_cmd(nvmeq, req->tag, NULL);
		set_current_state(TASK_RUNNING);
	}
	ret = schedule_timeout(timeout);

	/*
	 * Ensure that sync_completion has either run, or that it will
	 * never run.
	 */
	nvme_abort_cmd_info(nvmeq, blk_mq_rq_to_pdu(req));

	/*
	 * We never got the completion
	 */
	if (cmdinfo.status == -EINTR)
		return -EINTR;
	set_current_state(TASK_UNINTERRUPTIBLE);
	nvme_submit_cmd(nvmeq, cmd);
	schedule();

	if (result)
		*result = cmdinfo.result;

	return cmdinfo.status;
}