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 <dariusz.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/454878
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Darek Stojaczyk 2019-05-17 10:39:24 +02:00 committed by Changpeng Liu
parent 5931284f74
commit ac498fa31c

View File

@ -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;