nvmf/vfio-user: destroy controller when remote client is dead

When killing QEMU or remote client is terminated normally,
we can release current controller related data structure,
users may restart QEMU to connect the same socket file
again, for the new connection, vfio-user will create
a new controller data structure for it.

Here we add a lock in the endpoint data structure to protect
number of connected queue pairs variable, because controller
data structure is like a session, while endpoint is related
with the socket file, so it's safe here.  Moreover, we can
use this lock to protect live migration related data
structures in future.

Change-Id: Ie7060041a253604e7a2242813ec284eae46fe4e8
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6862
Community-CI: Broadcom CI
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: <dongx.yi@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Changpeng Liu 2021-03-11 21:27:28 +08:00 committed by Jim Harris
parent 3a3eb25ebb
commit 43b63c68b9

View File

@ -153,6 +153,8 @@ struct nvmf_vfio_user_ctrlr {
/* True when the admin queue is connected */
bool ready;
/* Number of connected queue pairs */
uint32_t num_connected_qps;
uint16_t cntlid;
@ -177,6 +179,7 @@ struct nvmf_vfio_user_endpoint {
const struct spdk_nvmf_subsystem *subsystem;
struct nvmf_vfio_user_ctrlr *ctrlr;
pthread_mutex_t lock;
TAILQ_ENTRY(nvmf_vfio_user_endpoint) link;
};
@ -279,6 +282,7 @@ nvmf_vfio_user_destroy_endpoint(struct nvmf_vfio_user_endpoint *endpoint)
vfu_destroy_ctx(endpoint->vfu_ctx);
pthread_mutex_destroy(&endpoint->lock);
free(endpoint);
}
@ -681,15 +685,19 @@ unmap_q(vfu_ctx_t *vfu_ctx, struct nvme_q *q)
static void
unmap_qp(struct nvmf_vfio_user_qpair *qp)
{
struct nvmf_vfio_user_ctrlr *ctrlr;
if (qp->ctrlr == NULL) {
return;
}
ctrlr = qp->ctrlr;
SPDK_DEBUGLOG(nvmf_vfio, "%s: destroy I/O QP%d\n",
ctrlr_id(qp->ctrlr), qp->qpair.qid);
ctrlr_id(ctrlr), qp->qpair.qid);
unmap_q(ctrlr->endpoint->vfu_ctx, &qp->sq);
unmap_q(ctrlr->endpoint->vfu_ctx, &qp->cq);
unmap_q(qp->ctrlr->endpoint->vfu_ctx, &qp->sq);
unmap_q(qp->ctrlr->endpoint->vfu_ctx, &qp->cq);
}
/*
@ -1505,6 +1513,8 @@ destroy_ctrlr(struct nvmf_vfio_user_ctrlr *ctrlr)
return 0;
}
SPDK_NOTICELOG("destroy %s\n", ctrlr_id(ctrlr));
for (i = 0; i < NVMF_VFIO_USER_DEFAULT_MAX_QPAIRS_PER_CTRLR; i++) {
destroy_qp(ctrlr, i);
}
@ -1514,6 +1524,7 @@ destroy_ctrlr(struct nvmf_vfio_user_ctrlr *ctrlr)
}
free(ctrlr);
return 0;
}
@ -1634,6 +1645,7 @@ nvmf_vfio_user_listen(struct spdk_nvmf_transport *transport,
goto out;
}
pthread_mutex_init(&endpoint->lock, NULL);
TAILQ_INSERT_TAIL(&vu_transport->endpoints, endpoint, link);
SPDK_NOTICELOG("%s: doorbells %p\n", uuid, endpoint->doorbells);
@ -1807,12 +1819,15 @@ handle_queue_connect_rsp(struct nvmf_vfio_user_req *req, void *cb_arg)
struct nvmf_vfio_user_poll_group *vu_group;
struct nvmf_vfio_user_qpair *qpair = cb_arg;
struct nvmf_vfio_user_ctrlr *ctrlr;
struct nvmf_vfio_user_endpoint *endpoint;
assert(qpair != NULL);
assert(req != NULL);
ctrlr = qpair->ctrlr;
endpoint = ctrlr->endpoint;
assert(ctrlr != NULL);
assert(endpoint != NULL);
if (spdk_nvme_cpl_is_error(&req->req.rsp->nvme_cpl)) {
SPDK_ERRLOG("SC %u, SCT %u\n", req->req.rsp->nvme_cpl.status.sc, req->req.rsp->nvme_cpl.status.sct);
@ -1825,10 +1840,13 @@ handle_queue_connect_rsp(struct nvmf_vfio_user_req *req, void *cb_arg)
TAILQ_INSERT_TAIL(&vu_group->qps, qpair, link);
qpair->state = VFIO_USER_QPAIR_ACTIVE;
pthread_mutex_lock(&endpoint->lock);
if (nvmf_qpair_is_admin_queue(&qpair->qpair)) {
ctrlr->cntlid = qpair->qpair.ctrlr->cntlid;
ctrlr->ready = true;
}
ctrlr->num_connected_qps++;
pthread_mutex_unlock(&endpoint->lock);
free(req->req.data);
req->req.data = NULL;
@ -1901,9 +1919,13 @@ nvmf_vfio_user_poll_group_remove(struct spdk_nvmf_transport_poll_group *group,
struct spdk_nvmf_qpair *qpair)
{
struct nvmf_vfio_user_qpair *vu_qpair;
struct nvmf_vfio_user_ctrlr *vu_ctrlr;
struct nvmf_vfio_user_endpoint *endpoint;
struct nvmf_vfio_user_poll_group *vu_group;
vu_qpair = SPDK_CONTAINEROF(qpair, struct nvmf_vfio_user_qpair, qpair);
vu_ctrlr = vu_qpair->ctrlr;
endpoint = vu_ctrlr->endpoint;
SPDK_DEBUGLOG(nvmf_vfio,
"%s: remove NVMf QP%d=%p from NVMf poll_group=%p\n",
@ -1911,9 +1933,13 @@ nvmf_vfio_user_poll_group_remove(struct spdk_nvmf_transport_poll_group *group,
vu_group = SPDK_CONTAINEROF(group, struct nvmf_vfio_user_poll_group, group);
TAILQ_REMOVE(&vu_group->qps, vu_qpair, link);
pthread_mutex_lock(&endpoint->lock);
assert(vu_ctrlr->num_connected_qps);
vu_ctrlr->num_connected_qps--;
pthread_mutex_unlock(&endpoint->lock);
return 0;
}
@ -2152,6 +2178,51 @@ handle_cmd_req(struct nvmf_vfio_user_ctrlr *ctrlr, struct spdk_nvme_cmd *cmd,
return 0;
}
static void
vfio_user_qpair_disconnect_cb(void *ctx)
{
struct nvmf_vfio_user_endpoint *endpoint = ctx;
struct nvmf_vfio_user_ctrlr *ctrlr;
pthread_mutex_lock(&endpoint->lock);
ctrlr = endpoint->ctrlr;
if (!ctrlr) {
pthread_mutex_unlock(&endpoint->lock);
return;
}
if (!ctrlr->num_connected_qps) {
destroy_ctrlr(ctrlr);
pthread_mutex_unlock(&endpoint->lock);
return;
}
pthread_mutex_unlock(&endpoint->lock);
}
static int
vfio_user_stop_ctrlr(struct nvmf_vfio_user_ctrlr *ctrlr)
{
uint32_t i;
struct nvmf_vfio_user_qpair *qpair;
struct nvmf_vfio_user_endpoint *endpoint;
SPDK_DEBUGLOG(nvmf_vfio, "%s stop processing\n", ctrlr_id(ctrlr));
ctrlr->ready = false;
endpoint = ctrlr->endpoint;
assert(endpoint != NULL);
for (i = 0; i < NVMF_VFIO_USER_DEFAULT_MAX_QPAIRS_PER_CTRLR; i++) {
qpair = ctrlr->qp[i];
if (qpair == NULL) {
continue;
}
spdk_nvmf_qpair_disconnect(&qpair->qpair, vfio_user_qpair_disconnect_cb, endpoint);
}
return 0;
}
static int
nvmf_vfio_user_ctrlr_poll(struct nvmf_vfio_user_ctrlr *ctrlr)
{
@ -2215,8 +2286,7 @@ nvmf_vfio_user_poll_group_poll(struct spdk_nvmf_transport_poll_group *group)
if (spdk_unlikely(err) != 0) {
/* initiator shutdown or reset, waiting for another re-connect */
if (errno == ENOTCONN) {
TAILQ_REMOVE(&vu_group->qps, vu_qpair, link);
ctrlr->ready = false;
vfio_user_stop_ctrlr(ctrlr);
continue;
}