From: Jens Axboe Date: Fri, 12 Dec 2014 15:53:40 +0000 (-0700) Subject: NVMe: fix race condition in nvme_submit_sync_cmd() X-Git-Tag: v3.19-rc1~87^2 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=849c6e7746e4f6317ace6aa7d2fcdcd844e99ddb;p=linux-block.git 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 Signed-off-by: Jens Axboe --- 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, nvme_finish_cmd(nvmeq, req->tag, NULL); set_current_state(TASK_RUNNING); } - schedule_timeout(timeout); + ret = schedule_timeout(timeout); - if (cmdinfo.status == -EINTR) { - nvme_abort_cmd_info(nvmeq, blk_mq_rq_to_pdu(req)); + /* + * 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) *result = cmdinfo.result;