From 5d5738688571640268ec8cea9fdffbdfc51f8b25 Mon Sep 17 00:00:00 2001 From: Seth Howell Date: Tue, 11 Sep 2018 16:05:50 -0700 Subject: [PATCH] env_dpdk: spdk_mem_map_translate informs user of translation size. This function will now check for whether or not a memory region is contiguous accross 2MB map entries and return the total length of that contiguous buffer up to the size specified by the user. Also includes unittests This series of changes is aimed at enabling spdk_mem_map_translate to report back to the user the length of the valid mem_map up to the function that requested the translation. This will be useful when retrieving memory regions associated with I/O buffers in NVMe-oF. For large I/O it will be possible that the buffer is split over multiple MRs and the I/O will have to be split into multiple SGLs. Change-Id: I2ce582427d451be5a317808d0825c770e12e9a69 Signed-off-by: Seth Howell Reviewed-on: https://review.gerrithub.io/425329 Tested-by: SPDK CI Jenkins Chandler-Test-Pool: SPDK Automated Test System Reviewed-by: Ben Walker Reviewed-by: Shuhei Matsumoto --- include/spdk/env.h | 3 +++ lib/env_dpdk/memory.c | 35 ++++++++++++++++++++++-- lib/env_dpdk/vtophys.c | 3 ++- lib/nvme/nvme_rdma.c | 3 ++- lib/nvmf/rdma.c | 3 ++- test/env/memory/memory_ut.c | 54 ++++++++++++++++++++++++++++++++++++- test/env/vtophys/vtophys.c | 3 ++- 7 files changed, 97 insertions(+), 7 deletions(-) diff --git a/include/spdk/env.h b/include/spdk/env.h index 8df04e6d3..307499b72 100644 --- a/include/spdk/env.h +++ b/include/spdk/env.h @@ -979,11 +979,14 @@ typedef int (*spdk_mem_map_notify_cb)(void *cb_ctx, struct spdk_mem_map *map, enum spdk_mem_map_notify_action action, void *vaddr, size_t size); +typedef int (*spdk_mem_map_contiguous_translations)(uint64_t addr_1, uint64_t addr_2); + /** * A function table to be implemented by each memory map. */ struct spdk_mem_map_ops { spdk_mem_map_notify_cb notify_cb; + spdk_mem_map_contiguous_translations are_contiguous; }; /** diff --git a/lib/env_dpdk/memory.c b/lib/env_dpdk/memory.c index a7618732d..2d1f168e7 100644 --- a/lib/env_dpdk/memory.c +++ b/lib/env_dpdk/memory.c @@ -484,8 +484,12 @@ spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t uint64_t idx_256tb; uint64_t idx_1gb; uint64_t vfn_2mb; + uint64_t total_size = 0; + uint64_t cur_size; + uint64_t prev_translation; if (size != NULL) { + total_size = *size; *size = 0; } @@ -503,12 +507,39 @@ spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t return map->default_translation; } - map_2mb = &map_1gb->map[idx_1gb]; + cur_size = VALUE_2MB; if (size != NULL) { *size = VALUE_2MB; } - return map_2mb->translation_2mb; + map_2mb = &map_1gb->map[idx_1gb]; + if (size == NULL || map->ops.are_contiguous == NULL || + map_2mb->translation_2mb == map->default_translation) { + return map_2mb->translation_2mb; + } + + prev_translation = map_2mb->translation_2mb;; + while (cur_size < total_size) { + vfn_2mb++; + idx_256tb = MAP_256TB_IDX(vfn_2mb); + idx_1gb = MAP_1GB_IDX(vfn_2mb); + + map_1gb = map->map_256tb.map[idx_256tb]; + if (spdk_unlikely(!map_1gb)) { + break; + } + + map_2mb = &map_1gb->map[idx_1gb]; + if (!map->ops.are_contiguous(prev_translation, map_2mb->translation_2mb)) { + break; + } + + cur_size += VALUE_2MB; + prev_translation = map_2mb->translation_2mb; + } + + *size = cur_size; + return prev_translation; } #if RTE_VERSION >= RTE_VERSION_NUM(18, 05, 0, 0) diff --git a/lib/env_dpdk/vtophys.c b/lib/env_dpdk/vtophys.c index 3b330931f..00e8bb6d8 100644 --- a/lib/env_dpdk/vtophys.c +++ b/lib/env_dpdk/vtophys.c @@ -605,7 +605,8 @@ int spdk_vtophys_init(void) { const struct spdk_mem_map_ops vtophys_map_ops = { - .notify_cb = spdk_vtophys_notify + .notify_cb = spdk_vtophys_notify, + .are_contiguous = NULL }; #if SPDK_VFIO_ENABLED diff --git a/lib/nvme/nvme_rdma.c b/lib/nvme/nvme_rdma.c index 349638744..53e7a6069 100644 --- a/lib/nvme/nvme_rdma.c +++ b/lib/nvme/nvme_rdma.c @@ -637,7 +637,8 @@ nvme_rdma_register_mem(struct nvme_rdma_qpair *rqpair) struct ibv_pd *pd = rqpair->cm_id->qp->pd; struct spdk_nvme_rdma_mr_map *mr_map; const struct spdk_mem_map_ops nvme_rdma_map_ops = { - .notify_cb = nvme_rdma_mr_map_notify + .notify_cb = nvme_rdma_mr_map_notify, + .are_contiguous = NULL }; pthread_mutex_lock(&g_rdma_mr_maps_mutex); diff --git a/lib/nvmf/rdma.c b/lib/nvmf/rdma.c index c33b4af92..c1007216f 100644 --- a/lib/nvmf/rdma.c +++ b/lib/nvmf/rdma.c @@ -1635,7 +1635,8 @@ spdk_nvmf_rdma_create(struct spdk_nvmf_transport_opts *opts) uint32_t sge_count; const struct spdk_mem_map_ops nvmf_rdma_map_ops = { - .notify_cb = spdk_nvmf_rdma_mem_notify + .notify_cb = spdk_nvmf_rdma_mem_notify, + .are_contiguous = NULL }; rtransport = calloc(1, sizeof(*rtransport)); diff --git a/test/env/memory/memory_ut.c b/test/env/memory/memory_ut.c index 39a80c121..1171cec96 100644 --- a/test/env/memory/memory_ut.c +++ b/test/env/memory/memory_ut.c @@ -96,8 +96,20 @@ test_mem_map_notify(void *cb_ctx, struct spdk_mem_map *map, return 0; } +static int +test_check_regions_contiguous(uint64_t addr1, uint64_t addr2) +{ + return addr1 == addr2; +} + const struct spdk_mem_map_ops test_mem_map_ops = { - .notify_cb = test_mem_map_notify + .notify_cb = test_mem_map_notify, + .are_contiguous = test_check_regions_contiguous +}; + +const struct spdk_mem_map_ops test_mem_map_ops_no_contig = { + .notify_cb = test_mem_map_notify, + .are_contiguous = NULL }; static void @@ -119,6 +131,7 @@ test_mem_map_translation(void) struct spdk_mem_map *map; uint64_t default_translation = 0xDEADBEEF0BADF00D; uint64_t addr; + uint64_t mapping_length; int rc; map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL); @@ -144,6 +157,12 @@ test_mem_map_translation(void) rc = spdk_mem_map_set_translation(map, 0, 3 * VALUE_2MB, 0); CU_ASSERT(rc == 0); + /* Make sure we indicate that the three regions are contiguous */ + mapping_length = VALUE_2MB * 3; + addr = spdk_mem_map_translate(map, 0, &mapping_length); + CU_ASSERT(addr == 0); + CU_ASSERT(mapping_length == VALUE_2MB * 3) + /* Clear translation for the middle page of the larger region. */ rc = spdk_mem_map_clear_translation(map, VALUE_2MB, VALUE_2MB); CU_ASSERT(rc == 0); @@ -152,6 +171,18 @@ test_mem_map_translation(void) addr = spdk_mem_map_translate(map, 0, NULL); CU_ASSERT(addr == 0); + /* Make sure we indicate that the three regions are no longer contiguous */ + mapping_length = VALUE_2MB * 3; + addr = spdk_mem_map_translate(map, 0, &mapping_length); + CU_ASSERT(addr == 0); + CU_ASSERT(mapping_length == VALUE_2MB) + + /* Get translation for an unallocated block. Make sure size is 0 */ + mapping_length = VALUE_2MB * 3; + addr = spdk_mem_map_translate(map, VALUE_2MB, &mapping_length); + CU_ASSERT(addr == default_translation); + CU_ASSERT(mapping_length == VALUE_2MB) + /* Verify translation for 2nd page is the default */ addr = spdk_mem_map_translate(map, VALUE_2MB, NULL); CU_ASSERT(addr == default_translation); @@ -199,6 +230,27 @@ test_mem_map_translation(void) spdk_mem_map_free(&map); CU_ASSERT(map == NULL); + + /* Allocate a map without a contiguous region checker */ + map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops_no_contig, NULL); + SPDK_CU_ASSERT_FATAL(map != NULL); + + /* map three contiguous regions */ + rc = spdk_mem_map_set_translation(map, 0, 3 * VALUE_2MB, 0); + CU_ASSERT(rc == 0); + + /* Since we can't check their contiguity, make sure we only return the size of one page */ + mapping_length = VALUE_2MB * 3; + addr = spdk_mem_map_translate(map, 0, &mapping_length); + CU_ASSERT(addr == 0); + CU_ASSERT(mapping_length == VALUE_2MB) + + /* Clear the translation */ + rc = spdk_mem_map_clear_translation(map, 0, VALUE_2MB * 3); + CU_ASSERT(rc == 0); + + spdk_mem_map_free(&map); + CU_ASSERT(map == NULL); } static void diff --git a/test/env/vtophys/vtophys.c b/test/env/vtophys/vtophys.c index 0387e36c2..ea01a7df8 100644 --- a/test/env/vtophys/vtophys.c +++ b/test/env/vtophys/vtophys.c @@ -136,7 +136,8 @@ mem_map_test(void) struct spdk_mem_map *map; uint64_t default_translation = 0xDEADBEEF0BADF00D; const struct spdk_mem_map_ops test_map_ops = { - .notify_cb = test_map_notify + .notify_cb = test_map_notify, + .are_contiguous = NULL };