diff --git a/lib/env_dpdk/memory.c b/lib/env_dpdk/memory.c index 204fa321e..76a08ed12 100644 --- a/lib/env_dpdk/memory.c +++ b/lib/env_dpdk/memory.c @@ -377,7 +377,7 @@ spdk_mem_unregister(void *vaddr, size_t len) int rc; void *seg_vaddr; size_t seg_len; - uint64_t reg; + uint64_t reg, newreg; if ((uintptr_t)vaddr & ~MASK_256TB) { DEBUG_PRINT("invalid usermode virtual address %p\n", vaddr); @@ -392,6 +392,16 @@ spdk_mem_unregister(void *vaddr, size_t len) pthread_mutex_lock(&g_spdk_mem_map_mutex); + /* The first page must be a start of a region. Also check if it's + * registered to make sure we don't return -ERANGE for non-registered + * regions. + */ + reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)vaddr, NULL); + if ((reg & REG_MAP_REGISTERED) && (reg & REG_MAP_NOTIFY_START) == 0) { + pthread_mutex_unlock(&g_spdk_mem_map_mutex); + return -ERANGE; + } + seg_vaddr = vaddr; seg_len = len; while (seg_len > 0) { @@ -404,8 +414,17 @@ spdk_mem_unregister(void *vaddr, size_t len) seg_len -= VALUE_2MB; } + newreg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)seg_vaddr, NULL); + /* If the next page is registered, it must be a start of a region as well, + * otherwise we'd be unregistering only a part of a region. + */ + if ((newreg & REG_MAP_NOTIFY_START) == 0 && (newreg & REG_MAP_REGISTERED)) { + pthread_mutex_unlock(&g_spdk_mem_map_mutex); + return -ERANGE; + } seg_vaddr = vaddr; seg_len = 0; + while (len > 0) { reg = spdk_mem_map_translate(g_mem_reg_map, (uint64_t)vaddr, NULL); spdk_mem_map_set_translation(g_mem_reg_map, (uint64_t)vaddr, VALUE_2MB, 0); diff --git a/test/env/memory/memory_ut.c b/test/env/memory/memory_ut.c index 5d928e832..e9be93d05 100644 --- a/test/env/memory/memory_ut.c +++ b/test/env/memory/memory_ut.c @@ -385,14 +385,18 @@ test_mem_map_registration(void) /* Unregister the middle page of the larger region. */ rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB); - CU_ASSERT(rc == 0); + CU_ASSERT(rc == -ERANGE); /* Unregister the first page */ rc = spdk_mem_unregister((void *)0, VALUE_2MB); - CU_ASSERT(rc == 0); + CU_ASSERT(rc == -ERANGE); /* Unregister the third page */ rc = spdk_mem_unregister((void *)(2 * VALUE_2MB), VALUE_2MB); + CU_ASSERT(rc == -ERANGE); + + /* Unregister the entire address range */ + rc = spdk_mem_unregister((void *)0, 3 * VALUE_2MB); CU_ASSERT(rc == 0); spdk_mem_map_free(&map);