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