From ac498fa31c66c04b3537ed14e0935cad9023bae4 Mon Sep 17 00:00:00 2001 From: Darek Stojaczyk Date: Fri, 17 May 2019 10:39:24 +0200 Subject: [PATCH] vhost: use DPDK APIs to split non-contiguous virtual memory buffers Currently, we translate each 2MB chunk to manually check if it's contiguous with the previous one, but there are rte_vhost APIs that do it way more efficiently. rte_vhost_va_from_guest_pa() was introduced in DPDK 18.02, but was backported to 17.11 as well, so we don't even need any RTE_VERSION ifdefs to use it now. This function calculates the remaining region size instead of trying to translate subsequent 2MB chunks over and over. The previous rte_vhost_gpa_to_vva() was deprecated a long time ago and after this patch we no longer make any use of it. DPDK usages of this new function check if the translated memory region has 0 length, which seems very silly, but let's just do it in SPDK as well. Change-Id: Ifae8daa5f810b5a2ba1524958ad2399af700b532 Signed-off-by: Darek Stojaczyk Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/454878 Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Changpeng Liu --- lib/vhost/vhost.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index 408a45a1f..4058d38c0 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -479,9 +479,8 @@ int spdk_vhost_vring_desc_to_iov(struct spdk_vhost_session *vsession, struct iovec *iov, uint16_t *iov_index, const struct vring_desc *desc) { - uint32_t remaining = desc->len; - uint32_t to_boundary; - uint32_t len; + uint64_t len; + uint64_t remaining = desc->len; uintptr_t payload = desc->addr; uintptr_t vva; @@ -490,31 +489,12 @@ spdk_vhost_vring_desc_to_iov(struct spdk_vhost_session *vsession, struct iovec * SPDK_ERRLOG("SPDK_VHOST_IOVS_MAX(%d) reached\n", SPDK_VHOST_IOVS_MAX); return -1; } - vva = (uintptr_t)rte_vhost_gpa_to_vva(vsession->mem, payload); - if (vva == 0) { + len = remaining; + vva = (uintptr_t)rte_vhost_va_from_guest_pa(vsession->mem, payload, &len); + if (vva == 0 || len == 0) { SPDK_ERRLOG("gpa_to_vva(%p) == NULL\n", (void *)payload); return -1; } - to_boundary = VALUE_2MB - _2MB_OFFSET(payload); - if (spdk_likely(remaining <= to_boundary)) { - len = remaining; - } else { - /* - * Descriptor crosses a 2MB hugepage boundary. vhost memory regions are allocated - * from hugepage memory, so this means this descriptor may be described by - * discontiguous vhost memory regions. Do not blindly split on the 2MB boundary, - * only split it if the two sides of the boundary do not map to the same vhost - * memory region. This helps ensure we do not exceed the max number of IOVs - * defined by SPDK_VHOST_IOVS_MAX. - */ - len = to_boundary; - while (len < remaining) { - if (vva + len != (uintptr_t)rte_vhost_gpa_to_vva(vsession->mem, payload + len)) { - break; - } - len += spdk_min(remaining - len, VALUE_2MB); - } - } iov[*iov_index].iov_base = (void *)vva; iov[*iov_index].iov_len = len; remaining -= len;