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

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
...@@ -926,14 +926,6 @@ static irqreturn_t nvme_irq_check(int irq, void *data) ...@@ -926,14 +926,6 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
return IRQ_WAKE_THREAD; 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 sync_cmd_info {
struct task_struct *task; struct task_struct *task;
u32 result; u32 result;
...@@ -956,7 +948,6 @@ static void sync_completion(struct nvme_queue *nvmeq, void *ctx, ...@@ -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, static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
u32 *result, unsigned timeout) u32 *result, unsigned timeout)
{ {
int ret;
struct sync_cmd_info cmdinfo; struct sync_cmd_info cmdinfo;
struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req); struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
struct nvme_queue *nvmeq = cmd_rq->nvmeq; struct nvme_queue *nvmeq = cmd_rq->nvmeq;
...@@ -968,29 +959,12 @@ static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd, ...@@ -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); nvme_set_info(cmd_rq, &cmdinfo, sync_completion);
set_current_state(TASK_KILLABLE); set_current_state(TASK_UNINTERRUPTIBLE);
ret = nvme_submit_cmd(nvmeq, cmd); nvme_submit_cmd(nvmeq, cmd);
if (ret) { schedule();
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;
if (result) if (result)
*result = cmdinfo.result; *result = cmdinfo.result;
return cmdinfo.status; return cmdinfo.status;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment