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: Keith Busch <keith.busch@intel.com>
This commit is contained in:
parent
4832851840
commit
0c0f9b95c8
1 changed files with 3 additions and 29 deletions
|
@ -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,
|
||||||
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,
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue