Commit ed0ce0fc authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

memory: include contiguous areas w/ 4KB pages when translating



When translating a contiguous region of memory that includes a 4KB
mappings, the length will now include this 4KB portion.  Identifying
whether pointers passed to the are_contiguous() callback refer to a 4KB
or a 2MB page is the responsibility of the user.

Change-Id: I68c97414e10bb508313e4939db76aeeefe12e9f8
Signed-off-by: default avatarKonrad Sztyber <ksztyber@nvidia.com>
Reviewed-on: https://review.spdk.io/c/spdk/spdk/+/26214


Community-CI: Mellanox Build Bot
Reviewed-by: default avatarBen Walker <ben@nvidia.com>
Reviewed-by: default avatarJim Harris <jim.harris@nvidia.com>
Tested-by: default avatarSPDK Automated Test System <spdkbot@gmail.com>
parent d8bfa4f5
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -818,7 +818,6 @@ spdk_mem_map_clear_translation(struct spdk_mem_map *map, uint64_t vaddr, uint64_
inline uint64_t
spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t *size)
{
	uint64_t vfn_2mb;
	uint64_t cur_size;
	uint64_t prev_translation;
	uint64_t orig_translation;
@@ -830,13 +829,10 @@ spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t
		return map->default_translation;
	}

	vfn_2mb = VFN_2MB(vaddr);
	curr_translation = mem_map_translate(map, vaddr, &page_size);
	cur_size = page_size - (page_size == VALUE_4KB ? _4KB_OFFSET(vaddr) : _2MB_OFFSET(vaddr));

	/* For now, we only support mappings spanning across multiple pages if they're 2MB */
	if (size == NULL || map->ops.are_contiguous == NULL ||
	    curr_translation == map->default_translation || page_size == VALUE_4KB) {
	    curr_translation == map->default_translation) {
		if (size != NULL) {
			*size = spdk_min(*size, cur_size);
		}
@@ -844,15 +840,15 @@ spdk_mem_map_translate(const struct spdk_mem_map *map, uint64_t vaddr, uint64_t
	}

	prev_translation = orig_translation = curr_translation;
	vaddr += cur_size;
	while (cur_size < *size) {
		vfn_2mb++;
		curr_translation = mem_map_translate(map, vfn_2mb << SHIFT_2MB, &page_size);
		if (page_size == VALUE_4KB ||
		    !map->ops.are_contiguous(prev_translation, curr_translation)) {
		curr_translation = mem_map_translate(map, vaddr, &page_size);
		if (!map->ops.are_contiguous(prev_translation, curr_translation)) {
			break;
		}

		cur_size += VALUE_2MB;
		cur_size += page_size;
		vaddr += page_size;
		prev_translation = curr_translation;
	}

+119 −2
Original line number Diff line number Diff line
@@ -163,6 +163,11 @@ struct spdk_mem_map_ops test_map_ops_notify_checklen = {
};

struct spdk_mem_map_ops test_map_ops_notify_nop = {
	.notify_cb = test_mem_map_notify_nop,
	.are_contiguous = test_check_regions_contiguous
};

struct spdk_mem_map_ops test_map_ops_notify_nop_no_contig = {
	.notify_cb = test_mem_map_notify_nop,
	.are_contiguous = NULL
};
@@ -486,7 +491,7 @@ test_mem_map_4kb(void)
	uint64_t i, addr, traddr, size;
	int rc;

	map = spdk_mem_map_alloc(default_translation, &test_map_ops_notify_nop, NULL);
	map = spdk_mem_map_alloc(default_translation, &test_map_ops_notify_nop_no_contig, NULL);
	SPDK_CU_ASSERT_FATAL(map != NULL);

	/* Check single 4KB page translation */
@@ -741,6 +746,117 @@ test_mem_map_4kb(void)
	CU_ASSERT(map == NULL);
}

static void
test_mem_map_4kb_contig_pages(void)
{
	struct spdk_mem_map *map;
	const uint64_t default_translation = 0xDEADBEEF0BADF00D;
	uint64_t i, addr, traddr, size;
	int rc;

	/* The ops treats adjescent pages with the same translation as contiguous */
	map = spdk_mem_map_alloc(default_translation, &test_map_ops_notify_nop, NULL);
	SPDK_CU_ASSERT_FATAL(map != NULL);

	/* Check two regions: 2x4KB pages + 3x4KB pages immediatelly following it */
	addr = 0;
	rc = spdk_mem_map_set_translation(map, addr, 2 * VALUE_4KB, 0xfeedbeeff00d0);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr + 2 * VALUE_4KB, 3 * VALUE_4KB, 0xfeedbeeff00d1);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d0);
	CU_ASSERT_EQUAL(size, 2 * VALUE_4KB - 1);
	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + 2 * VALUE_4KB + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d1);
	CU_ASSERT_EQUAL(size, 3 * VALUE_4KB - 1);
	traddr = spdk_mem_map_translate(map, addr + 5 * VALUE_4KB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	/* Check 2x4KB contiguous pages created via two set_translation() calls  */
	addr = VALUE_2MB;
	rc = spdk_mem_map_set_translation(map, addr, VALUE_4KB, 0xfeedbeeff00d2);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr + VALUE_4KB, VALUE_4KB, 0xfeedbeeff00d2);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d2);
	CU_ASSERT_EQUAL(size, 2 * VALUE_4KB - 1);
	traddr = spdk_mem_map_translate(map, addr + 2 * VALUE_4KB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	/* Check contiguous region consisting of 2x4KB pages + 2x2MB pages */
	addr = 2 * VALUE_2MB;
	rc = spdk_mem_map_set_translation(map, addr - 2 * VALUE_4KB, 2 * VALUE_4KB, 0xfeedbeeff00d3);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr, 2 * VALUE_2MB, 0xfeedbeeff00d3);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr - 2 * VALUE_4KB + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d3);
	CU_ASSERT_EQUAL(size, 2 * VALUE_4KB + 2 * VALUE_2MB - 1);
	traddr = spdk_mem_map_translate(map, addr + 2 * VALUE_4KB + 2 * VALUE_2MB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	/* Check the same, but switch the order (i.e. 2x4KB + 2x2MB -> 2x2MB + 2x4KB) */
	addr = 4 * VALUE_2MB;
	rc = spdk_mem_map_set_translation(map, addr, 2 * VALUE_2MB, 0xfeedbeeff00d4);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr + 2 * VALUE_2MB, 2 * VALUE_4KB, 0xfeedbeeff00d4);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d4);
	CU_ASSERT_EQUAL(size, 2 * VALUE_4KB + 2 * VALUE_2MB - 1);
	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + VALUE_4KB + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d4);
	CU_ASSERT_EQUAL(size, VALUE_4KB + 2 * VALUE_2MB - 1);
	traddr = spdk_mem_map_translate(map, addr + 2 * VALUE_4KB + 2 * VALUE_2MB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	/* Check 4KB + 2MB + 4KB */
	addr = 7 * VALUE_2MB;
	rc = spdk_mem_map_set_translation(map, addr - VALUE_4KB, VALUE_4KB, 0xfeedbeeff00d5);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr, VALUE_2MB, 0xfeedbeeff00d5);
	CU_ASSERT_EQUAL(rc, 0);
	rc = spdk_mem_map_set_translation(map, addr + VALUE_2MB, VALUE_4KB, 0xfeedbeeff00d5);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr - VALUE_4KB + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d5);
	CU_ASSERT_EQUAL(size, 2 * VALUE_4KB + VALUE_2MB - 1);
	traddr = spdk_mem_map_translate(map, addr + VALUE_4KB + VALUE_2MB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	/* Check a region consisting of a 2MB page created via 4KB mappings plus a 2MB page */
	addr = 9 * VALUE_2MB;
	for (i = 0; i < VALUE_2MB; i += VALUE_4KB) {
		rc = spdk_mem_map_set_translation(map, addr + i, VALUE_4KB, 0xfeedbeeff00d6);
		CU_ASSERT_EQUAL(rc, 0);
	}
	rc = spdk_mem_map_set_translation(map, addr + VALUE_2MB, VALUE_2MB, 0xfeedbeeff00d6);
	CU_ASSERT_EQUAL(rc, 0);

	size = VALUE_1GB;
	traddr = spdk_mem_map_translate(map, addr + 1, &size);
	CU_ASSERT_EQUAL(traddr, 0xfeedbeeff00d6);
	CU_ASSERT_EQUAL(size, 2 * VALUE_2MB - 1);
	traddr = spdk_mem_map_translate(map, addr + 2 * VALUE_2MB, NULL);
	CU_ASSERT_EQUAL(traddr, default_translation);

	spdk_mem_map_free(&map);
}

int
main(int argc, char **argv)
{
@@ -774,7 +890,8 @@ main(int argc, char **argv)
		CU_add_test(suite, "mem_map_translation", test_mem_map_translation) == NULL ||
		CU_add_test(suite, "mem_map_registration", test_mem_map_registration) == NULL ||
		CU_add_test(suite, "mem_map_adjacent_registrations", test_mem_map_registration_adjacent) == NULL ||
		CU_add_test(suite, "mem_map_4kb", test_mem_map_4kb) == NULL
		CU_add_test(suite, "mem_map_4kb", test_mem_map_4kb) == NULL ||
		CU_add_test(suite, "mem_map_4kb_contig_pages", test_mem_map_4kb_contig_pages) == NULL
	) {
		CU_cleanup_registry();
		return CU_get_error();