diff options
| author | Steve Wise <swise@opengridcomputing.com> | 2016-11-08 12:16:02 -0500 |
|---|---|---|
| committer | Sagi Grimberg <sagi@grimberg.me> | 2016-11-13 19:08:53 -0500 |
| commit | c8dbc37cd81d4705fce51123f5d81ea3267a5b88 (patch) | |
| tree | 930d2f3e3778b18d28f8cde75bf256111de120cb /drivers/nvme/host | |
| parent | 766dbb179d41d6337fed2b3ca00caa5845d298ce (diff) | |
nvme-rdma: stop and free io queues on connect failure
While testing nvme-rdma with the spdk nvmf target over iw_cxgb4, I
configured the target (mistakenly) to generate an error creating the
NVMF IO queues. This resulted a "Invalid SQE Parameter" error sent back
to the host on the first IO queue connect:
[ 9610.928182] nvme nvme1: queue_size 128 > ctrl maxcmd 120, clamping down
[ 9610.938745] nvme nvme1: creating 32 I/O queues.
So nvmf_connect_io_queue() returns an error to
nvmf_connect_io_queue() / nvmf_connect_io_queues(), and that
is returned to nvme_rdma_create_io_queues(). In the error path,
nvmf_rdma_create_io_queues() frees the queue tagset memory _before_
stopping and freeing the IB queues, which causes yet another
touch-after-free crash due to SQ CQEs being flushed after the ib_cqe
structs pointed-to by the flushed WRs have been freed (since they are
part of the nvme_rdma_request struct).
The fix is to stop and free the queues in nvmf_connect_io_queues()
if there is an error connecting any of the queues.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Diffstat (limited to 'drivers/nvme/host')
| -rw-r--r-- | drivers/nvme/host/rdma.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 438d6948895f..3d25add36d91 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c | |||
| @@ -625,11 +625,18 @@ static int nvme_rdma_connect_io_queues(struct nvme_rdma_ctrl *ctrl) | |||
| 625 | 625 | ||
| 626 | for (i = 1; i < ctrl->queue_count; i++) { | 626 | for (i = 1; i < ctrl->queue_count; i++) { |
| 627 | ret = nvmf_connect_io_queue(&ctrl->ctrl, i); | 627 | ret = nvmf_connect_io_queue(&ctrl->ctrl, i); |
| 628 | if (ret) | 628 | if (ret) { |
| 629 | break; | 629 | dev_info(ctrl->ctrl.device, |
| 630 | "failed to connect i/o queue: %d\n", ret); | ||
| 631 | goto out_free_queues; | ||
| 632 | } | ||
| 630 | set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags); | 633 | set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags); |
| 631 | } | 634 | } |
| 632 | 635 | ||
| 636 | return 0; | ||
| 637 | |||
| 638 | out_free_queues: | ||
| 639 | nvme_rdma_free_io_queues(ctrl); | ||
| 633 | return ret; | 640 | return ret; |
| 634 | } | 641 | } |
| 635 | 642 | ||
