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: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/376238
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Ben Walker 2017-08-28 13:29:19 -07:00 committed by Jim Harris
parent 0ab300f872
commit 3ee93c3293

View File

@ -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) {
SPDK_ERRLOG("Mismatched protection domains\n");
return -1;
}
return 0;
if (device->pd != rqpair->cm_id->pd) {
SPDK_ERRLOG("Mismatched protection domains\n");
return -1;
}
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;
}