diff --git a/README.md b/README.md index 0cfc50cdc..048bcfaf7 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,8 @@ so it should be used with a pool manager that will take over the managing of the provided memory - for example the jemalloc pool with the `disable_provider_free` parameter set to true. +The memory visibility mode parameter must be set to `UMF_MEM_MAP_SYNC` in case of FSDAX. + ##### Requirements 1) Linux OS diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h index fb217a0e8..073b04efb 100644 --- a/include/umf/memory_provider.h +++ b/include/umf/memory_provider.h @@ -20,7 +20,8 @@ extern "C" { /// @brief Memory visibility mode typedef enum umf_memory_visibility_t { UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping - UMF_MEM_MAP_SHARED, ///< shared memory mapping (supported on Linux only) + UMF_MEM_MAP_SHARED, ///< shared memory mapping (Linux only) + UMF_MEM_MAP_SYNC, ///< direct mapping of persistent memory (supported only for files supporting DAX, Linux only) } umf_memory_visibility_t; /// @brief Protection of the memory allocations diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index ed0c2a25d..45fc725cc 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -130,8 +130,13 @@ static umf_result_t devdax_initialize(void *params, void **provider) { goto err_free_devdax_provider; } - devdax_provider->base = utils_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + unsigned map_sync_flag = 0; + utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + + // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + devdax_provider->base = utils_mmap_file(NULL, devdax_provider->size, + devdax_provider->protection, + map_sync_flag, fd, 0 /* offset */); utils_close_fd(fd); if (devdax_provider->base == NULL) { LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", @@ -458,8 +463,13 @@ static umf_result_t devdax_open_ipc_handle(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - char *base = utils_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + unsigned map_sync_flag = 0; + utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + + // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + char *base = utils_mmap_file(NULL, devdax_provider->size, + devdax_provider->protection, map_sync_flag, fd, + 0 /* offset */); if (base == NULL) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, errno); diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 757dcb1d0..ed9b23164 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -261,7 +261,7 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, ASSERT_IS_ALIGNED(extended_size, page_size); ASSERT_IS_ALIGNED(offset_fd, page_size); - void *ptr = utils_mmap(NULL, extended_size, prot, flag, fd, offset_fd); + void *ptr = utils_mmap_file(NULL, extended_size, prot, flag, fd, offset_fd); if (ptr == NULL) { LOG_PERR("memory mapping failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; @@ -612,8 +612,9 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *ptr = utils_mmap(NULL, file_ipc_data->size, file_provider->protection, - file_provider->visibility, fd, file_ipc_data->offset_fd); + *ptr = utils_mmap_file(NULL, file_ipc_data->size, file_provider->protection, + file_provider->visibility, fd, + file_ipc_data->offset_fd); (void)utils_close_fd(fd); if (*ptr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index a58614061..999fc5745 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -124,7 +124,8 @@ int utils_set_file_size(int fd, size_t size); void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, size_t fd_offset); -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd); +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset); int utils_munmap(void *addr, size_t length); diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index f5f76be21..f1e6beb5d 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -31,29 +31,65 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, case UMF_MEM_MAP_SHARED: *out_flag = MAP_SHARED; return UMF_RESULT_SUCCESS; + case UMF_MEM_MAP_SYNC: + *out_flag = MAP_SYNC; + return UMF_RESULT_SUCCESS; } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } /* - * MMap a /dev/dax device. - * First try to mmap with (MAP_SHARED_VALIDATE | MAP_SYNC) flags - * which allows flushing from the user-space. If MAP_SYNC fails - * try to mmap with MAP_SHARED flag (without MAP_SYNC). + * Map given file into memory. + * If (flags & MAP_PRIVATE) it uses just mmap. Otherwise, if (flags & MAP_SYNC) + * it tries to mmap with (flags | MAP_SHARED_VALIDATE | MAP_SYNC) + * which allows flushing from the user-space. If MAP_SYNC fails and the user + * did not specify it by himself it tries to mmap with (flags | MAP_SHARED). */ -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { - void *ptr = utils_mmap(hint_addr, length, prot, - MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); - if (ptr) { - LOG_DEBUG( - "devdax mapped with the (MAP_SHARED_VALIDATE | MAP_SYNC) flags"); - return ptr; - } - - ptr = utils_mmap(hint_addr, length, prot, MAP_SHARED, fd, 0); - if (ptr) { - LOG_DEBUG("devdax mapped with the MAP_SHARED flag"); - return ptr; +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { + void *addr; + + /* + * MAP_PRIVATE and MAP_SHARED are mutually exclusive, + * therefore mmap with MAP_PRIVATE is executed separately. + */ + if (flags & MAP_PRIVATE) { + addr = utils_mmap(hint_addr, length, prot, flags, fd, fd_offset); + if (addr == MAP_FAILED) { + LOG_PERR("mapping file with the MAP_PRIVATE flag failed"); + return NULL; + } + + LOG_DEBUG("file mapped with the MAP_PRIVATE flag"); + return addr; + } + + errno = 0; + + if (flags & MAP_SYNC) { + /* try to mmap with MAP_SYNC flag */ + const int sync_flags = MAP_SHARED_VALIDATE | MAP_SYNC; + addr = utils_mmap(hint_addr, length, prot, flags | sync_flags, fd, + fd_offset); + if (addr) { + LOG_DEBUG("file mapped with the MAP_SYNC flag"); + return addr; + } + + LOG_PERR("mapping file with the MAP_SYNC flag failed"); + } + + if ((!(flags & MAP_SYNC)) || errno == EINVAL || errno == ENOTSUP || + errno == EOPNOTSUPP) { + /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ + const int shared_flags = (flags & (~MAP_SYNC)) | MAP_SHARED; + addr = utils_mmap(hint_addr, length, prot, shared_flags, fd, fd_offset); + if (addr) { + LOG_DEBUG("file mapped with the MAP_SHARED flag"); + return addr; + } + + LOG_PERR("mapping file with the MAP_SHARED flag failed"); } return NULL; diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index 9c91e2b01..586f0fa52 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -23,15 +23,20 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX + case UMF_MEM_MAP_SYNC: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused + (void)flags; // unused (void)fd; // unused + (void)fd_offset; // unused return NULL; // not supported } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 33faa1b97..4646b6f55 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -96,6 +96,8 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet + case UMF_MEM_MAP_SYNC: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -145,12 +147,15 @@ void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot); } -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused + (void)flags; // unused (void)fd; // unused - return NULL; // not supported on Windows + (void)fd_offset; // unused + return NULL; // not supported } int utils_munmap(void *addr, size_t length) {