aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2014-12-12 10:53:40 -0500
committerJens Axboe <axboe@fb.com>2014-12-12 10:53:40 -0500
commit849c6e7746e4f6317ace6aa7d2fcdcd844e99ddb (patch)
treea46e807ce51483393beb9e1d8c1ed331e9a023ca /drivers/block
parentfe54303ee2be293c1c5c7a53a152453789cabc2f (diff)
NVMe: fix race condition in nvme_submit_sync_cmd()
If we have a race between the schedule timing out and the command completing, we could have the task issuing the command exit nvme_submit_sync_cmd() while the irq is running sync_completion(). If that happens, we could be corrupting memory, since the stack that held 'cmdinfo' is no longer valid. Fix this by always calling nvme_abort_cmd_info(). Once that call completes, we know that we have either run sync_completion() if the completion came in, or that we will never run it since we now have special_completion() as the command callback handler. Acked-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nvme-core.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index e92bdf4c68fc..b1d5d8797315 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -804,12 +804,19 @@ static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
804 nvme_finish_cmd(nvmeq, req->tag, NULL); 804 nvme_finish_cmd(nvmeq, req->tag, NULL);
805 set_current_state(TASK_RUNNING); 805 set_current_state(TASK_RUNNING);
806 } 806 }
807 schedule_timeout(timeout); 807 ret = schedule_timeout(timeout);
808 808
809 if (cmdinfo.status == -EINTR) { 809 /*
810 nvme_abort_cmd_info(nvmeq, blk_mq_rq_to_pdu(req)); 810 * Ensure that sync_completion has either run, or that it will
811 * never run.
812 */
813 nvme_abort_cmd_info(nvmeq, blk_mq_rq_to_pdu(req));
814
815 /*
816 * We never got the completion
817 */
818 if (cmdinfo.status == -EINTR)
811 return -EINTR; 819 return -EINTR;
812 }
813 820
814 if (result) 821 if (result)
815 *result = cmdinfo.result; 822 *result = cmdinfo.result;