Commit cf450c0d authored by Ben Walker's avatar Ben Walker Committed by Tomasz Zawadzki
Browse files

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: default avatarBen Walker <benjamin.walker@intel.com>
Change-Id: Ia4e8a770e8b5c956814aa90e9119013356dfab46
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2511


Community-CI: Mellanox Build Bot
Community-CI: Broadcom CI
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@mellanox.com>
parent 8668141b
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -1248,6 +1248,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
+51 −0
Original line number Diff line number Diff line
@@ -509,6 +509,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)
{