From b8d72590b322e492bf46c7f1db6c16123e671e29 Mon Sep 17 00:00:00 2001 From: Jin Yu Date: Tue, 15 Oct 2019 00:43:37 +0800 Subject: [PATCH] vhost: spdk live recovery from crash or killing This patch is for the vhost-blk live recovery feature which can make spdk recover from crash or killing. The relate rte_xx functions are in the the shared memory protocol patches which have been merged in DPDK 19.11. Change-Id: Ia0ac99f8ba0bd66dc9f525f2c72bd1de141ec596 Signed-off-by: Li Lin Signed-off-by: Ni Xun Signed-off-by: Zhang Yu Signed-off-by: Jin Yu Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/471235 Reviewed-by: Shuhei Matsumoto Reviewed-by: Changpeng Liu Tested-by: SPDK CI Jenkins Community-CI: SPDK CI Jenkins --- lib/vhost/vhost.c | 6 ++++ lib/vhost/vhost_blk.c | 65 +++++++++++++++++++++++++++++++++++++- lib/vhost/vhost_internal.h | 4 +++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index 897d8e3ee..1ab12c80f 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -414,6 +414,7 @@ vhost_vq_used_ring_enqueue(struct spdk_vhost_session *vsession, struct rte_vhost_vring *vring = &virtqueue->vring; struct vring_used *used = vring->used; uint16_t last_idx = virtqueue->last_used_idx & (vring->size - 1); + uint16_t vq_idx = virtqueue->vring_idx; SPDK_DEBUGLOG(SPDK_LOG_VHOST_RING, "Queue %td - USED RING: last_idx=%"PRIu16" req id=%"PRIu16" len=%"PRIu32"\n", @@ -428,10 +429,14 @@ vhost_vq_used_ring_enqueue(struct spdk_vhost_session *vsession, /* Ensure the used ring is updated before we log it or increment used->idx. */ spdk_smp_wmb(); + rte_vhost_set_last_inflight_io_split(vsession->vid, vq_idx, id); + vhost_log_used_vring_elem(vsession, virtqueue, last_idx); * (volatile uint16_t *) &used->idx = virtqueue->last_used_idx; vhost_log_used_vring_idx(vsession, virtqueue); + rte_vhost_clr_inflight_desc_split(vsession->vid, vq_idx, virtqueue->last_used_idx, id); + virtqueue->used_req_cnt++; } @@ -1060,6 +1065,7 @@ vhost_start_device_cb(int vid) continue; } q->vring_idx = i; + rte_vhost_get_vhost_ring_inflight(vid, i, &q->vring_inflight); if (q->vring.desc == NULL || q->vring.size == 0) { continue; diff --git a/lib/vhost/vhost_blk.c b/lib/vhost/vhost_blk.c index 2bd9198b5..523ce51f1 100644 --- a/lib/vhost/vhost_blk.c +++ b/lib/vhost/vhost_blk.c @@ -59,7 +59,8 @@ (1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI)) /* Vhost-blk support protocol features */ -#define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG)) +#define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG) | \ + (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) struct spdk_vhost_blk_task { struct spdk_bdev_io *bdev_io; @@ -432,6 +433,64 @@ process_blk_request(struct spdk_vhost_blk_task *task, return 0; } +static void +submit_inflight_desc(struct spdk_vhost_blk_session *bvsession, + struct spdk_vhost_virtqueue *vq) +{ + struct spdk_vhost_blk_dev *bvdev = bvsession->bvdev; + struct spdk_vhost_blk_task *task; + struct spdk_vhost_session *vsession = &bvsession->vsession; + spdk_vhost_resubmit_info *resubmit = vq->vring_inflight.resubmit_inflight; + spdk_vhost_resubmit_desc *resubmit_list; + int rc; + uint16_t req_idx; + + if (spdk_likely(resubmit == NULL || resubmit->resubmit_list == NULL)) { + return; + } + + resubmit_list = resubmit->resubmit_list; + while (resubmit->resubmit_num-- > 0) { + req_idx = resubmit_list[resubmit->resubmit_num].index; + SPDK_DEBUGLOG(SPDK_LOG_VHOST_BLK, "====== Start processing request idx %"PRIu16"======\n", + req_idx); + + if (spdk_unlikely(req_idx >= vq->vring.size)) { + SPDK_ERRLOG("%s: request idx '%"PRIu16"' exceeds virtqueue size (%"PRIu16").\n", + bvdev->vdev.name, req_idx, vq->vring.size); + vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0); + continue; + } + + task = &((struct spdk_vhost_blk_task *)vq->tasks)[req_idx]; + if (spdk_unlikely(task->used)) { + SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n", + bvdev->vdev.name, req_idx); + vhost_vq_used_ring_enqueue(vsession, vq, req_idx, 0); + continue; + } + + vsession->task_cnt++; + + task->used = true; + task->iovcnt = SPDK_COUNTOF(task->iovs); + task->status = NULL; + task->used_len = 0; + + rc = process_blk_request(task, bvsession, vq); + if (rc == 0) { + SPDK_DEBUGLOG(SPDK_LOG_VHOST_BLK, "====== Task %p req_idx %d submitted ======\n", task, + req_idx); + } else { + SPDK_DEBUGLOG(SPDK_LOG_VHOST_BLK, "====== Task %p req_idx %d failed ======\n", task, + req_idx); + } + } + + free(resubmit_list); + resubmit->resubmit_list = NULL; +} + static void process_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue *vq) { @@ -440,6 +499,9 @@ process_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue int rc; uint16_t reqs[32]; uint16_t reqs_cnt, i; + uint16_t vq_idx = vq->vring_idx; + + submit_inflight_desc(bvsession, vq); reqs_cnt = vhost_vq_avail_ring_get(vq, reqs, SPDK_COUNTOF(reqs)); if (!reqs_cnt) { @@ -457,6 +519,7 @@ process_vq(struct spdk_vhost_blk_session *bvsession, struct spdk_vhost_virtqueue continue; } + rte_vhost_set_inflight_desc_split(vsession->vid, vq_idx, reqs[i]); task = &((struct spdk_vhost_blk_task *)vq->tasks)[reqs[i]]; if (spdk_unlikely(task->used)) { SPDK_ERRLOG("%s: request with idx '%"PRIu16"' is already pending.\n", diff --git a/lib/vhost/vhost_internal.h b/lib/vhost/vhost_internal.h index f8503701a..377903956 100644 --- a/lib/vhost/vhost_internal.h +++ b/lib/vhost/vhost_internal.h @@ -85,8 +85,12 @@ struct vhost_poll_group { TAILQ_ENTRY(vhost_poll_group) tailq; }; +typedef struct rte_vhost_resubmit_desc spdk_vhost_resubmit_desc; +typedef struct rte_vhost_resubmit_info spdk_vhost_resubmit_info; + struct spdk_vhost_virtqueue { struct rte_vhost_vring vring; + struct rte_vhost_ring_inflight vring_inflight; uint16_t last_avail_idx; uint16_t last_used_idx;