env: Add spdk_mem_reserve

The spdk_mem_reserve() function reserves a memory region in SPDK's
memory maps. This pre-allocates all of the required data structures
to hold memory address translations for that region without actually
populating the region.

After a region is reserved, calls to spdk_mem_register() for
addresses in that range will not require any internal memory
allocations. This is useful when overlaying a custom memory allocator
on top of SPDK's hugepage memory, such as tcmalloc.

Signed-off-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2511 (master)

This backport requires increasing SO_MINOR version, since it adds
new API. Version 2.1 does not conflict with any other, since on master
the API was increased from 2 to 3 SO_VER see:
(229ef16b) lib/env_dpdk: add map file and rev so major version.

(cherry picked from commit cf450c0d7c)
Change-Id: Ia4e8a770e8b5c956814aa90e9119013356dfab46
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2600
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Ben Walker 2020-05-18 11:05:43 -07:00 committed by Tomasz Zawadzki
parent e8d8cef0fd
commit d635d6d297
3 changed files with 69 additions and 0 deletions

View File

@ -1241,6 +1241,20 @@ int spdk_mem_register(void *vaddr, size_t len);
*/
int spdk_mem_unregister(void *vaddr, size_t len);
/**
* Reserve the address space specified in all memory maps.
*
* This pre-allocates the necessary space in the memory maps such that
* future calls to spdk_mem_register() on that region require no
* internal memory allocations.
*
* \param vaddr Virtual address to reserve
* \param len Length in bytes of vaddr
*
* \return 0 on success, negated errno on failure.
*/
int spdk_mem_reserve(void *vaddr, size_t len);
#ifdef __cplusplus
}
#endif

View File

@ -34,6 +34,10 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SO_VER := 2
SO_MINOR := 1
SO_SUFFIX := $(SO_VER).$(SO_MINOR)
CFLAGS += $(ENV_CFLAGS)
C_SRCS = env.c memory.c pci.c init.c threads.c
C_SRCS += pci_nvme.c pci_ioat.c pci_virtio.c pci_vmd.c

View File

@ -508,6 +508,57 @@ spdk_mem_unregister(void *vaddr, size_t len)
return 0;
}
int
spdk_mem_reserve(void *vaddr, size_t len)
{
struct spdk_mem_map *map;
void *seg_vaddr;
size_t seg_len;
uint64_t reg;
if ((uintptr_t)vaddr & ~MASK_256TB) {
DEBUG_PRINT("invalid usermode virtual address %p\n", vaddr);
return -EINVAL;
}
if (((uintptr_t)vaddr & MASK_2MB) || (len & MASK_2MB)) {
DEBUG_PRINT("invalid %s parameters, vaddr=%p len=%ju\n",
__func__, vaddr, len);
return -EINVAL;
}
if (len == 0) {
return 0;
}
pthread_mutex_lock(&g_spdk_mem_map_mutex);
/* Check if any part of this range is already registered */
seg_vaddr = vaddr;
seg_len = len;
while (seg_len > 0) {
reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL);
if (reg & REG_MAP_REGISTERED) {
pthread_mutex_unlock(&g_spdk_mem_map_mutex);
return -EBUSY;
}
seg_vaddr += VALUE_2MB;
seg_len -= VALUE_2MB;
}
/* Simply set the translation to the memory map's default. This allocates the space in the
* map but does not provide a valid translation. */
spdk_mem_map_set_translation(g_mem_reg_map, (uint64_t)vaddr, len,
g_mem_reg_map->default_translation);
TAILQ_FOREACH(map, &g_spdk_mem_maps, tailq) {
spdk_mem_map_set_translation(map, (uint64_t)vaddr, len, map->default_translation);
}
pthread_mutex_unlock(&g_spdk_mem_map_mutex);
return 0;
}
static struct map_1gb *
spdk_mem_map_get_map_1gb(struct spdk_mem_map *map, uint64_t vfn_2mb)
{