diff options
author | Keith Busch <keith.busch@intel.com> | 2016-11-15 15:56:26 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-11-16 14:39:57 -0500 |
commit | d48756228ee9161ac8836b346589a43fabdc9f3c (patch) | |
tree | 9f1c735aa5b75345e71baca7a3bcbe19c8edc568 | |
parent | 959401aa2b8cc6422809762a6ba4b2635154e9a6 (diff) |
nvme/pci: Don't free queues on error
The nvme_remove function tears down all allocated resources in the correct
order, so no need to free queues on error during initialization. This
fixes possible use-after-free errors when queues are still associated
with a blk-mq hctx.
Reported-by: Scott Bauer <scott.bauer@intel.com>
Tested-by: Scott Bauer <scott.bauer@intel.com>
Signed-off-by: Keith Busch <keith.busch@intel.com>
Reviewed-by: Sagi Grimberg <sagi@grimbeg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: stable@vger.kernel.org
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/nvme/host/pci.c | 18 |
1 files changed, 4 insertions, 14 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 0248d0e21fee..5e52034ab010 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c | |||
@@ -1242,20 +1242,16 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) | |||
1242 | 1242 | ||
1243 | result = nvme_enable_ctrl(&dev->ctrl, cap); | 1243 | result = nvme_enable_ctrl(&dev->ctrl, cap); |
1244 | if (result) | 1244 | if (result) |
1245 | goto free_nvmeq; | 1245 | return result; |
1246 | 1246 | ||
1247 | nvmeq->cq_vector = 0; | 1247 | nvmeq->cq_vector = 0; |
1248 | result = queue_request_irq(nvmeq); | 1248 | result = queue_request_irq(nvmeq); |
1249 | if (result) { | 1249 | if (result) { |
1250 | nvmeq->cq_vector = -1; | 1250 | nvmeq->cq_vector = -1; |
1251 | goto free_nvmeq; | 1251 | return result; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | return result; | 1254 | return result; |
1255 | |||
1256 | free_nvmeq: | ||
1257 | nvme_free_queues(dev, 0); | ||
1258 | return result; | ||
1259 | } | 1255 | } |
1260 | 1256 | ||
1261 | static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) | 1257 | static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) |
@@ -1317,10 +1313,8 @@ static int nvme_create_io_queues(struct nvme_dev *dev) | |||
1317 | max = min(dev->max_qid, dev->queue_count - 1); | 1313 | max = min(dev->max_qid, dev->queue_count - 1); |
1318 | for (i = dev->online_queues; i <= max; i++) { | 1314 | for (i = dev->online_queues; i <= max; i++) { |
1319 | ret = nvme_create_queue(dev->queues[i], i); | 1315 | ret = nvme_create_queue(dev->queues[i], i); |
1320 | if (ret) { | 1316 | if (ret) |
1321 | nvme_free_queues(dev, i); | ||
1322 | break; | 1317 | break; |
1323 | } | ||
1324 | } | 1318 | } |
1325 | 1319 | ||
1326 | /* | 1320 | /* |
@@ -1460,13 +1454,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) | |||
1460 | result = queue_request_irq(adminq); | 1454 | result = queue_request_irq(adminq); |
1461 | if (result) { | 1455 | if (result) { |
1462 | adminq->cq_vector = -1; | 1456 | adminq->cq_vector = -1; |
1463 | goto free_queues; | 1457 | return result; |
1464 | } | 1458 | } |
1465 | return nvme_create_io_queues(dev); | 1459 | return nvme_create_io_queues(dev); |
1466 | |||
1467 | free_queues: | ||
1468 | nvme_free_queues(dev, 1); | ||
1469 | return result; | ||
1470 | } | 1460 | } |
1471 | 1461 | ||
1472 | static void nvme_del_queue_end(struct request *req, int error) | 1462 | static void nvme_del_queue_end(struct request *req, int error) |