Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 959401aa authored by Jens Axboe's avatar Jens Axboe
Browse files

Merge branch 'nvmf-4.9-rc' of git://git.infradead.org/nvme-fabrics into for-linus

Sagi writes:

These are the relevant fixes for rc6
- fix possible crash in nvmet-rdma cm_handler from Bart
- fix possible memory leak in nvmet-rdma for connection failures
- fix possible use-after-free conditions in nvmet-rdma
- fix possible IO errors during reconnect stage from Christoph
- fix possible memory leak in nvme-rdma during IO queues connect
  failures from Steve
parents e76d21c4 14c862db
Loading
Loading
Loading
Loading
+39 −3
Original line number Original line Diff line number Diff line
@@ -83,6 +83,7 @@ enum nvme_rdma_queue_flags {
	NVME_RDMA_Q_CONNECTED = (1 << 0),
	NVME_RDMA_Q_CONNECTED = (1 << 0),
	NVME_RDMA_IB_QUEUE_ALLOCATED = (1 << 1),
	NVME_RDMA_IB_QUEUE_ALLOCATED = (1 << 1),
	NVME_RDMA_Q_DELETING = (1 << 2),
	NVME_RDMA_Q_DELETING = (1 << 2),
	NVME_RDMA_Q_LIVE = (1 << 3),
};
};


struct nvme_rdma_queue {
struct nvme_rdma_queue {
@@ -624,10 +625,18 @@ static int nvme_rdma_connect_io_queues(struct nvme_rdma_ctrl *ctrl)


	for (i = 1; i < ctrl->queue_count; i++) {
	for (i = 1; i < ctrl->queue_count; i++) {
		ret = nvmf_connect_io_queue(&ctrl->ctrl, i);
		ret = nvmf_connect_io_queue(&ctrl->ctrl, i);
		if (ret)
		if (ret) {
			break;
			dev_info(ctrl->ctrl.device,
				"failed to connect i/o queue: %d\n", ret);
			goto out_free_queues;
		}
		set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags);
	}
	}


	return 0;

out_free_queues:
	nvme_rdma_free_io_queues(ctrl);
	return ret;
	return ret;
}
}


@@ -712,6 +721,8 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
	if (ret)
	if (ret)
		goto stop_admin_q;
		goto stop_admin_q;


	set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[0].flags);

	ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->cap);
	ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->cap);
	if (ret)
	if (ret)
		goto stop_admin_q;
		goto stop_admin_q;
@@ -761,8 +772,10 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)


	nvme_stop_keep_alive(&ctrl->ctrl);
	nvme_stop_keep_alive(&ctrl->ctrl);


	for (i = 0; i < ctrl->queue_count; i++)
	for (i = 0; i < ctrl->queue_count; i++) {
		clear_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[i].flags);
		clear_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[i].flags);
		clear_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags);
	}


	if (ctrl->queue_count > 1)
	if (ctrl->queue_count > 1)
		nvme_stop_queues(&ctrl->ctrl);
		nvme_stop_queues(&ctrl->ctrl);
@@ -1378,6 +1391,24 @@ nvme_rdma_timeout(struct request *rq, bool reserved)
	return BLK_EH_HANDLED;
	return BLK_EH_HANDLED;
}
}


/*
 * We cannot accept any other command until the Connect command has completed.
 */
static inline bool nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
		struct request *rq)
{
	if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
		struct nvme_command *cmd = (struct nvme_command *)rq->cmd;

		if (rq->cmd_type != REQ_TYPE_DRV_PRIV ||
		    cmd->common.opcode != nvme_fabrics_command ||
		    cmd->fabrics.fctype != nvme_fabrics_type_connect)
			return false;
	}

	return true;
}

static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
		const struct blk_mq_queue_data *bd)
		const struct blk_mq_queue_data *bd)
{
{
@@ -1394,6 +1425,9 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,


	WARN_ON_ONCE(rq->tag < 0);
	WARN_ON_ONCE(rq->tag < 0);


	if (!nvme_rdma_queue_is_ready(queue, rq))
		return BLK_MQ_RQ_QUEUE_BUSY;

	dev = queue->device->dev;
	dev = queue->device->dev;
	ib_dma_sync_single_for_cpu(dev, sqe->dma,
	ib_dma_sync_single_for_cpu(dev, sqe->dma,
			sizeof(struct nvme_command), DMA_TO_DEVICE);
			sizeof(struct nvme_command), DMA_TO_DEVICE);
@@ -1544,6 +1578,8 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl)
	if (error)
	if (error)
		goto out_cleanup_queue;
		goto out_cleanup_queue;


	set_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[0].flags);

	error = nvmf_reg_read64(&ctrl->ctrl, NVME_REG_CAP, &ctrl->cap);
	error = nvmf_reg_read64(&ctrl->ctrl, NVME_REG_CAP, &ctrl->cap);
	if (error) {
	if (error) {
		dev_err(ctrl->ctrl.device,
		dev_err(ctrl->ctrl.device,
+7 −3
Original line number Original line Diff line number Diff line
@@ -838,10 +838,14 @@ static void nvmet_fatal_error_handler(struct work_struct *work)


void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl)
void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl)
{
{
	mutex_lock(&ctrl->lock);
	if (!(ctrl->csts & NVME_CSTS_CFS)) {
		ctrl->csts |= NVME_CSTS_CFS;
		ctrl->csts |= NVME_CSTS_CFS;
		INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler);
		INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler);
		schedule_work(&ctrl->fatal_err_work);
		schedule_work(&ctrl->fatal_err_work);
	}
	}
	mutex_unlock(&ctrl->lock);
}
EXPORT_SYMBOL_GPL(nvmet_ctrl_fatal_error);
EXPORT_SYMBOL_GPL(nvmet_ctrl_fatal_error);


static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
+15 −3
Original line number Original line Diff line number Diff line
@@ -951,6 +951,7 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)


static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
static void nvmet_rdma_destroy_queue_ib(struct nvmet_rdma_queue *queue)
{
{
	ib_drain_qp(queue->cm_id->qp);
	rdma_destroy_qp(queue->cm_id);
	rdma_destroy_qp(queue->cm_id);
	ib_free_cq(queue->cq);
	ib_free_cq(queue->cq);
}
}
@@ -1066,6 +1067,7 @@ nvmet_rdma_alloc_queue(struct nvmet_rdma_device *ndev,
	spin_lock_init(&queue->rsp_wr_wait_lock);
	spin_lock_init(&queue->rsp_wr_wait_lock);
	INIT_LIST_HEAD(&queue->free_rsps);
	INIT_LIST_HEAD(&queue->free_rsps);
	spin_lock_init(&queue->rsps_lock);
	spin_lock_init(&queue->rsps_lock);
	INIT_LIST_HEAD(&queue->queue_list);


	queue->idx = ida_simple_get(&nvmet_rdma_queue_ida, 0, 0, GFP_KERNEL);
	queue->idx = ida_simple_get(&nvmet_rdma_queue_ida, 0, 0, GFP_KERNEL);
	if (queue->idx < 0) {
	if (queue->idx < 0) {
@@ -1244,7 +1246,6 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)


	if (disconnect) {
	if (disconnect) {
		rdma_disconnect(queue->cm_id);
		rdma_disconnect(queue->cm_id);
		ib_drain_qp(queue->cm_id->qp);
		schedule_work(&queue->release_work);
		schedule_work(&queue->release_work);
	}
	}
}
}
@@ -1269,7 +1270,12 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
{
{
	WARN_ON_ONCE(queue->state != NVMET_RDMA_Q_CONNECTING);
	WARN_ON_ONCE(queue->state != NVMET_RDMA_Q_CONNECTING);


	pr_err("failed to connect queue\n");
	mutex_lock(&nvmet_rdma_queue_mutex);
	if (!list_empty(&queue->queue_list))
		list_del_init(&queue->queue_list);
	mutex_unlock(&nvmet_rdma_queue_mutex);

	pr_err("failed to connect queue %d\n", queue->idx);
	schedule_work(&queue->release_work);
	schedule_work(&queue->release_work);
}
}


@@ -1352,6 +1358,12 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
	case RDMA_CM_EVENT_ADDR_CHANGE:
	case RDMA_CM_EVENT_ADDR_CHANGE:
	case RDMA_CM_EVENT_DISCONNECTED:
	case RDMA_CM_EVENT_DISCONNECTED:
	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
		/*
		 * We might end up here when we already freed the qp
		 * which means queue release sequence is in progress,
		 * so don't get in the way...
		 */
		if (queue)
			nvmet_rdma_queue_disconnect(queue);
			nvmet_rdma_queue_disconnect(queue);
		break;
		break;
	case RDMA_CM_EVENT_DEVICE_REMOVAL:
	case RDMA_CM_EVENT_DEVICE_REMOVAL: