Commit 3ee93c32 authored by Ben Walker's avatar Ben Walker Committed by Jim Harris
Browse files

nvmf/rdma: Poll groups can now span devices



Currently they're entirely contained within a single
spdk_nvmf_ctrlr, which won't span devices, but this
sets the stage for a more flexible library.

Change-Id: I653f3d6fe4187f4eaf18cda0a6960040ba6952d7
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/376238


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 0ab300f8
Loading
Loading
Loading
Loading
+107 −28
Original line number Diff line number Diff line
@@ -199,15 +199,25 @@ struct spdk_nvmf_rdma_qpair {
	struct ibv_mr				*bufs_mr;

	TAILQ_ENTRY(spdk_nvmf_rdma_qpair)	link;
	TAILQ_ENTRY(spdk_nvmf_rdma_qpair)	pending_link;
};

/* List of RDMA connections that have not yet received a CONNECT capsule */
static TAILQ_HEAD(, spdk_nvmf_rdma_qpair) g_pending_conns = TAILQ_HEAD_INITIALIZER(g_pending_conns);

struct spdk_nvmf_rdma_poller {
	struct spdk_nvmf_rdma_device		*device;
	struct spdk_nvmf_rdma_poll_group	*group;

	TAILQ_HEAD(, spdk_nvmf_rdma_qpair)	qpairs;

	TAILQ_ENTRY(spdk_nvmf_rdma_poller)	link;
};

struct spdk_nvmf_rdma_poll_group {
	struct spdk_nvmf_poll_group		group;

	struct spdk_nvmf_rdma_device		*device;
	TAILQ_HEAD(, spdk_nvmf_rdma_poller)	pollers;
};

/* Assuming rdma_cm uses just one protection domain per ibv_context. */
@@ -648,7 +658,7 @@ nvmf_rdma_connect(struct spdk_nvmf_transport *transport, struct rdma_cm_event *e

	/* Add this RDMA connection to the global list until a CONNECT capsule
	 * is received. */
	TAILQ_INSERT_TAIL(&g_pending_conns, rdma_qpair, link);
	TAILQ_INSERT_TAIL(&g_pending_conns, rdma_qpair, pending_link);

	return 0;

@@ -692,11 +702,11 @@ nvmf_rdma_disconnect(struct rdma_cm_event *evt)
	/* The connection may still be in this pending list when a disconnect
	 * event arrives. Search for it and remove it if it is found.
	 */
	TAILQ_FOREACH_SAFE(r, &g_pending_conns, link, t) {
	TAILQ_FOREACH_SAFE(r, &g_pending_conns, pending_link, t) {
		if (r == rdma_qpair) {
			SPDK_DEBUGLOG(SPDK_TRACE_RDMA, "Received disconnect for qpair %p before first SEND ack\n",
				      rdma_qpair);
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, link);
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, pending_link);
			break;
		}
	}
@@ -1365,15 +1375,15 @@ spdk_nvmf_rdma_accept(struct spdk_nvmf_transport *transport)

	/* Process pending connections for incoming capsules. The only capsule
	 * this should ever find is a CONNECT request. */
	TAILQ_FOREACH_SAFE(rdma_qpair, &g_pending_conns, link, tmp) {
	TAILQ_FOREACH_SAFE(rdma_qpair, &g_pending_conns, pending_link, tmp) {
		rc = spdk_nvmf_rdma_poll(&rdma_qpair->qpair);
		if (rc < 0) {
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, link);
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, pending_link);
			spdk_nvmf_rdma_qpair_destroy(rdma_qpair);
		} else if (rc > 0) {
			/* At least one request was processed which is assumed to be
			 * a CONNECT. Remove this connection from our list. */
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, link);
			TAILQ_REMOVE(&g_pending_conns, rdma_qpair, pending_link);
		}
	}

@@ -1438,13 +1448,49 @@ spdk_nvmf_rdma_discover(struct spdk_nvmf_transport *transport,
static struct spdk_nvmf_poll_group *
spdk_nvmf_rdma_poll_group_create(struct spdk_nvmf_transport *transport)
{
	struct spdk_nvmf_rdma_transport		*rtransport;
	struct spdk_nvmf_rdma_poll_group	*rgroup;
	struct spdk_nvmf_rdma_poller		*poller;
	struct spdk_nvmf_rdma_device		*device;

	rtransport = SPDK_CONTAINEROF(transport, struct spdk_nvmf_rdma_transport, transport);

	rgroup = calloc(1, sizeof(*rgroup));
	if (!rgroup) {
		return NULL;
	}

	TAILQ_INIT(&rgroup->pollers);

	pthread_mutex_lock(&rtransport->lock);
	TAILQ_FOREACH(device, &rtransport->devices, link) {
		if (device->map == NULL) {
			/*
			 * The device is not in use (no listeners),
			 * so no protection domain has been constructed.
			 * Skip it.
			 */
			SPDK_NOTICELOG("Skipping unused RDMA device when creating poll group.\n");
			continue;
		}

		poller = calloc(1, sizeof(*poller));
		if (!poller) {
			SPDK_ERRLOG("Unable to allocate memory for new RDMA poller\n");
			free(rgroup);
			pthread_mutex_unlock(&rtransport->lock);
			return NULL;
		}

		poller->device = device;
		poller->group = rgroup;

		TAILQ_INIT(&poller->qpairs);

		TAILQ_INSERT_TAIL(&rgroup->pollers, poller, link);
	}

	pthread_mutex_unlock(&rtransport->lock);
	return &rgroup->group;
}

@@ -1452,6 +1498,7 @@ static void
spdk_nvmf_rdma_poll_group_destroy(struct spdk_nvmf_poll_group *group)
{
	struct spdk_nvmf_rdma_poll_group	*rgroup;
	struct spdk_nvmf_rdma_poller		*poller, *tmp;

	rgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_rdma_poll_group, group);

@@ -1459,6 +1506,11 @@ spdk_nvmf_rdma_poll_group_destroy(struct spdk_nvmf_poll_group *group)
		return;
	}

	TAILQ_FOREACH_SAFE(poller, &rgroup->pollers, link, tmp) {
		TAILQ_REMOVE(&rgroup->pollers, poller, link);
		free(poller);
	}

	free(rgroup);
}

@@ -1467,39 +1519,32 @@ spdk_nvmf_rdma_poll_group_add(struct spdk_nvmf_poll_group *group,
			      struct spdk_nvmf_qpair *qpair)
{
	struct spdk_nvmf_rdma_poll_group	*rgroup;
	struct spdk_nvmf_rdma_qpair 		*rdma_qpair;
	struct spdk_nvmf_rdma_transport		*rtransport;
	struct spdk_nvmf_rdma_qpair 		*rqpair;
	struct spdk_nvmf_rdma_device 		*device;
	struct spdk_nvmf_rdma_poller		*poller;

	rgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_rdma_poll_group, group);
	rdma_qpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair);
	rtransport = SPDK_CONTAINEROF(group->transport, struct spdk_nvmf_rdma_transport, transport);
	rqpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair);

	if (rgroup->device != NULL) {
		if (rgroup->device->context != rdma_qpair->cm_id->verbs) {
			SPDK_ERRLOG("Attempted to add a qpair to a poll group with mismatched RDMA devices.\n");
			return -1;
		}
	device = rqpair->port->device;

		if (rgroup->device->pd != rdma_qpair->cm_id->pd) {
	if (device->pd != rqpair->cm_id->pd) {
		SPDK_ERRLOG("Mismatched protection domains\n");
		return -1;
	}

		return 0;
	}

	TAILQ_FOREACH(device, &rtransport->devices, link) {
		if (device->context == rdma_qpair->cm_id->verbs) {
	TAILQ_FOREACH(poller, &rgroup->pollers, link) {
		if (poller->device == device) {
			break;
		}
	}
	if (!device) {
		SPDK_ERRLOG("Attempted to add a qpair with an unknown device\n");
		return -EINVAL;

	if (!poller) {
		SPDK_ERRLOG("No poller found for device.\n");
		return -1;
	}

	rgroup->device = device;
	TAILQ_INSERT_TAIL(&poller->qpairs, rqpair, link);

	return 0;
}
@@ -1508,6 +1553,40 @@ static int
spdk_nvmf_rdma_poll_group_remove(struct spdk_nvmf_poll_group *group,
				 struct spdk_nvmf_qpair *qpair)
{
	struct spdk_nvmf_rdma_poll_group	*rgroup;
	struct spdk_nvmf_rdma_qpair 		*rqpair;
	struct spdk_nvmf_rdma_device 		*device;
	struct spdk_nvmf_rdma_poller		*poller;
	struct spdk_nvmf_rdma_qpair		*rq, *trq;

	rgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_rdma_poll_group, group);
	rqpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair);

	device = rqpair->port->device;

	TAILQ_FOREACH(poller, &rgroup->pollers, link) {
		if (poller->device == device) {
			break;
		}
	}

	if (!poller) {
		SPDK_ERRLOG("No poller found for device.\n");
		return -1;
	}

	TAILQ_FOREACH_SAFE(rq, &poller->qpairs, link, trq) {
		if (rq == rqpair) {
			TAILQ_REMOVE(&poller->qpairs, rqpair, link);
			break;
		}
	}

	if (rq == NULL) {
		SPDK_ERRLOG("RDMA qpair cannot be removed from group (not in group).\n");
		return -1;
	}

	return 0;
}