summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2015-02-19 14:29:48 -0700
committerKeith Busch <keith.busch@intel.com>2015-02-19 16:15:38 -0700
commit0c0f9b95c8b710b74772edd9693fe7ab5419a75a (patch)
tree222cbbadbeec1a193e380d6d18ef4b95122b45fb
parent483285184059b3f5b3a5707977349528abc82441 (diff)
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>
-rw-r--r--drivers/block/nvme-core.c32
1 files changed, 3 insertions, 29 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index cf2d8e3c93a8..b64bccbb78c9 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -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;
}