diff --git a/README.md b/README.md index 4ff16896efee0ab885c8d3f47c18f42723db2b80..b5271c3abf373119f201e801e0c317ae4093149c 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,7 @@ see https://github.com/pmem/pmdk/issues/4207. * **MS Visual Studio 2015** * [Windows SDK 10.0.17134.12](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) +* **Windows, version >= 1803** * **perl** (i.e. [StrawberryPerl](http://strawberryperl.com/)) * **PowerShell 5** diff --git a/doc/libpmem2/pmem2_config_set_vm_reservation.3.md b/doc/libpmem2/pmem2_config_set_vm_reservation.3.md index eec77707d9c8b9453b6e16761d76e1f7265ddce2..52211820e323eda3adbdaa5b0e618a78cf950c7f 100644 --- a/doc/libpmem2/pmem2_config_set_vm_reservation.3.md +++ b/doc/libpmem2/pmem2_config_set_vm_reservation.3.md @@ -16,7 +16,6 @@ date: pmem2 API version 1.0 [SYNOPSIS](#synopsis)<br /> [DESCRIPTION](#description)<br /> [RETURN VALUE](#return-value)<br /> -[ERRORS](#errors)<br /> [SEE ALSO](#see-also)<br /> # NAME # @@ -31,22 +30,21 @@ values in the pmem2_config structure struct pmem2_config; struct pmem2_vm_reservation; -int pmem2_config_set_vm_reservation(struct pmem2_config *cfg, - struct pmem2_vm_reservation *rsv, size_t offset); +int pmem2_config_set_vm_reservation(struct pmem2_config *config, + struct pmem2_vm_reservation *rsv, size_t rsv_offset); ``` # DESCRIPTION # -The **pmem2_config_set_vm_reservation**() function is not supported yet. +The **pmem2_config_set_vm_reservation**() function sets the virtual memory reservation +and an offset to be used during a mapping. *rsv* should be already initialized. Please see +**pmem2_vm_reservation_new**(3) for details. *rsv_offset* marks the offset in the +reservation for the mapping. # RETURN VALUE # -**pmem2_config_set_vm_reservation**() returns PMEM2_E_NOSUPP . - -# ERRORS # - -The **pmem2_config_set_vm_reservation**() function is not supported yet. +**pmem2_config_set_vm_reservation**() function always returns 0. # SEE ALSO # -**libpmem2**(7), **pmem2_vm_reservation_new**(3) and **<http://pmem.io>** +**pmem2_vm_reservation_new**(3), **libpmem2**(7) and **<http://pmem.io>** diff --git a/doc/libpmem2/pmem2_map_new.3.md b/doc/libpmem2/pmem2_map_new.3.md index 148d702419d32e8381046625c4b8c2d080915873..12f1a36158e4a04fe6efda579010fe81a95a3a87 100644 --- a/doc/libpmem2/pmem2_map_new.3.md +++ b/doc/libpmem2/pmem2_map_new.3.md @@ -91,6 +91,10 @@ the alignment required for specific *\*source*. Please see * **PMEM2_E_SRC_DEVDAX_PRIVATE** - device DAX mapped with MAP_PRIVATE. (Linux only) +* **PMEM2_E_ADDRESS_UNALIGNED** - when mapping device DAX to a virtual memory reservation +and the base mapping address (reservation address + reservation offset) is not aligned +to the device DAX granularity. Please see **pmem2_config_set_vm_reservation**(3). (Linux only) + * **PMEM2_E_NOSUPP** - when config-provided protection flags combination is not supported. * **PMEM2_E_NO_ACCESS** - there is a conflict between mapping protection and file opening mode. diff --git a/doc/libpmem2/pmem2_vm_reservation_get_address.3.md b/doc/libpmem2/pmem2_vm_reservation_get_address.3.md new file mode 100644 index 0000000000000000000000000000000000000000..41abc87c245baea62f0dc6bf20c621a7c1e98989 --- /dev/null +++ b/doc/libpmem2/pmem2_vm_reservation_get_address.3.md @@ -0,0 +1,46 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(PMEM2_VM_RESERVATION_GET_ADDRESS, 3) +collection: libpmem2 +header: PMDK +date: pmem2 API version 1.0 +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2020, Intel Corporation) + +[comment]: <> (pmem2_vm_reservation_get_address.3 -- man page for libpmem2 pmem2_vm_reservation_get_address operation) + +[NAME](#name)<br /> +[SYNOPSIS](#synopsis)<br /> +[DESCRIPTION](#description)<br /> +[RETURN VALUE](#return-value)<br /> +[SEE ALSO](#see-also)<br /> + +# NAME # + +**pmem2_vm_reservation_get_address**() - reads address of the virtual memory reservation + +# SYNOPSIS # + +```c +#include <libpmem2.h> + +void *pmem2_vm_reservation_get_address(struct pmem2_vm_reservation *rsv); +``` + +# DESCRIPTION # + +The **pmem2_vm_reservation_get_address**() function reads address of the created virtual memory +reservation. The *rsv* parameter points to the structure describing the reservation created using +the **pmem2_vm_reservation_new**(3) function. + +# RETURN VALUE # + +The **pmem2_vm_reservation_get_address**() function returns a pointer to the virtual memory +reservation area. + +# SEE ALSO # + +**pmem2_vm_reservation_new**(3), **libpmem2**(7) and **<https://pmem.io>** diff --git a/doc/libpmem2/pmem2_vm_reservation_get_size.3.md b/doc/libpmem2/pmem2_vm_reservation_get_size.3.md new file mode 100644 index 0000000000000000000000000000000000000000..ccf704829407e530ebd6e7c4f4b962b0f0fb50de --- /dev/null +++ b/doc/libpmem2/pmem2_vm_reservation_get_size.3.md @@ -0,0 +1,45 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(PMEM2_VM_RESERVATION_GET_SIZE, 3) +collection: libpmem2 +header: PMDK +date: pmem2 API version 1.0 +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2020, Intel Corporation) + +[comment]: <> (pmem2_vm_reservation_get_size.3 -- man page for libpmem2 virtual memory reservation operation) + +[NAME](#name)<br /> +[SYNOPSIS](#synopsis)<br /> +[DESCRIPTION](#description)<br /> +[RETURN VALUE](#return-value)<br /> +[SEE ALSO](#see-also)<br /> + +# NAME # + +**pmem2_vm_reservation_get_size**() - reads virtual memory reservation size + +# SYNOPSIS # + +```c +#include <libpmem2.h> + +size_t pmem2_vm_reservation_get_size(struct pmem2_vm_reservation *rsv); +``` + +# DESCRIPTION # + +The **pmem2_vm_reservation_get_size**() function reads size of the created virtual memory +reservation. The *rsv* parameter points to the structure describing virtual memory reservation +created using the **pmem2_vm_reservation_new**(3) function. + +# RETURN VALUE # + +The **pmem2_vm_reservation_get_size**() function returns a size of the virtual reservation area. + +# SEE ALSO # + +**pmem2_vm_reservation_new**(3), **libpmem2**(7) and **<https://pmem.io>** diff --git a/doc/libpmem2/pmem2_vm_reservation_new.3.md b/doc/libpmem2/pmem2_vm_reservation_new.3.md index f04b2cdc3910a0478da07c4434f6e556b838ee84..b9cba1f4cf26abbbb269ea266f07e745eb2d7aac 100644 --- a/doc/libpmem2/pmem2_vm_reservation_new.3.md +++ b/doc/libpmem2/pmem2_vm_reservation_new.3.md @@ -21,8 +21,8 @@ date: pmem2 API version 1.0 # NAME # -**pmem2_vm_reservation_new**(), **pmem2_vm_reservation_delete**() - creates or deletes virtual memory -reservation that is made basing on the pmem2_vm_reservation structure +**pmem2_vm_reservation_new**(), **pmem2_vm_reservation_delete**() - creates or deletes +an instance of virtual memory reservation # SYNOPSIS # @@ -30,19 +30,58 @@ reservation that is made basing on the pmem2_vm_reservation structure #include <libpmem2.h> struct pmem2_vm_reservation; -void pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv, - size_t size, void *address); -void pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv); +void pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv_ptr, + void *addr, size_t size); +void pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv_ptr); ``` # DESCRIPTION # -**pmem2_vm_reservation_new**() and **pmem2_vm_reservation_delete**() functions are not supported yet. +The **pmem2_vm_reservation_new**() function creates a new blank mapping in the +virtual address space of the calling process. Reservation serves as a placeholder +of a given size on which sources can be mapped. + +For the function to succeed, the *addr* must be either aligned to an appropriate allocation granularity, +or be a NULL, the size has to be aligned to an appropraite allocation granularity. + +If the **pmem2_vm_reservation_new**() succeeds in creating a reservation, it instantiates a new +*struct pmem2_vm_reservation** object describing the reservation. The pointer to this object +is stored in the user-provided variable via the *rsv_ptr* pointer. If the function fails, an appropriate +error value will be returned. For a list of possible return values please see [RETURN VALUE](#return-value) + +After instantiating an object via the **pmem2_vm_reservation_new**() function, it is necessary to +finalize it using the **pmem2_vm_reservation_delete**() function. + +The **pmem2_vm_reservation_delete**() function destroys the object describing the reservation and unmaps +virtual memory region the *struct pmem2_vm_reservation** had assigned during the initialization. + +For the function to succeed, it is required that the reservation passed via the *rsv_ptr* pointer will not +contain any mappings. # RETURN VALUE # -**pmem2_vm_reservation_new**() returns PMEM2_E_NOSUPP . -**pmem2_vm_reservation_delete**() returns PMEM2_E_NOSUPP . +The **pmem2_vm_reservation_new**() and **pmem2_vm_reservation_delete**() functions return 0 +on success or a negative error code on failure. + +The function returns 0 on success or a negative error code on failure. + +# ERRORS # + +The **pmem2_vm_reservation_new**() function can fail with the following errors: + +* **PMEM2_E_ADDRESS_UNALIGNED** - argument *addr* is not aligned to the appropriate +allocation granularity. + +* **PMEM2_E_MAPPING_EXISTS** - mapping already exists in the range (*addr*, *addr* + *size*). + +It can also return **-EAGAIN**, **-ENOMEM** from the underlying **mmap**(2) function and **-ENOMEM** +in case of insufficient memory to allocate an instance of *struct pmem2_vm_reservation*. + +The **pmem2_vm_reservation_delete**() function can fail with the following errors: + +* **PMEM2_E_RESERVATION_NOT_EMPTY** - reservation contains mappings. + +It can also return errors from the underlying **munmap**(2) function. # ERRORS # @@ -50,4 +89,4 @@ The **pmem2_vm_reservation_new**() and **pmem2_vm_reservation_delete**() functio # SEE ALSO # -**libpmem2**(7), **pmem2_config_set_vm_reservation**(3) and **<http://pmem.io>** +**pmem2_config_set_vm_reservation**(3), **libpmem2**(7) and **<http://pmem.io>** diff --git a/src/PMDK.sln b/src/PMDK.sln index afb0919df18cb8b9fc4ad6345683e622be9dcde2..7a5569642e1dc74ed34932b89f9df93919cf27c2 100644 --- a/src/PMDK.sln +++ b/src/PMDK.sln @@ -208,6 +208,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sys", "sys", "{45027FC5-4A3 windows\include\sys\wait.h = windows\include\sys\wait.h EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem2_vm_reservation", "test\pmem2_vm_reservation\pmem2_vm_reservation.vcxproj", "{46629F21-089C-4205-B2F8-E01748ECE517}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctl_cow", "test\ctl_cow\ctl_cow.vcxproj", "{46B82069-10BE-432A-8D93-F4D995148555}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_lookup", "test\obj_pool_lookup\obj_pool_lookup.vcxproj", "{4850F425-9128-4E91-973C-5AE7BD97395B}" @@ -540,9 +542,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pmalloc_mt", "test\obj_pmalloc_mt\obj_pmalloc_mt.vcxproj", "{9FF62356-30B4-42A1-8DC7-45262A18DD44}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libpmem2", "libpmem2", "{A14A4556-9092-430D-B9CA-B2B1223D56CB}" - ProjectSection(SolutionItems) = preProject - test\pmem2_map_prot\pmem2_map_prot.vcxproj = test\pmem2_map_prot\pmem2_map_prot.vcxproj - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gran_detecto", "test\tools\gran_detecto\gran_detecto.vcxproj", "{A18B076A-CE8C-49A6-8B80-F02843E4BF0A}" EndProject @@ -1112,6 +1111,10 @@ Global {433F7840-C597-4950-84C9-E4FF7DF6A298}.Debug|x64.Build.0 = Debug|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Release|x64.ActiveCfg = Release|x64 {433F7840-C597-4950-84C9-E4FF7DF6A298}.Release|x64.Build.0 = Release|x64 + {46629F21-089C-4205-B2F8-E01748ECE517}.Debug|x64.ActiveCfg = Debug|x64 + {46629F21-089C-4205-B2F8-E01748ECE517}.Debug|x64.Build.0 = Debug|x64 + {46629F21-089C-4205-B2F8-E01748ECE517}.Release|x64.ActiveCfg = Release|x64 + {46629F21-089C-4205-B2F8-E01748ECE517}.Release|x64.Build.0 = Release|x64 {46B82069-10BE-432A-8D93-F4D995148555}.Debug|x64.ActiveCfg = Debug|x64 {46B82069-10BE-432A-8D93-F4D995148555}.Debug|x64.Build.0 = Debug|x64 {46B82069-10BE-432A-8D93-F4D995148555}.Release|x64.ActiveCfg = Release|x64 @@ -1988,6 +1991,7 @@ Global {42CCEF95-5ADD-460C-967E-DD5B2C744943} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} {433F7840-C597-4950-84C9-E4FF7DF6A298} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {45027FC5-4A32-47BD-AC5B-66CC7616B1D2} = {9A8482A7-BF0C-423D-8266-189456ED41F6} + {46629F21-089C-4205-B2F8-E01748ECE517} = {A14A4556-9092-430D-B9CA-B2B1223D56CB} {46B82069-10BE-432A-8D93-F4D995148555} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} {4850F425-9128-4E91-973C-5AE7BD97395B} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {492BAA3D-0D5D-478E-9765-500463AE69AA} = {853D45D8-980C-4991-B62A-DAC6FD245402} diff --git a/src/examples/libpmem2/map_multiple_files/map_multiple_files.c b/src/examples/libpmem2/map_multiple_files/map_multiple_files.c index dea602ca5a5d215f487e16efc253f66c959c4db8..34dade2ca71a1c8fc0514465bbe9c8706f727e5d 100644 --- a/src/examples/libpmem2/map_multiple_files/map_multiple_files.c +++ b/src/examples/libpmem2/map_multiple_files/map_multiple_files.c @@ -177,7 +177,7 @@ main(int argc, char *argv[]) } struct pmem2_vm_reservation *rsv; - if (!pmem2_vm_reservation_new(&rsv, reservation_size, NULL)) { + if (pmem2_vm_reservation_new(&rsv, NULL, reservation_size)) { pmem2_perror("pmem2_vm_reservation_new"); goto fdsc_fini; } @@ -199,7 +199,7 @@ main(int argc, char *argv[]) int nmap; for (nmap = 0; nmap < nfiles; nmap++) { if (pmem2_config_set_vm_reservation( - cfg, rsv, offset) != PMEM2_E_NOSUPP) { + cfg, rsv, offset)) { pmem2_perror("pmem2_config_set_vm_reservation"); goto unmap; } diff --git a/src/include/libpmem2.h b/src/include/libpmem2.h index f29848bb6b715702d8b4279b03039a07d06f5b25..3c2fcb77c4aa9ea4165980ff3a036a3928e5afbf 100644 --- a/src/include/libpmem2.h +++ b/src/include/libpmem2.h @@ -68,6 +68,7 @@ extern "C" { #define PMEM2_E_LENGTH_OUT_OF_RANGE (-100030) #define PMEM2_E_INVALID_PROT_FLAG (-100031) #define PMEM2_E_NO_ACCESS (-100032) +#define PMEM2_E_VM_RESERVATION_NOT_EMPTY (-100033) /* source setup */ @@ -90,10 +91,14 @@ int pmem2_source_delete(struct pmem2_source **src); struct pmem2_vm_reservation; -int pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv, - size_t size, void *address); +void *pmem2_vm_reservation_get_address(struct pmem2_vm_reservation *rsv); -int pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv); +size_t pmem2_vm_reservation_get_size(struct pmem2_vm_reservation *rsv); + +int pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv_ptr, + void *addr, size_t size); + +int pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv_ptr); /* config setup */ diff --git a/src/libpmem2/Makefile b/src/libpmem2/Makefile index 3e19b4ffbae825e1d13ac5c4e58d36cbcf86cfa0..4816aa3644b4905c26e2aacbecea659a1e18fd19 100644 --- a/src/libpmem2/Makefile +++ b/src/libpmem2/Makefile @@ -28,6 +28,7 @@ SOURCE =\ source.c\ source_posix.c\ vm_reservation.c\ + vm_reservation_posix.c\ ravl_interval.c ifeq ($(OS_KERNEL_NAME),Linux) diff --git a/src/libpmem2/config.c b/src/libpmem2/config.c index 0e494d5072b00573259bf3e9acb084913c315d5d..f2366ae6675b0984cac60836ab084931f7872586 100644 --- a/src/libpmem2/config.c +++ b/src/libpmem2/config.c @@ -26,6 +26,8 @@ pmem2_config_init(struct pmem2_config *cfg) cfg->requested_max_granularity = PMEM2_GRANULARITY_INVALID; cfg->sharing = PMEM2_SHARED; cfg->protection_flag = PMEM2_PROT_READ | PMEM2_PROT_WRITE; + cfg->reserv = NULL; + cfg->reserv_offset = 0; } /* @@ -229,7 +231,10 @@ int pmem2_config_set_vm_reservation(struct pmem2_config *cfg, struct pmem2_vm_reservation *rsv, size_t offset) { - return PMEM2_E_NOSUPP; + cfg->reserv = rsv; + cfg->reserv_offset = offset; + + return 0; } /* diff --git a/src/libpmem2/config.h b/src/libpmem2/config.h index 95189cbecad5a44a5677dea01f780422120e1fa3..83f22f81002c85173384af2e978e9dea3cf52483 100644 --- a/src/libpmem2/config.h +++ b/src/libpmem2/config.h @@ -22,6 +22,8 @@ struct pmem2_config { enum pmem2_granularity requested_max_granularity; enum pmem2_sharing_type sharing; /* the way the file will be mapped */ unsigned protection_flag; + struct pmem2_vm_reservation *reserv; + size_t reserv_offset; }; void pmem2_config_init(struct pmem2_config *cfg); diff --git a/src/libpmem2/libpmem2.def b/src/libpmem2/libpmem2.def index 25b7095ce004fdcd19590e6daf5f9bad283578db..86a2d6b5bb88df2ef51a5911e613758254e241dc 100644 --- a/src/libpmem2/libpmem2.def +++ b/src/libpmem2/libpmem2.def @@ -47,6 +47,8 @@ EXPORTS pmem2_source_from_handle pmem2_source_size pmem2_vm_reservation_delete + pmem2_vm_reservation_get_address + pmem2_vm_reservation_get_size pmem2_vm_reservation_new DllMain diff --git a/src/libpmem2/libpmem2.link.in b/src/libpmem2/libpmem2.link.in index 0de25abe1caf970ad30ecf3fc6a9978f43932e7b..d9a9674c2ccd692613fa39e65e3544eecc2d93c0 100644 --- a/src/libpmem2/libpmem2.link.in +++ b/src/libpmem2/libpmem2.link.in @@ -43,6 +43,8 @@ LIBPMEM2_1.0 { pmem2_source_from_handle; pmem2_source_size; pmem2_vm_reservation_delete; + pmem2_vm_reservation_get_address; + pmem2_vm_reservation_get_size; pmem2_vm_reservation_new; local: *; diff --git a/src/libpmem2/libpmem2.vcxproj b/src/libpmem2/libpmem2.vcxproj index a79d4aa8889dc656b31eebd60a2f6300c6c60da2..6492e6065e3f54c32d20b216e485470cdf94a2a5 100644 --- a/src/libpmem2/libpmem2.vcxproj +++ b/src/libpmem2/libpmem2.vcxproj @@ -38,6 +38,7 @@ <ClCompile Include="source_windows.c" /> <ClCompile Include="usc_windows.c" /> <ClCompile Include="vm_reservation.c" /> + <ClCompile Include="vm_reservation_windows.c" /> <ClCompile Include="x86_64\cpu.c" /> <ClCompile Include="x86_64\init.c" /> <ClCompile Include="x86_64\memcpy\memcpy_nt_sse2.c" /> @@ -75,6 +76,7 @@ <ClInclude Include="pmem2_utils.h" /> <ClInclude Include="ravl_interval.h" /> <ClInclude Include="source.h" /> + <ClInclude Include="vm_reservation.h" /> <ClInclude Include="x86_64\cpu.h" /> <ClInclude Include="x86_64\avx.h" /> <ClInclude Include="x86_64\flush.h" /> @@ -139,4 +141,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> +</Project> \ No newline at end of file diff --git a/src/libpmem2/libpmem2.vcxproj.filters b/src/libpmem2/libpmem2.vcxproj.filters index a9f15ab259783b58c3f365e01c5b7f68eae14538..1d2b5f0cb15d319170aaf0c9fa470811b3207f5d 100644 --- a/src/libpmem2/libpmem2.vcxproj.filters +++ b/src/libpmem2/libpmem2.vcxproj.filters @@ -132,6 +132,9 @@ <ClCompile Include="ravl_interval.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\core\os_thread.h"> @@ -203,6 +206,9 @@ <ClInclude Include="ravl_interval.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="vm_reservation.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="libpmem2.def"> @@ -214,4 +220,4 @@ <Filter>Source Files</Filter> </ResourceCompile> </ItemGroup> -</Project> +</Project> \ No newline at end of file diff --git a/src/libpmem2/map.c b/src/libpmem2/map.c index d15f30ea61f5d58e4e24792b6c1e31b21f1fbccf..edea3131c20164a85858d486ce340c852a8b3e38 100644 --- a/src/libpmem2/map.c +++ b/src/libpmem2/map.c @@ -221,7 +221,7 @@ pmem2_map_find(const void *addr, size_t len) { struct pmem2_map map; map.addr = (void *)addr; - map.reserved_length = len; + map.content_length = len; struct ravl_interval_node *node; diff --git a/src/libpmem2/map.h b/src/libpmem2/map.h index b37f22dea600b2474a856ddb51da8ffea005e775..8261ff9d8587c982b31ca9271033ca91100cec02 100644 --- a/src/libpmem2/map.h +++ b/src/libpmem2/map.h @@ -12,6 +12,7 @@ #include "libpmem2.h" #include "os.h" #include "source.h" +#include "vm_reservation.h" #ifdef _WIN32 #include <windows.h> @@ -41,8 +42,13 @@ struct pmem2_map { pmem2_memset_fn memset_fn; struct pmem2_source source; + struct pmem2_vm_reservation *reserv; }; +#ifdef _WIN32 +os_rwlock_t split_merge_lock; +#endif + enum pmem2_granularity get_min_granularity(bool eADR, bool is_pmem, enum pmem2_sharing_type sharing); struct pmem2_map *pmem2_map_find(const void *addr, size_t len); diff --git a/src/libpmem2/map_posix.c b/src/libpmem2/map_posix.c index 134d9792b5d23ef05478dd79e12479511a0985f2..fcf9891364864535aa8708018acecd6696f152a2 100644 --- a/src/libpmem2/map_posix.c +++ b/src/libpmem2/map_posix.c @@ -292,6 +292,26 @@ unmap(void *addr, size_t len) return 0; } +/* + * vm_reservation_mend -- replaces the given mapping with anonymous + * reservation, mending the reservation area + */ +static int +vm_reservation_mend(struct pmem2_vm_reservation *rsv, void *addr, size_t size) +{ + ASSERT((char *)addr >= (char *)rsv->addr && + (char *)addr + size <= (char *)rsv->addr + rsv->size); + + char *daddr = mmap(addr, size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (daddr == MAP_FAILED) { + ERR("!mmap MAP_ANONYMOUS"); + return PMEM2_E_ERRNO; + } + + return 0; +} + /* * pmem2_map_new -- map memory according to provided config */ @@ -390,17 +410,66 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, if (ret) return ret; - /* find a hint for the mapping */ - void *reserv = NULL; - ret = map_reserve(content_length, alignment, &reserv, &reserved_length, - cfg); - if (ret != 0) { - if (ret == PMEM2_E_MAPPING_EXISTS) - LOG(1, "given mapping region is already occupied"); - else - LOG(1, "cannot find a contiguous region of given size"); + /* prepare pmem2_map structure */ + map = (struct pmem2_map *)pmem2_malloc(sizeof(*map), &ret); + if (!map) return ret; + + void *reserv = NULL; + if (cfg->reserv) { + void *rsv = cfg->reserv; + void *rsv_addr = pmem2_vm_reservation_get_address(rsv); + size_t rsv_size = pmem2_vm_reservation_get_size(rsv); + size_t rsv_offset = cfg->reserv_offset; + + /* check if reservation has enough space */ + if (rsv_offset + content_length > rsv_size) { + ret = PMEM2_E_LENGTH_OUT_OF_RANGE; + goto err; + } + + if (rsv_offset % Mmap_align) { + ret = PMEM2_E_OFFSET_UNALIGNED; + ERR( + "virtual memory reservation offset %zu is not a multiple of %llu", + rsv_offset, Mmap_align); + goto err; + } + + reserv = (char *)rsv_addr + rsv_offset; + if ((size_t)reserv % alignment) { + ret = PMEM2_E_ADDRESS_UNALIGNED; + ERR( + "base mapping address %p (virtual memory reservation address + offset)" \ + " is not a multiple of %zu required by device DAX", + reserv, alignment); + goto err; + } + + reserved_length = roundup(content_length, Pagesize); + + map->addr = reserv; + map->content_length = content_length; + + /* register wanted vm reservation region */ + ret = vm_reservation_map_register(cfg->reserv, map); + if (ret) + goto err; + } else { + /* find a hint for the mapping */ + ret = map_reserve(content_length, alignment, &reserv, + &reserved_length, cfg); + if (ret != 0) { + if (ret == PMEM2_E_MAPPING_EXISTS) + LOG(1, + "given mapping region is already occupied"); + else + LOG(1, + "cannot find a contiguous region of given size"); + goto err; + } } + ASSERTne(reserv, NULL); if (cfg->sharing == PMEM2_PRIVATE) { @@ -417,16 +486,17 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, } ret = file_map(reserv, content_length, proto, flags, map_fd, off, - &map_sync, &addr); + &map_sync, &addr); if (ret) { /* unmap the reservation mapping */ munmap(reserv, reserved_length); if (ret == -EACCES) - return PMEM2_E_NO_ACCESS; + ret = PMEM2_E_NO_ACCESS; else if (ret == -ENOTSUP) - return PMEM2_E_NOSUPP; - else - return ret; + ret = PMEM2_E_NOSUPP; + else if (ret == -EEXIST) + ret = PMEM2_E_MAPPING_EXISTS; + goto err_file_map; } LOG(3, "mapped at %p", addr); @@ -448,26 +518,23 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, cfg->requested_max_granularity); ERR("%s", err); ret = PMEM2_E_GRANULARITY_NOT_SUPPORTED; - goto err; + goto err_gran_reg; } - /* prepare pmem2_map structure */ - map = (struct pmem2_map *)pmem2_malloc(sizeof(*map), &ret); - if (!map) - goto err; - map->addr = addr; map->reserved_length = reserved_length; map->content_length = content_length; map->effective_granularity = available_min_granularity; pmem2_set_flush_fns(map); pmem2_set_mem_fns(map); + map->reserv = cfg->reserv; map->source = *src; map->source.value.fd = INVALID_FD; /* fd should not be used after map */ ret = pmem2_register_mapping(map); - if (ret) - goto err_register; + if (ret) { + goto err_gran_reg; + } *map_ptr = map; @@ -479,12 +546,22 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, return 0; -err_register: - free(map); +err_gran_reg: + /* + * if the reservation was given by pmem2_config, instead of unmapping, + * we will need to mend the reservation + */ + if (cfg->reserv) + vm_reservation_mend(cfg->reserv, addr, reserved_length); + else + unmap(addr, reserved_length); +err_file_map: + if (cfg->reserv) + vm_reservation_map_unregister(cfg->reserv, map); err: - unmap(addr, reserved_length); - return ret; + free(map); + return ret; } /* @@ -504,9 +581,20 @@ pmem2_map_delete(struct pmem2_map **map_ptr) VALGRIND_REMOVE_PMEM_MAPPING(map->addr, map->content_length); - ret = unmap(map->addr, map->reserved_length); - if (ret) - return ret; + if (map->reserv) { + ret = vm_reservation_map_unregister(map->reserv, map); + if (ret) + return ret; + + ret = vm_reservation_mend(map->reserv, map->addr, + map->reserved_length); + if (ret) + return ret; + } else { + ret = unmap(map->addr, map->reserved_length); + if (ret) + return ret; + } Free(map); *map_ptr = NULL; diff --git a/src/libpmem2/map_windows.c b/src/libpmem2/map_windows.c index fe98f05ebe44e067cb842096f1dee076666766c7..315dffbcd1b7e0ef7e7d6add3e858a0bac42f193 100644 --- a/src/libpmem2/map_windows.c +++ b/src/libpmem2/map_windows.c @@ -13,10 +13,12 @@ #include "auto_flush.h" #include "config.h" #include "map.h" +#include "os_thread.h" #include "out.h" #include "persist.h" #include "pmem2_utils.h" #include "source.h" +#include "sys_util.h" #include "util.h" #define HIDWORD(x) ((DWORD)((x) >> 32)) @@ -99,6 +101,110 @@ is_direct_access(HANDLE fh) return 0; } +struct pmem2_map *vm_reservation_map_find_closest_prior( + struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len); +struct pmem2_map *vm_reservation_map_find_closest_later( + struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len); + +/* + * reservation_mend -- unmaps given mapping and mends reservation area + */ +static int +reservation_mend(struct pmem2_vm_reservation *rsv, void *addr, size_t length) +{ + void *rsv_addr = pmem2_vm_reservation_get_address(rsv); + size_t rsv_size = pmem2_vm_reservation_get_size(rsv); + size_t rsv_offset = (size_t)addr - (size_t)rsv->addr; + + if (addr < rsv_addr || + (char *)addr + length > (char *)rsv_addr + rsv_size) + return PMEM2_E_LENGTH_OUT_OF_RANGE; + + int ret = UnmapViewOfFile2(GetCurrentProcess(), + addr, + MEM_PRESERVE_PLACEHOLDER); + if (!ret) { + ERR("!!UnmapViewOfFile2"); + return pmem2_lasterror_to_err(); + } + + /* + * Before mapping to the reservation, it is neccessary to split + * the unoccupied region into separate placeholders, so that + * the mapping and the cut out placeholder will be of the same + * size. + */ + void *mend_addr = addr; + size_t mend_size = length; + struct pmem2_map *map = NULL; + + if (rsv_offset > 0) { + map = vm_reservation_map_find_closest_prior(rsv, rsv_offset, + length); + if (map) { + mend_addr = (char *)map->addr + map->reserved_length; + mend_size += (char *)addr - (char *)mend_addr; + } else { + mend_addr = rsv->addr; + mend_size += rsv_offset; + } + } + + if (rsv_offset + length < rsv_size) { + map = vm_reservation_map_find_closest_later(rsv, rsv_offset, + length); + if (map) + mend_size += (char *)map->addr - (char *)addr - length; + else + mend_size += rsv->size - rsv_offset - length; + } + + if (addr != mend_addr) { + ret = VirtualFree(mend_addr, + mend_size, + MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + if (!ret) { + ERR("!!VirtualFree"); + return pmem2_lasterror_to_err(); + + } + } + + return 0; +} + +/* + * reservation_split - splits the virtual memory reservation into + * separate regions + */ +int +reservation_split(struct pmem2_vm_reservation *rsv, size_t rsv_offset, + size_t length) +{ + void *rsv_addr = pmem2_vm_reservation_get_address(rsv); + size_t rsv_size = pmem2_vm_reservation_get_size(rsv); + + if ((rsv_offset > 0 && !vm_reservation_map_find(rsv, + rsv_offset - 1, 1)) || + (rsv_offset + length < rsv_size && + !vm_reservation_map_find(rsv, + rsv_offset + length, 1))) { + /* split the placeholder */ + int ret = VirtualFree((char *)rsv_addr + rsv_offset, + length, + MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + if (!ret) { + ERR("!!VirtualFree"); + ret = pmem2_lasterror_to_err(); + return ret; + } + } + + return 0; +} + /* * pmem2_map_new -- map memory according to provided config */ @@ -226,31 +332,101 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, ret = pmem2_config_validate_addr_alignment(cfg, src); if (ret) - return ret; + goto err_close_mapping_handle; - /* let's get addr from cfg struct */ - LPVOID addr_hint = cfg->addr; + /* prepare pmem2_map structure */ + struct pmem2_map *map; + map = (struct pmem2_map *)pmem2_malloc(sizeof(*map), &ret); + if (!map) + goto err_close_mapping_handle; - /* obtain a pointer to the mapping view */ - void *base = MapViewOfFileEx(mh, - access, - HIDWORD(effective_offset), - LODWORD(effective_offset), - length, - addr_hint); /* hint address */ + void *base; + if (cfg->reserv) { + void *rsv = cfg->reserv; + void *rsv_addr = pmem2_vm_reservation_get_address(rsv); + size_t rsv_size = pmem2_vm_reservation_get_size(rsv); + size_t rsv_offset = cfg->reserv_offset; + + /* check if reservation has enough space */ + if (rsv_offset + length > rsv_size) { + ret = PMEM2_E_LENGTH_OUT_OF_RANGE; + goto err_free_map_struct; + } - if (base == NULL) { - ERR("!!MapViewOfFileEx"); - if (cfg->addr_request == PMEM2_ADDRESS_FIXED_NOREPLACE) { + if (rsv_offset % Mmap_align) { + ret = PMEM2_E_OFFSET_UNALIGNED; + ERR( + "virtual memory reservation offset %zu is not a multiple of %llu", + rsv_offset, Mmap_align); + goto err_free_map_struct; + } + + map->addr = (char *)rsv_addr + rsv_offset; + map->content_length = length; + + /* register wanted vm reservation region */ + ret = vm_reservation_map_register(cfg->reserv, map); + if (ret) + goto err_free_map_struct; + + /* + * Before mapping to the reservation, it is neccessary to split + * the unoccupied region into separate placeholders, so that + * the mapping and the cut out placeholder will be of the same + * size. + */ + util_rwlock_wrlock(&split_merge_lock); + ret = reservation_split(rsv, rsv_offset, length); + util_rwlock_unlock(&split_merge_lock); + if (ret) + goto err_vm_reserv_unregister; + + /* replace placeholder with a regular mapping */ + base = MapViewOfFile3(mh, + NULL, + (char *)rsv_addr + rsv_offset, /* addr in reservation */ + 0, + length, + MEM_REPLACE_PLACEHOLDER, + proto, + NULL, + 0); + + if (base == NULL) { + ERR("!!MapViewOfFile3"); DWORD ret_windows = GetLastError(); if (ret_windows == ERROR_INVALID_ADDRESS) ret = PMEM2_E_MAPPING_EXISTS; else ret = pmem2_lasterror_to_err(); + goto err_vm_reserv_unregister; + } + } else { + /* let's get addr from cfg struct */ + LPVOID addr_hint = cfg->addr; + + /* obtain a pointer to the mapping view */ + base = MapViewOfFileEx(mh, + access, + HIDWORD(effective_offset), + LODWORD(effective_offset), + length, + addr_hint); /* hint address */ + + if (base == NULL) { + ERR("!!MapViewOfFileEx"); + if (cfg->addr_request == + PMEM2_ADDRESS_FIXED_NOREPLACE) { + DWORD ret_windows = GetLastError(); + if (ret_windows == ERROR_INVALID_ADDRESS) + ret = PMEM2_E_MAPPING_EXISTS; + else + ret = pmem2_lasterror_to_err(); + } + else + ret = pmem2_lasterror_to_err(); + goto err_free_map_struct; } - else - ret = pmem2_lasterror_to_err(); - goto err_close_mapping_handle; } if (!CloseHandle(mh)) { @@ -292,12 +468,6 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, goto err_unmap_base; } - /* prepare pmem2_map structure */ - struct pmem2_map *map; - map = (struct pmem2_map *)pmem2_malloc(sizeof(*map), &ret); - if (!map) - goto err_unmap_base; - map->addr = base; /* * XXX probably in some cases the reserved length > the content length. @@ -306,26 +476,40 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, map->reserved_length = length; map->content_length = length; map->effective_granularity = available_min_granularity; + map->reserv = cfg->reserv; map->source = *src; pmem2_set_flush_fns(map); pmem2_set_mem_fns(map); ret = pmem2_register_mapping(map); if (ret) - goto err_register; + goto err_unmap_base; /* return a pointer to the pmem2_map structure */ *map_ptr = map; return ret; -err_register: +err_unmap_base: + /* + * if the reservation was given by pmem2_config, instead of unmapping, + * we will need to map with MAP_FIXED to mend the reservation + */ + if (cfg->reserv) { + reservation_mend(cfg->reserv, base, length); + vm_reservation_map_unregister(cfg->reserv, map); + } else + UnmapViewOfFile(base); free(map); -err_unmap_base: - UnmapViewOfFile(base); return ret; +err_vm_reserv_unregister: + vm_reservation_map_unregister(cfg->reserv, map); + +err_free_map_struct: + free(map); + err_close_mapping_handle: CloseHandle(mh); return ret; @@ -345,9 +529,22 @@ pmem2_map_delete(struct pmem2_map **map_ptr) if (ret) return ret; - if (!UnmapViewOfFile(map->addr)) { - ERR("!!UnmapViewOfFile"); - return pmem2_lasterror_to_err(); + if (map->reserv) { + util_rwlock_wrlock(&split_merge_lock); + ret = reservation_mend(map->reserv, map->addr, + map->reserved_length); + util_rwlock_unlock(&split_merge_lock); + if (ret) + return ret; + + ret = vm_reservation_map_unregister(map->reserv, map); + if (ret) + return ret; + } else { + if (!UnmapViewOfFile(map->addr)) { + ERR("!!UnmapViewOfFile"); + return pmem2_lasterror_to_err(); + } } Free(map); diff --git a/src/libpmem2/ravl_interval.c b/src/libpmem2/ravl_interval.c index 40419d804e24581b5f86d5837ec7bf764e191d21..fe4debe7c95c794f22719690c1f3a6f7682e1a14 100644 --- a/src/libpmem2/ravl_interval.c +++ b/src/libpmem2/ravl_interval.c @@ -42,11 +42,9 @@ ravl_interval_compare(const void *lhs, const void *rhs) const struct ravl_interval_node *left = lhs; const struct ravl_interval_node *right = rhs; - if (left->get_min(left->addr) < right->get_min(right->addr) && - left->get_max(left->addr) <= right->get_min(right->addr)) + if (left->get_max(left->addr) <= right->get_min(right->addr)) return -1; - if (left->get_min(left->addr) > right->get_min(right->addr) && - left->get_max(left->addr) >= right->get_min(right->addr)) + if (left->get_min(left->addr) >= right->get_max(right->addr)) return 1; return 0; } @@ -213,7 +211,47 @@ ravl_interval_find(struct ravl_interval *ri, void *addr) } /* - * ravl_interval_data -- returns the data contained within interval node + * ravl_interval_find_closest_prior -- find the closest interval + * neighbor prior to the current one + */ +struct ravl_interval_node * +ravl_interval_find_closest_prior(struct ravl_interval *ri, void *addr) +{ + struct ravl_interval_node range; + range.addr = addr; + range.get_min = ri->get_min; + range.get_max = ri->get_max; + + struct ravl_node *node; + node = ravl_find(ri->tree, &range, RAVL_PREDICATE_LESS); + if (!node) + return NULL; + + return ravl_data(node); +} + +/* + * ravl_interval_find_closest_later -- find the closest interval neighbor + * that occurs after the current one + */ +struct ravl_interval_node * +ravl_interval_find_closest_later(struct ravl_interval *ri, void *addr) +{ + struct ravl_interval_node range; + range.addr = addr; + range.get_min = ri->get_min; + range.get_max = ri->get_max; + + struct ravl_node *node; + node = ravl_find(ri->tree, &range, RAVL_PREDICATE_GREATER); + if (!node) + return NULL; + + return ravl_data(node); +} + +/* + * ravl_interval_data -- returns the data contained within an interval node */ void * ravl_interval_data(struct ravl_interval_node *rin) diff --git a/src/libpmem2/ravl_interval.h b/src/libpmem2/ravl_interval.h index 6e15c286146b148a5f4c7e5aa1331f54959c860f..b3f379ab550a266fb67b47ffbd7dfaee797ce781 100644 --- a/src/libpmem2/ravl_interval.h +++ b/src/libpmem2/ravl_interval.h @@ -28,5 +28,9 @@ struct ravl_interval_node *ravl_interval_find_equal(struct ravl_interval *ri, void *addr); struct ravl_interval_node *ravl_interval_find(struct ravl_interval *ri, void *addr); +struct ravl_interval_node *ravl_interval_find_closest_prior( + struct ravl_interval *ri, void *addr); +struct ravl_interval_node *ravl_interval_find_closest_later( + struct ravl_interval *ri, void *addr); void *ravl_interval_data(struct ravl_interval_node *rin); #endif diff --git a/src/libpmem2/vm_reservation.c b/src/libpmem2/vm_reservation.c index faa0b71d533b9f3c4a13c7a48ff46f861fca7d04..851c95feb80d5ea4281aa384abacdf50af054812 100644 --- a/src/libpmem2/vm_reservation.c +++ b/src/libpmem2/vm_reservation.c @@ -5,24 +5,226 @@ * vm_reservation.c -- implementation of virtual memory allocation API */ -#include "libpmem2.h" +#include "alloc.h" +#include "map.h" +#include "pmem2_utils.h" +#include "os_thread.h" +#include "ravl_interval.h" +#include "sys_util.h" +#include "vm_reservation.h" + +#ifdef _WIN32 +#include <Windows.h> +#endif + +int vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, + size_t *rsize); +int vm_reservation_release_memory(void *addr, size_t size); + +/* + * pmem2_vm_reservation_get_address -- get reservation address + */ +void * +pmem2_vm_reservation_get_address(struct pmem2_vm_reservation *rsv) +{ + LOG(3, "reservation %p", rsv); + + return rsv->addr; +} + +/* + * pmem2_vm_reservation_get_size -- get reservation size + */ +size_t +pmem2_vm_reservation_get_size(struct pmem2_vm_reservation *rsv) +{ + LOG(3, "reservation %p", rsv); + + return rsv->size; +} + +/* + * mapping_min - return min boundary for mapping + */ +static size_t +mapping_min(void *map) +{ + return (size_t)pmem2_map_get_address(map); +} + +/* + * mapping_max - return max boundary for mapping + */ +static size_t +mapping_max(void *map) +{ + return (size_t)pmem2_map_get_address(map) + + pmem2_map_get_size(map); +} + +/* + * pmem2_vm_reservation_init - initialize the reservation structure + */ +static int +vm_reservation_init(struct pmem2_vm_reservation *rsv) +{ + os_rwlock_init(&rsv->lock); + + rsv->itree = ravl_interval_new(mapping_min, mapping_max); + + if (!rsv->itree) + return -1; + + return 0; +} + +/* + * pmem2_vm_reservation_fini - finalize the reservation structure + */ +static void +vm_reservation_fini(struct pmem2_vm_reservation *rsv) +{ + ravl_interval_delete(rsv->itree); +} /* * pmem2_vm_reservation_new -- creates new virtual memory reservation */ int -pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv, - size_t size, void *address) +pmem2_vm_reservation_new(struct pmem2_vm_reservation **rsv_ptr, + void *addr, size_t size) { - return PMEM2_E_NOSUPP; + *rsv_ptr = NULL; + + unsigned long long gran = Mmap_align; + + if (addr && (unsigned long long)addr % gran) { + ERR("address %p is not a multiple of 0x%llx", addr, + gran); + return PMEM2_E_ADDRESS_UNALIGNED; + } + + if (size % gran) { + ERR("reservation size %zu is not a multiple of %llu", + size, gran); + return PMEM2_E_LENGTH_UNALIGNED; + } + + int ret; + struct pmem2_vm_reservation *rsv = pmem2_malloc( + sizeof(struct pmem2_vm_reservation), &ret); + + if (ret) + return ret; + + /* initialize the ravl interval tree */ + ret = vm_reservation_init(rsv); + if (ret) + goto err_rsv_init; + + void *raddr = NULL; + size_t rsize = 0; + ret = vm_reservation_reserve_memory(addr, size, &raddr, &rsize); + if (ret) + goto err_reserve; + + rsv->addr = raddr; + rsv->size = rsize; + + *rsv_ptr = rsv; + + return 0; + +err_reserve: + vm_reservation_fini(rsv); +err_rsv_init: + Free(rsv); + return ret; } /* * pmem2_vm_reservation_delete -- deletes reservation bound to - * structure pmem2_vm_reservation + * the pmem2_vm_reservation structure + */ +int +pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv_ptr) +{ + struct pmem2_vm_reservation *rsv = *rsv_ptr; + + /* check if reservation contains any mapping */ + if (vm_reservation_map_find(rsv, 0, rsv->size)) + return PMEM2_E_VM_RESERVATION_NOT_EMPTY; + + int ret = vm_reservation_release_memory(rsv->addr, rsv->size); + if (ret) + return ret; + + vm_reservation_fini(rsv); + Free(rsv); + + return 0; +} + +/* + * vm_reservation_map_register -- register mapping in the mappings tree + * of reservation structure */ int -pmem2_vm_reservation_delete(struct pmem2_vm_reservation **rsv) +vm_reservation_map_register(struct pmem2_vm_reservation *rsv, + struct pmem2_map *map) { - return PMEM2_E_NOSUPP; + util_rwlock_wrlock(&rsv->lock); + int ret = ravl_interval_insert(rsv->itree, map); + util_rwlock_unlock(&rsv->lock); + + if (ret == -EEXIST) + return PMEM2_E_MAPPING_EXISTS; + + return ret; +} + +/* + * vm_reservation_map_unregister -- unregister mapping from the mapping tree + * of reservation structure + */ +int +vm_reservation_map_unregister(struct pmem2_vm_reservation *rsv, + struct pmem2_map *map) +{ + int ret = 0; + struct ravl_interval_node *node; + + util_rwlock_wrlock(&rsv->lock); + node = ravl_interval_find_equal(rsv->itree, map); + if (node) + ret = ravl_interval_remove(rsv->itree, node); + else + ret = PMEM2_E_MAPPING_NOT_FOUND; + util_rwlock_unlock(&rsv->lock); + + return ret; +} + +/* + * vm_reservation_map_find -- find the earliest mapping overlapping with + * (addr, addr+size) range + */ +struct pmem2_map * +vm_reservation_map_find(struct pmem2_vm_reservation *rsv, size_t reserv_offset, + size_t len) +{ + struct pmem2_map map; + map.addr = (char *)rsv->addr + reserv_offset; + map.content_length = len; + + struct ravl_interval_node *node; + + util_rwlock_rdlock(&rsv->lock); + node = ravl_interval_find(rsv->itree, &map); + util_rwlock_unlock(&rsv->lock); + + if (!node) + return NULL; + + return (struct pmem2_map *)ravl_interval_data(node); } diff --git a/src/libpmem2/vm_reservation.h b/src/libpmem2/vm_reservation.h new file mode 100644 index 0000000000000000000000000000000000000000..6fd3cef560a903115900c16c074cb5e2ad84c4f8 --- /dev/null +++ b/src/libpmem2/vm_reservation.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * vm_reservation.h -- internal definitions for virtual memory reservation + */ +#ifndef PMEM2_VM_RESERVATION_H +#define PMEM2_VM_RESERVATION_H + +#include "ravl_interval.h" + +struct pmem2_vm_reservation { + struct ravl_interval *itree; + void *addr; + size_t size; + os_rwlock_t lock; +}; + +int vm_reservation_map_register(struct pmem2_vm_reservation *rsv, + struct pmem2_map *map); +int vm_reservation_map_unregister(struct pmem2_vm_reservation *rsv, + struct pmem2_map *map); +struct pmem2_map *vm_reservation_map_find(struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len); + +#endif /* vm_reservation.h */ diff --git a/src/libpmem2/vm_reservation_posix.c b/src/libpmem2/vm_reservation_posix.c new file mode 100644 index 0000000000000000000000000000000000000000..612f822d9b21f636ce9b34a60e4e5a3aa0cc5d02 --- /dev/null +++ b/src/libpmem2/vm_reservation_posix.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * vm_reservation_posix.c -- implementation of virtual memory + * reservation API (POSIX) + */ + +#include <sys/mman.h> + +#include "alloc.h" +#include "map.h" +#include "out.h" +#include "pmem2_utils.h" + +int vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, + size_t *rsize); +int vm_reservation_release_memory(void *addr, size_t size); + +/* + * vm_reservation_reserve_memory -- create a blank virual memory mapping + */ +int +vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, + size_t *rsize) +{ + int map_flag = 0; + if (addr) { +/* + * glibc started exposing MAP_FIXED_NOREPLACE flag in version 4.17, + * but even if the flag is not supported, we can imitate its behavior + */ +#ifdef MAP_FIXED_NOREPLACE + map_flag = MAP_FIXED_NOREPLACE; +#else + map_flag = 0; +#endif + } + + /* + * Create a dummy mapping to find an unused region of given size. + * If the flag is supported and requested region is occupied, + * mmap will fail with EEXIST. + */ + char *daddr = mmap(addr, size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | map_flag, -1, 0); + if (daddr == MAP_FAILED) { + if (errno == EEXIST) { + ERR("!mmap MAP_FIXED_NOREPLACE"); + return PMEM2_E_MAPPING_EXISTS; + } + ERR("!mmap MAP_ANONYMOUS"); + return PMEM2_E_ERRNO; + } + + /* + * When requested address is not specified, any returned address + * is acceptable. If kernel does not support flag and given addr + * is occupied, kernel chooses new addr randomly and returns it. + * We do not want that behavior, so we validate it and fail when + * addresses do not match. + */ + if (addr && daddr != addr) { + munmap(daddr, size); + ERR("mapping exists in the given address"); + return PMEM2_E_MAPPING_EXISTS; + } + + *raddr = daddr; + *rsize = roundup(size, Pagesize); + + return 0; +} + +/* + * vm_reservation_release_memory -- releases blank virtual memory mapping + */ +int +vm_reservation_release_memory(void *addr, size_t size) +{ + if (munmap(addr, size)) { + ERR("!munmap"); + return PMEM2_E_ERRNO; + } + + return 0; +} diff --git a/src/libpmem2/vm_reservation_windows.c b/src/libpmem2/vm_reservation_windows.c new file mode 100644 index 0000000000000000000000000000000000000000..ab63a0d433c70de1771e30e740709ba350766826 --- /dev/null +++ b/src/libpmem2/vm_reservation_windows.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * vm_reservation_windows.c -- implementation of virtual memory + * reservation API (Windows) + */ + +#include "alloc.h" +#include "map.h" +#include "os_thread.h" +#include "out.h" +#include "pmem2_utils.h" +#include "sys_util.h" + +int vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, + size_t *rsize); +int vm_reservation_release_memory(void *addr, size_t size); +struct pmem2_map *vm_reservation_map_find_closest_prior( + struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len); +struct pmem2_map *vm_reservation_map_find_closest_later( + struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len); + +/* + * vm_reservation_reserve_memory -- create a blank virual memory mapping + */ +int +vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, + size_t *rsize) +{ + void *daddr = VirtualAlloc2(GetCurrentProcess(), + addr, + size, + MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, + PAGE_NOACCESS, + NULL, + 0); + + if (daddr == NULL) { + ERR("!!VirtualAlloc2"); + DWORD ret_windows = GetLastError(); + if (ret_windows == ERROR_INVALID_ADDRESS) + return PMEM2_E_MAPPING_EXISTS; + else + return pmem2_lasterror_to_err(); + } + + *raddr = daddr; + *rsize = size; + + return 0; +} + +/* + * vm_reservation_release_memory -- releases blank virtual memory mapping + */ +int +vm_reservation_release_memory(void *addr, size_t size) +{ + int ret = VirtualFree(addr, + 0, + MEM_RELEASE); + if (!ret) { + ERR("!!VirtualFree"); + return pmem2_lasterror_to_err(); + } + + return 0; +} + +/* + * vm_reservation_map_find_closest_prior -- find closest mapping neighbor + * prior to the provided mapping + */ +struct pmem2_map * +vm_reservation_map_find_closest_prior(struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len) +{ + struct pmem2_map map; + map.addr = (char *)rsv->addr + reserv_offset; + map.content_length = len; + + struct ravl_interval_node *node; + + util_rwlock_rdlock(&rsv->lock); + node = ravl_interval_find_closest_prior(rsv->itree, &map); + util_rwlock_unlock(&rsv->lock); + + if (!node) + return NULL; + + return (struct pmem2_map *)ravl_interval_data(node); +} + +/* + * vm_reservation_map_find_closest_later -- find closest mapping neighbor later + * than the mapping provided + */ +struct pmem2_map * +vm_reservation_map_find_closest_later(struct pmem2_vm_reservation *rsv, + size_t reserv_offset, size_t len) +{ + struct pmem2_map map; + map.addr = (char *)rsv->addr + reserv_offset; + map.content_length = len; + + struct ravl_interval_node *node; + + util_rwlock_rdlock(&rsv->lock); + node = ravl_interval_find_closest_later(rsv->itree, &map); + util_rwlock_unlock(&rsv->lock); + + if (!node) + return NULL; + + return (struct pmem2_map *)ravl_interval_data(node); +} diff --git a/src/test/Makefile b/src/test/Makefile index fb7d6770142127157874f5de7e9811fcf3c31bca..0568d5ff13c24f120a6716c4ece5a11ce04f72ba 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -217,7 +217,8 @@ PMEM2_TESTS = \ pmem2_movnt\ pmem2_movnt_align\ pmem2_mem_ext\ - pmem2_deep_flush + pmem2_deep_flush\ + pmem2_vm_reservation ifeq ($(OS_DIMM),ndctl) PMEM2_TESTS += \ diff --git a/src/test/Makefile.inc b/src/test/Makefile.inc index 959437a9d0cda043fa17e512f0caf7e14824c9f8..db5ab5d7992098fdd46afd64b4fadceff6de54a4 100644 --- a/src/test/Makefile.inc +++ b/src/test/Makefile.inc @@ -176,6 +176,7 @@ OBJS +=\ $(TOP)/src/debug/libpmem2/source_posix.o\ $(TOP)/src/debug/libpmem2/usc_$(OS_DIMM).o\ $(TOP)/src/debug/libpmem2/vm_reservation.o\ + $(TOP)/src/debug/libpmem2/vm_reservation_posix.o\ $(TOP)/src/debug/libpmem2/ravl_interval.o ifeq ($(OS_KERNEL_NAME),Linux) @@ -226,7 +227,8 @@ OBJS +=\ $(TOP)/src/nondebug/libpmem2/pmem2_utils_$(OS_DIMM).o\ $(TOP)/src/nondebug/libpmem2/ravl.o\ $(TOP)/src/nondebug/libpmem2/usc_$(OS_DIMM).o\ - $(TOP)/src/nondebug/libpmem2/vm_reservation.o + $(TOP)/src/nondebug/libpmem2/vm_reservation.o\ + $(TOP)/src/nondebug/libpmem2/vm_reservation_posix.o\ $(TOP)/src/nondebug/libpmem2/ravl_interval.o ifeq ($(OS_KERNEL_NAME),Linux) diff --git a/src/test/ex_libpmem2/TESTS.py b/src/test/ex_libpmem2/TESTS.py index 4eb44ab910f46eddf3bf616f21026176769eef57..2f2473b55126f24ea79d9fe26ee6faea45f76978 100755 --- a/src/test/ex_libpmem2/TESTS.py +++ b/src/test/ex_libpmem2/TESTS.py @@ -56,3 +56,18 @@ class TEST3(EX_LIBPMEM2): ctx.exec(example_path, "add", file_path, x, x) ctx.exec(example_path, "check", file_path) ctx.exec(example_path, "print", file_path, stdout_file='out3.log') + + +class TEST4(EX_LIBPMEM2): + + def run(self, ctx): + example_path = futils.get_example_path(ctx, 'pmem2', + 'map_multiple_files') + + args = [] + for x in range(1, 10): + file_path = ctx.create_holey_file(self.file_size, + 'testfile{}'.format(x)) + args.append(file_path) + + ctx.exec(example_path, *args, stdout_file='out4.log') diff --git a/src/test/ex_libpmem2/out4.log.match b/src/test/ex_libpmem2/out2.log.match similarity index 100% rename from src/test/ex_libpmem2/out4.log.match rename to src/test/ex_libpmem2/out2.log.match diff --git a/src/test/pmem2_granularity/pmem2_granularity.vcxproj b/src/test/pmem2_granularity/pmem2_granularity.vcxproj index 2ca0853ae75656a0557cd6e1da0ec60dd65c9705..aecb32e78d4dd44fb846cb0f8d19a8c21a114d28 100644 --- a/src/test/pmem2_granularity/pmem2_granularity.vcxproj +++ b/src/test/pmem2_granularity/pmem2_granularity.vcxproj @@ -87,6 +87,8 @@ <ClCompile Include="..\..\libpmem2\persist.c" /> <ClCompile Include="..\..\libpmem2\persist_windows.c" /> <ClCompile Include="..\..\libpmem2\ravl_interval.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> <ClCompile Include="..\pmem_has_auto_flush_win\mocks_windows.c"> diff --git a/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters b/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters index bd33ff66a3cf43dde9356b76f8c797fcc114b3f6..c660d254ab898f5dc37a21f02711cf41d402f587 100644 --- a/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters +++ b/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters @@ -68,6 +68,12 @@ <ClCompile Include="..\..\libpmem2\ravl_interval.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\unittest\ut_pmem2_utils.h"> diff --git a/src/test/pmem2_map/TESTS.py b/src/test/pmem2_map/TESTS.py index d41b37166b09accf242d504d49957da5ccc059fe..78643f4b45775ac919700eee419d3f9227f8098e 100755 --- a/src/test/pmem2_map/TESTS.py +++ b/src/test/pmem2_map/TESTS.py @@ -112,8 +112,6 @@ class TEST12(PMEM2_MAP_DEVDAX): test_case = "test_unmap_valid" -# UnmapViewOfFile does not use length -@t.windows_exclude class TEST13(PMEM2_MAP): """unmap a pmem2 mapping with an invalid length""" test_case = "test_unmap_zero_length" diff --git a/src/test/pmem2_map/pmem2_map.c b/src/test/pmem2_map/pmem2_map.c index c3aaad02d0765047df14f376c2dc9be973def109..71b1f4a92ab2dfd5c911bff16118b0d7e0ee068e 100644 --- a/src/test/pmem2_map/pmem2_map.c +++ b/src/test/pmem2_map/pmem2_map.c @@ -77,6 +77,7 @@ prepare_map(struct pmem2_map **map_ptr, map->reserved_length = map->content_length = cfg->length; map->effective_granularity = PMEM2_GRANULARITY_PAGE; + map->reserv = NULL; *map_ptr = map; @@ -113,6 +114,7 @@ prepare_map(struct pmem2_map **map_ptr, map->source.value.ftype = PMEM2_FTYPE_REG; map->reserved_length = map->content_length = cfg->length; map->effective_granularity = PMEM2_GRANULARITY_PAGE; + map->reserv = NULL; *map_ptr = map; @@ -475,7 +477,8 @@ test_unmap_zero_length(const struct test_case *tc, int argc, char *argv[]) char *file = argv[0]; size_t size = ATOUL(argv[1]); - unmap_invalid_common(file, size, map_spoil_set_zero_length, -EINVAL); + unmap_invalid_common(file, size, map_spoil_set_zero_length, + PMEM2_E_MAPPING_NOT_FOUND); return 2; } diff --git a/src/test/pmem2_map/pmem2_map.vcxproj b/src/test/pmem2_map/pmem2_map.vcxproj index 2d2b0b31190e627105db29b310cdf9ad55631cb3..48a2f5284f6ef057efefaa23cd87cebb9023c65b 100644 --- a/src/test/pmem2_map/pmem2_map.vcxproj +++ b/src/test/pmem2_map/pmem2_map.vcxproj @@ -89,6 +89,8 @@ <ClCompile Include="..\..\libpmem2\persist_windows.c" /> <ClCompile Include="..\..\libpmem2\pmem2_utils.c" /> <ClCompile Include="..\..\libpmem2\ravl_interval.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> <ClCompile Include="..\unittest\ut_pmem2_setup.c" /> @@ -102,6 +104,7 @@ <ClInclude Include="..\..\libpmem2\pmem2.h" /> <ClInclude Include="..\..\libpmem2\pmem2_utils.h" /> <ClInclude Include="..\..\libpmem2\ravl_interval.h" /> + <ClInclude Include="..\..\libpmem2\vm_reservation.h" /> <ClInclude Include="..\unittest\ut_pmem2.h" /> </ItemGroup> <ItemGroup> diff --git a/src/test/pmem2_map/pmem2_map.vcxproj.filters b/src/test/pmem2_map/pmem2_map.vcxproj.filters index 1ee5eda891a7e2b8f0f52da0e7e8c3d3dd20f8cd..5f6bc4e098a0a2b510453bb71ef8240f98f9c799 100644 --- a/src/test/pmem2_map/pmem2_map.vcxproj.filters +++ b/src/test/pmem2_map/pmem2_map.vcxproj.filters @@ -68,6 +68,12 @@ <ClCompile Include="..\..\libpmem2\ravl_interval.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\libpmem2\config.h"> @@ -88,6 +94,9 @@ <ClInclude Include="..\..\libpmem2\ravl_interval.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\libpmem2\vm_reservation.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="TESTS.py"> diff --git a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj index 77002b0961d2f3e0a738b11d65d3f2680b6b84b0..14977b550f5361ebd21abdee099e8ac61cb86fd7 100644 --- a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj +++ b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj @@ -89,6 +89,8 @@ <ClCompile Include="..\..\libpmem2\persist_windows.c" /> <ClCompile Include="..\..\libpmem2\pmem2_utils.c" /> <ClCompile Include="..\..\libpmem2\ravl_interval.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> <ClCompile Include="..\unittest\ut_pmem2_config.c" /> diff --git a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters index 7f2b984f4ce14b3352cbc93af91a0858c4b013fc..b742780aead3309a274857a29c9669d7035e6b79 100644 --- a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters +++ b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters @@ -71,6 +71,12 @@ <ClCompile Include="..\..\libpmem2\ravl_interval.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\libpmem2\config.h"> @@ -97,4 +103,4 @@ <Filter>Test Scripts</Filter> </None> </ItemGroup> -</Project> +</Project> \ No newline at end of file diff --git a/src/test/pmem2_vm_reservation/.gitignore b/src/test/pmem2_vm_reservation/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..49024628859e1135d1044cc856285ec1c9d542c3 --- /dev/null +++ b/src/test/pmem2_vm_reservation/.gitignore @@ -0,0 +1 @@ +pmem2_vm_reservation diff --git a/src/test/pmem2_vm_reservation/Makefile b/src/test/pmem2_vm_reservation/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..62f703dede77046261c8d6f91cf38fd8bccbe85a --- /dev/null +++ b/src/test/pmem2_vm_reservation/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation +# + +# +# src/test/pmem2_vm_reservation/Makefile -- build pmem2_vm_reservation +# unit tests +# +TOP = ../../.. + +vpath %.c $(TOP)/src/test/unittest + +INCS += -I$(TOP)/src/libpmem2 +TARGET = pmem2_vm_reservation +OBJS += pmem2_vm_reservation.o\ + ut_pmem2_utils.o\ + ut_pmem2_source.o\ + ut_pmem2_setup.o + +LIBPMEM2=internal-debug + +include ../Makefile.inc diff --git a/src/test/pmem2_vm_reservation/TESTS.py b/src/test/pmem2_vm_reservation/TESTS.py new file mode 100755 index 0000000000000000000000000000000000000000..d3d23bae3f503b862afdf79f6ea6dce95baa52f8 --- /dev/null +++ b/src/test/pmem2_vm_reservation/TESTS.py @@ -0,0 +1,273 @@ +#!../env.py +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation +# + +import os + +import testframework as t +from testframework import granularity as g + + +class PMEM2_VM_RESERVATION(t.Test): + test_type = t.Short + filesize = 16 * t.MiB + with_size = True + + def run(self, ctx): + filepath = ctx.create_holey_file(self.filesize, 'testfile',) + if self.with_size: + filesize = os.stat(filepath).st_size + ctx.exec('pmem2_vm_reservation', self.test_case, filepath, + filesize) + else: + ctx.exec('pmem2_vm_reservation', self.test_case, filepath) + + +class PMEM2_VM_RESERVATION_ASYNC(t.Test): + test_type = t.Short + filesize = 16 * t.MiB + + def run(self, ctx): + filepath = ctx.create_holey_file(self.filesize, 'testfile',) + filesize = os.stat(filepath).st_size + ctx.exec('pmem2_vm_reservation', self.test_case, filepath, + filesize, self.threads, self.ops_per_thread) + + +@t.windows_exclude +@t.require_devdax(t.DevDax('devdax1')) +class PMEM2_VM_RESERVATION_DEVDAX(t.Test): + test_type = t.Short + with_size = True + + def run(self, ctx): + dd = ctx.devdaxes.devdax1 + if self.with_size: + ctx.exec('pmem2_vm_reservation', self.test_case, dd.path, dd.size) + else: + ctx.exec('pmem2_vm_reservation', self.test_case, dd.path) + + +@t.windows_exclude +@t.require_devdax(t.DevDax('devdax1')) +class PMEM2_VM_RESERVATION_ASYNC_DEVDAX(t.Test): + test_type = t.Short + with_size = True + + def run(self, ctx): + dd = ctx.devdaxes.devdax1 + if self.with_size: + ctx.exec('pmem2_vm_reservation', self.test_case, dd.path, dd.size, + self.threads, self.ops_per_thread) + else: + ctx.exec('pmem2_vm_reservation', self.test_case, dd.path, + self.threads, self.ops_per_thread) + + +class TEST0(PMEM2_VM_RESERVATION): + """create a vm reservation in the region belonging to existing mapping""" + test_case = "test_vm_reserv_new_region_occupied_map" + + +class TEST1(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax create a vm reservation in the region belonging to existing mapping + """ + test_case = "test_vm_reserv_new_region_occupied_map" + + +class TEST2(PMEM2_VM_RESERVATION): + """ + create a vm reservation in the region belonging to other + existing vm reservation + """ + test_case = "test_vm_reserv_new_region_occupied_reserv" + + +class TEST3(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax create a vm reservation in the region belonging to other + existing vm reservation + """ + test_case = "test_vm_reserv_new_region_occupied_reserv" + + +class TEST4(PMEM2_VM_RESERVATION): + """create a vm reservation with unaligned address provided""" + test_case = "test_vm_reserv_new_unaligned_addr" + + +class TEST5(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax create a vm reservation with unaligned address provided""" + test_case = "test_vm_reserv_new_unaligned_addr" + + +class TEST6(PMEM2_VM_RESERVATION): + """create a vm reservation with unaligned size provided""" + test_case = "test_vm_reserv_new_unaligned_size" + + +class TEST7(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax create a vm reservation with unaligned size provided""" + test_case = "test_vm_reserv_new_unaligned_size" + + +class TEST8(PMEM2_VM_RESERVATION): + """create a vm reservation with with error injection""" + test_case = "test_vm_reserv_new_alloc_enomem" + + +class TEST9(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax create a vm reservation with with error injection""" + test_case = "test_vm_reserv_new_alloc_enomem" + + +class TEST10(PMEM2_VM_RESERVATION): + """map a file to a vm reservation""" + test_case = "test_vm_reserv_map_file" + + +class TEST11(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax map a file to a vm reservation""" + test_case = "test_vm_reserv_map_file" + + +class TEST12(PMEM2_VM_RESERVATION): + """ + map a part of the file to a vm reservation smaller than the whole file + """ + test_case = "test_vm_reserv_map_part_file" + + +class TEST13(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax map a part of the file to a vm reservation + smaller than the whole file + """ + test_case = "test_vm_reserv_map_part_file" + + +class TEST14(PMEM2_VM_RESERVATION): + """delete a vm reservation that contains a mapping""" + test_case = "test_vm_reserv_delete_contains_mapping" + + +class TEST15(PMEM2_VM_RESERVATION): + """delete a vm reservation with spoiled address""" + test_case = "test_vm_reserv_delete_spoil_addr" + + +class TEST16(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax delete a vm reservation with spoiled address""" + test_case = "test_vm_reserv_delete_spoil_addr" + + +@t.windows_exclude +class TEST17(PMEM2_VM_RESERVATION): + """delete a vm reservation with spoiled size""" + test_case = "test_vm_reserv_delete_spoil_size" + + +class TEST18(PMEM2_VM_RESERVATION_DEVDAX): + """DevDax delete a vm reservation with spoiled size""" + test_case = "test_vm_reserv_delete_spoil_size" + + +class TEST19(PMEM2_VM_RESERVATION): + """ + map multiple files to a vm reservation, then + unmap every 2nd mapping and map the mappings again + """ + test_case = "test_vm_reserv_map_unmap_multiple_files" + + +class TEST20(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax map multiple files to a vm reservation, then + unmap every 2nd mapping and map the mappings again + """ + test_case = "test_vm_reserv_map_unmap_multiple_files" + + +class TEST21(PMEM2_VM_RESERVATION): + """map a file to a vm reservation with insufficient space""" + test_case = "test_vm_reserv_map_insufficient_space" + + +class TEST22(PMEM2_VM_RESERVATION): + """ + map a file to a vm reservation and overlap whole other existing mapping + belonging to the same reservation + """ + test_case = "test_vm_reserv_map_full_overlap" + + +class TEST23(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax map a file to a vm reservation and overlap whole other + existing mapping belonging to the same reservation + """ + test_case = "test_vm_reserv_map_full_overlap" + + +class TEST24(PMEM2_VM_RESERVATION): + """ + map a file to a vm reservation overlapping with the ealier half + of the other existing mapping + """ + test_case = "test_vm_reserv_map_partial_overlap_below" + + +class TEST25(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax map a file to a vm reservation overlapping with the ealier half + of the other existing mapping + """ + test_case = "test_vm_reserv_map_partial_overlap_below" + + +class TEST26(PMEM2_VM_RESERVATION): + """ + map a file to a vm reservation overlapping with the latter half + of the other existing mapping + """ + test_case = "test_vm_reserv_map_partial_overlap_above" + + +class TEST27(PMEM2_VM_RESERVATION_DEVDAX): + """ + DevDax map a file to a vm reservation overlapping with the latter half + of the other existing mapping + """ + test_case = "test_vm_reserv_map_partial_overlap_above" + + +@g.require_granularity(g.PAGE, g.CACHELINE) +class TEST28(PMEM2_VM_RESERVATION): + """ + map a file with invalid granularity to a vm reservation in the middle of + the vm reservation bigger than the file, then map a file that covers whole + vm reservation + """ + test_case = "test_vm_reserv_map_invalid_granularity" + + +class TEST29(PMEM2_VM_RESERVATION_ASYNC): + """ + map and unmap asynchronously multiple times to the whole vm reservation + region + """ + test_case = "test_vm_reserv_async_map_unmap_multiple_files" + threads = 32 + ops_per_thread = 10000 + + +class TEST30(PMEM2_VM_RESERVATION_ASYNC_DEVDAX): + """ + DevDax map and unmap asynchronously multiple times to the whole + whole vm reservation region + """ + test_case = "test_vm_reserv_async_map_unmap_multiple_files" + threads = 32 + ops_per_thread = 1000 diff --git a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.c b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.c new file mode 100644 index 0000000000000000000000000000000000000000..09d6eab61ee08efb0b50c386d8246ee451973537 --- /dev/null +++ b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.c @@ -0,0 +1,1003 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * pmem2_vm_reservation.c -- pmem2_vm_reservation unittests + */ + +#include <stdbool.h> + +#include "config.h" +#include "fault_injection.h" +#include "pmem2_utils.h" +#include "source.h" +#include "map.h" +#include "out.h" +#include "pmem2.h" +#include "unittest.h" +#include "ut_pmem2.h" +#include "ut_pmem2_setup.h" + +/* + * get_align_by_filename -- fetch map alignment for an unopened file + */ +static size_t +get_align_by_filename(const char *filename) +{ + struct pmem2_source *src; + size_t align; + int fd = OPEN(filename, O_RDONLY); + PMEM2_SOURCE_FROM_FD(&src, fd); + PMEM2_SOURCE_ALIGNMENT(src, &align); + PMEM2_SOURCE_DELETE(&src); + CLOSE(fd); + + return align; +} + +/* + * offset_align_to_devdax - align offset of the virtual memory reservation + * to device DAX granularity + */ +static size_t +offset_align_to_devdax(void *rsv_addr, size_t alignment) +{ + /* + * Address of the vm_reservation, is always aligned to the OS allocation + * granularity. DevDax demands its own granularity, we need to calculate + * the offset, so that (reservation address + offset) is aligned to the + * closest address, contained in the vm reservation, compatible with + * DevDax granularity. + */ + size_t mod_align = (size_t)rsv_addr % alignment; + if (mod_align) + return (alignment - mod_align); + + return 0; +} + +/* + * test_vm_reserv_new_region_occupied_map - create a reservation + * in the region belonging to existing mapping + */ +static int +test_vm_reserv_new_region_occupied_map(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_new_region_occupied_map " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + void *addr; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_source *src; + struct pmem2_vm_reservation *rsv; + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + + /* map a region of virtual address space */ + int ret = pmem2_map_new(&map, &cfg, src); + UT_ASSERTeq(ret, 0); + + addr = pmem2_map_get_address(map); + UT_ASSERTne(addr, NULL); + + /* create a reservation in the region occupied by existing mapping */ + ret = pmem2_vm_reservation_new(&rsv, addr, size); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAPPING_EXISTS); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_new_region_occupied_reserv - create a vm reservation + * in the region belonging to other existing vm reservation + */ +static int +test_vm_reserv_new_region_occupied_reserv(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_new_region_occupied_reserv " + "<file> <size>"); + + size_t size = ATOUL(argv[1]); + void *rsv_addr; + struct pmem2_vm_reservation *rsv1; + struct pmem2_vm_reservation *rsv2; + + /* reserve a region in the virtual address space */ + int ret = pmem2_vm_reservation_new(&rsv1, NULL, size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv1); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv1), size); + + /* + * Make a vm reservation of the region occupied by other + * existing reservation. + */ + ret = pmem2_vm_reservation_new(&rsv2, rsv_addr, size); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAPPING_EXISTS); + + ret = pmem2_vm_reservation_delete(&rsv1); + UT_ASSERTeq(ret, 0); + + return 2; +} + +/* + * test_vm_reserv_new_unaligned_addr - create a vm reservation with + * unaligned address provided + */ +static int +test_vm_reserv_new_unaligned_addr(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_new_unaligned_addr " + "<file> <size>"); + + size_t size = ATOUL(argv[1]); + void *rsv_addr = (char *)Mmap_align - 1; /* unaligned address */ + struct pmem2_vm_reservation *rsv; + + /* reserve a region in the virtual address space */ + int ret = pmem2_vm_reservation_new(&rsv, rsv_addr, size); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_ADDRESS_UNALIGNED); + + return 2; +} + +/* + * test_vm_reserv_new_unaligned_size - create a vm reservation with + * unaligned size provided + */ +static int +test_vm_reserv_new_unaligned_size(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_new_unaligned_size " + "<file> <size>"); + + size_t size = ATOUL(argv[1]) - 1; /* unaligned size */ + struct pmem2_vm_reservation *rsv; + + /* reserve a region in the virtual address space */ + int ret = pmem2_vm_reservation_new(&rsv, NULL, size); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_LENGTH_UNALIGNED); + + return 2; +} + +/* + * test_vm_reserv_new_alloc_enomem - create a vm reservation + * with error injection + */ +static int +test_vm_reserv_new_alloc_enomem(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_new_alloc_enomem " + "<file> <size>"); + + size_t size = ATOUL(argv[1]); + struct pmem2_vm_reservation *rsv; + + if (!core_fault_injection_enabled()) { + return 2; + } + core_inject_fault_at(PMEM_MALLOC, 1, "pmem2_malloc"); + + /* reserve a region in the virtual address space */ + int ret = pmem2_vm_reservation_new(&rsv, NULL, size); + UT_PMEM2_EXPECT_RETURN(ret, -ENOMEM); + + return 2; +} + +/* + * test_vm_reserv_map_file - map a file to a vm reservation + */ +static int +test_vm_reserv_map_file(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_file <file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_offset; + size_t rsv_size; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + rsv_size = size + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, 0); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + rsv_offset = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, 0); + + UT_ASSERTeq(pmem2_map_get_address(map), (char *)rsv_addr + rsv_offset); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_map_part_file - map a part of the file to a vm reservation + */ +static int +test_vm_reserv_map_part_file(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_part_file <file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + size_t offset = 0; + void *rsv_addr; + size_t rsv_offset; + size_t rsv_size; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + /* map only part of the file */ + offset = ALIGN_DOWN(size / 2, alignment); + + /* reservation size is not big enough for the whole file */ + rsv_size = size - offset + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, 0); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + rsv_offset = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, offset, + FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, 0); + + UT_ASSERTeq(pmem2_map_get_address(map), (char *)rsv_addr + rsv_offset); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_delete_contains_mapping - delete a vm reservation that + * contains mapping + */ +static int +test_vm_reserv_delete_contains_mapping(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_delete_contains_mapping " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_size; + size_t rsv_offset; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_source *src; + struct pmem2_vm_reservation *rsv; + + rsv_size = size + alignment; + + /* create a reservation in the virtual memory */ + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, 0); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + rsv_offset = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + /* create a mapping in the reserved region */ + ret = pmem2_map_new(&map, &cfg, src); + UT_ASSERTeq(ret, 0); + + /* delete the reservation while it contains a mapping */ + ret = pmem2_vm_reservation_delete(&rsv); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_VM_RESERVATION_NOT_EMPTY); + + ret = pmem2_map_delete(&map); + UT_PMEM2_EXPECT_RETURN(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_delete_spoil_addr - delete a vm reservation with + * spoiled address + */ +static int +test_vm_reserv_delete_spoil_addr(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_delete_spoil_addr " + "<file> <size>"); + size_t size = ATOUL(argv[1]); + void *rsv_addr; + struct pmem2_vm_reservation *rsv; + + /* create a reservation in the virtual memory */ + int ret = pmem2_vm_reservation_new(&rsv, NULL, size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + /* spoil vm_reservation struct address */ + rsv->addr = (void *) - 1; + + ret = pmem2_vm_reservation_delete(&rsv); + UT_PMEM2_EXPECT_RETURN(ret, -EINVAL); + + /* restore the appropriate address */ + rsv->addr = rsv_addr; + + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + + return 2; +} + +/* + * test_vm_reserv_delete_spoil_size - delete a vm reservation with + * spoiled size + */ +static int +test_vm_reserv_delete_spoil_size(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_delete_spoil_size " + "<file> <size>"); + size_t size = ATOUL(argv[1]); + size_t rsv_size; + struct pmem2_vm_reservation *rsv; + + /* create a reservation in the virtual memory */ + int ret = pmem2_vm_reservation_new(&rsv, NULL, size); + UT_ASSERTeq(ret, 0); + + rsv_size = pmem2_vm_reservation_get_size(rsv); + /* spoil vm_reservation struct address */ + rsv->size = 0; + + ret = pmem2_vm_reservation_delete(&rsv); + UT_PMEM2_EXPECT_RETURN(ret, -EINVAL); + + /* restore the appropriate size */ + rsv->size = rsv_size; + + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + + return 2; +} + +/* + * test_vm_reserv_map_unmap_multiple_files - map multiple files to a + * vm reservation, then unmap every 2nd mapping and map the mapping again + */ +static int +test_vm_reserv_map_unmap_multiple_files(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_unmap_multiple_files " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_offset; + size_t rsv_size; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map **map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + size_t NMAPPINGS = 10; + + map = MALLOC(sizeof(struct pmem2_map *) * NMAPPINGS); + + rsv_size = NMAPPINGS * size + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + size_t align_offset = offset_align_to_devdax(rsv_addr, alignment); + rsv_offset = align_offset; + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + + for (size_t i = 0; i < NMAPPINGS; i++, rsv_offset += size) { + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map[i], &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, 0); + + UT_ASSERTeq((char *)rsv_addr + rsv_offset, + pmem2_map_get_address(map[i])); + } + + for (size_t i = 0; i < NMAPPINGS; i += 2) { + ret = pmem2_map_delete(&map[i]); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map[i], NULL); + } + + rsv_offset = align_offset; + for (size_t i = 0; i < NMAPPINGS; i += 2, rsv_offset += 2 * size) { + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map[i], &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, 0); + + UT_ASSERTeq((char *)rsv_addr + rsv_offset, + pmem2_map_get_address(map[i])); + } + + for (size_t i = 0; i < NMAPPINGS; i++) { + ret = pmem2_map_delete(&map[i]); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map[i], NULL); + } + + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + FREE(map); + + return 2; +} + +/* + * test_vm_reserv_map_insufficient_space - map a file to a vm reservation + * with insufficient space + */ +static int +test_vm_reserv_map_insufficient_space(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_insufficient_space " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + void *rsv_addr; + size_t rsv_size; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + rsv_size = size / 2; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, 0); + + ret = pmem2_map_new(&map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_LENGTH_OUT_OF_RANGE); + + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_map_full_overlap - map a file to a vm reservation + * and overlap existing mapping + */ +static int +test_vm_reserv_map_full_overlap(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_full_overlap " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_offset; + size_t rsv_size; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_map *overlap_map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + rsv_size = size + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + rsv_offset = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, 0); + + ret = pmem2_map_new(&overlap_map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAPPING_EXISTS); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_map_partial_overlap_below - map a file to a vm reservation + * overlapping with the ealier half of the other existing mapping + */ +static int +test_vm_reserv_map_partial_overlap_below(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_partial_overlap_below " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_size; + size_t rsv_offset; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_map *overlap_map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + rsv_size = size + size / 2 + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + size_t offset_align = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + + rsv_offset = ALIGN_DOWN(size / 2, alignment) + offset_align; + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_ASSERTeq(ret, 0); + + rsv_offset = offset_align; + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&overlap_map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAPPING_EXISTS); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_map_partial_overlap_above - map a file to a vm reservation + * overlapping with the latter half of the other existing mapping + */ +static int +test_vm_reserv_map_partial_overlap_above(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_partial_overlap_above " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_size; + size_t rsv_offset; + struct FHandle *fh; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_map *overlap_map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + + rsv_size = size + size / 2 + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + size_t offset_align = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + + rsv_offset = offset_align; + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_ASSERTeq(ret, 0); + + rsv_offset = ALIGN_DOWN(size / 2, alignment) + offset_align; + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&overlap_map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAPPING_EXISTS); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +/* + * test_vm_reserv_map_invalid_granularity - map a file with invalid granularity + * to a vm reservation in the middle of the vm reservation bigger than + * the file, then map a file that covers whole vm reservation + */ +static int +test_vm_reserv_map_invalid_granularity(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: test_vm_reserv_map_invalid_granularity " + "<file> <size>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t offset = 0; + size_t rsv_offset; + size_t rsv_size; + struct pmem2_config cfg; + struct pmem2_map *map; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + struct FHandle *fh; + + /* map only half of the file */ + offset = size / 2; + + rsv_size = size; + /* map it to the middle of the vm reservation */ + rsv_offset = size / 4; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, offset, + FH_RDWR); + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + /* spoil requested granularity */ + enum pmem2_granularity gran = cfg.requested_max_granularity; + cfg.requested_max_granularity = PMEM2_GRANULARITY_BYTE; + + ret = pmem2_map_new(&map, &cfg, src); + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_GRANULARITY_NOT_SUPPORTED); + + /* map whole file */ + offset = 0; + rsv_offset = 0; + + /* restore correct granularity */ + cfg.requested_max_granularity = gran; + cfg.offset = offset; + + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + ret = pmem2_map_new(&map, &cfg, src); + UT_ASSERTeq(ret, 0); + + UT_ASSERTeq((char *)pmem2_vm_reservation_get_address(rsv) + + rsv_offset, pmem2_map_get_address(map)); + + ret = pmem2_map_delete(&map); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(map, NULL); + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 2; +} + +#define MAX_THREADS 32 + +struct worker_args { + struct pmem2_config cfg; + struct pmem2_source *src; + struct pmem2_map **map; + size_t n_ops; + os_mutex_t lock; +}; + +static void * +map_worker(void *arg) +{ + struct worker_args *warg = arg; + + for (size_t n = 0; n < warg->n_ops; n++) { + if (!(*warg->map)) { + int ret = pmem2_map_new(warg->map, &warg->cfg, + warg->src); + if (ret != PMEM2_E_MAPPING_EXISTS) + UT_ASSERTeq(ret, 0); + } + } + + return NULL; +} + +static void * +unmap_worker(void *arg) +{ + struct worker_args *warg = arg; + + for (size_t n = 0; n < warg->n_ops; n++) { + if (*(warg->map)) { + int ret = pmem2_map_delete(warg->map); + if (ret != PMEM2_E_MAPPING_NOT_FOUND) + UT_ASSERTeq(ret, 0); + } + } + + return NULL; +} + +static void +run_worker(void *(worker_func)(void *arg), struct worker_args args[], + size_t n_threads) +{ + os_thread_t threads[MAX_THREADS]; + + for (size_t n = 0; n < n_threads; n++) + THREAD_CREATE(&threads[n], NULL, worker_func, &args[n]); + + for (size_t n = 0; n < n_threads; n++) + THREAD_JOIN(&threads[n], NULL); +} + +/* + * test_vm_reserv_async_map_unmap_multiple_files - map and unmap + * asynchronously multiple files to the vm reservation. Mappings + * will occur to 3 different overlapping regions of the vm reservation. + */ +static int +test_vm_reserv_async_map_unmap_multiple_files(const struct test_case *tc, + int argc, char *argv[]) +{ + if (argc < 4) + UT_FATAL("usage: test_vm_reserv_async_map_unmap_multiple_files" + "<file> <size> <threads> <ops/thread>"); + + char *file = argv[0]; + size_t size = ATOUL(argv[1]); + size_t n_threads = ATOU(argv[2]); + size_t ops_per_thread = ATOU(argv[3]); + size_t alignment = get_align_by_filename(file); + void *rsv_addr; + size_t rsv_size; + size_t rsv_offset; + struct pmem2_config cfg; + struct pmem2_map *map[MAX_THREADS]; + struct pmem2_vm_reservation *rsv; + struct pmem2_source *src; + struct FHandle *fh; + struct worker_args args[MAX_THREADS]; + + for (size_t n = 0; n < n_threads; n++) + map[n] = NULL; + + /* + * reservation will fit as many files as there are threads + 1, + * it's expanded by the length of alignment, for the device DAX + */ + rsv_size = (n_threads + 1) * (size / 2) + alignment; + + int ret = pmem2_vm_reservation_new(&rsv, NULL, rsv_size); + UT_ASSERTeq(ret, 0); + + rsv_addr = pmem2_vm_reservation_get_address(rsv); + UT_ASSERTne(rsv_addr, NULL); + UT_ASSERTeq(pmem2_vm_reservation_get_size(rsv), rsv_size); + + /* in case of DevDax */ + size_t offset_align = offset_align_to_devdax(rsv_addr, alignment); + + ut_pmem2_prepare_config(&cfg, &src, &fh, FH_FD, file, 0, 0, FH_RDWR); + + /* + * the offset increases by the half of file size. + */ + for (size_t n = 0; n < n_threads; n++) { + /* calculate offset for each thread */ + rsv_offset = ALIGN_DOWN((n % n_threads) * (size / 2), alignment) + + offset_align; + pmem2_config_set_vm_reservation(&cfg, rsv, rsv_offset); + + args[n].cfg = cfg; + args[n].src = src; + args[n].map = &(map[n]); + args[n].n_ops = ops_per_thread; + } + + run_worker(map_worker, args, n_threads); + run_worker(unmap_worker, args, n_threads); + + ret = pmem2_vm_reservation_delete(&rsv); + UT_ASSERTeq(ret, 0); + PMEM2_SOURCE_DELETE(&src); + UT_FH_CLOSE(fh); + + return 4; +} + +/* + * test_cases -- available test cases + */ +static struct test_case test_cases[] = { + TEST_CASE(test_vm_reserv_new_region_occupied_map), + TEST_CASE(test_vm_reserv_new_region_occupied_reserv), + TEST_CASE(test_vm_reserv_new_unaligned_addr), + TEST_CASE(test_vm_reserv_new_unaligned_size), + TEST_CASE(test_vm_reserv_new_alloc_enomem), + TEST_CASE(test_vm_reserv_map_file), + TEST_CASE(test_vm_reserv_map_part_file), + TEST_CASE(test_vm_reserv_delete_contains_mapping), + TEST_CASE(test_vm_reserv_delete_spoil_addr), + TEST_CASE(test_vm_reserv_delete_spoil_size), + TEST_CASE(test_vm_reserv_map_unmap_multiple_files), + TEST_CASE(test_vm_reserv_map_insufficient_space), + TEST_CASE(test_vm_reserv_map_full_overlap), + TEST_CASE(test_vm_reserv_map_partial_overlap_above), + TEST_CASE(test_vm_reserv_map_partial_overlap_below), + TEST_CASE(test_vm_reserv_map_invalid_granularity), + TEST_CASE(test_vm_reserv_async_map_unmap_multiple_files), +}; + +#define NTESTS (sizeof(test_cases) / sizeof(test_cases[0])) + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "pmem2_vm_reservation"); + TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); + DONE(NULL); +} + +#ifdef _MSC_VER +MSVC_CONSTR(libpmem2_init) +MSVC_DESTR(libpmem2_fini) +#endif diff --git a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..15cea738672d1cd33b7d16933b00853ccaf9a924 --- /dev/null +++ b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{46629F21-089C-4205-B2F8-E01748ECE517}</ProjectGuid> + <RootNamespace>pmem2_vm_reservation</RootNamespace> + <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_debug.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_release.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>SSE2_AVAILABLE=0;AVX_AVAILABLE=0;AVX512F_AVAILABLE=0;PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(SolutionDir)\libpmem2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>$(SolutionDir)\libpmem2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>SSE2_AVAILABLE=0;AVX_AVAILABLE=0;AVX512F_AVAILABLE=0;PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectReference Include="..\..\common\libpmemcommon.vcxproj"> + <Project>{492baa3d-0d5d-478e-9765-500463ae69aa}</Project> + </ProjectReference> + <ProjectReference Include="..\unittest\libut.vcxproj"> + <Project>{ce3f2dfb-8470-4802-ad37-21caf6cb2681}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\common\ravl.c" /> + <ClCompile Include="..\..\libpmem2\config.c" /> + <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" /> + <ClCompile Include="..\..\libpmem2\errormsg.c" /> + <ClCompile Include="..\..\libpmem2\libpmem2.c" /> + <ClCompile Include="..\..\libpmem2\map.c" /> + <ClCompile Include="..\..\libpmem2\map_windows.c" /> + <ClCompile Include="..\..\libpmem2\memops_generic.c" /> + <ClCompile Include="..\..\libpmem2\persist.c" /> + <ClCompile Include="..\..\libpmem2\persist_windows.c" /> + <ClCompile Include="..\..\libpmem2\pmem2_utils.c" /> + <ClCompile Include="..\..\libpmem2\ravl_interval.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> + <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> + <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> + <ClCompile Include="..\unittest\ut_pmem2_setup.c" /> + <ClCompile Include="..\unittest\ut_pmem2_source.c" /> + <ClCompile Include="..\unittest\ut_pmem2_utils.c" /> + <ClCompile Include="pmem2_vm_reservation.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\libpmem2\config.h" /> + <ClInclude Include="..\..\libpmem2\map.h" /> + <ClInclude Include="..\..\libpmem2\pmem2.h" /> + <ClInclude Include="..\..\libpmem2\pmem2_utils.h" /> + <ClInclude Include="..\..\libpmem2\ravl_interval.h" /> + <ClInclude Include="..\..\libpmem2\vm_reservation.h" /> + <ClInclude Include="..\unittest\ut_pmem2.h" /> + </ItemGroup> + <ItemGroup> + <None Include="TESTS.py" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..ed6dafe142f6d6dbda46d431a5227d01b0d9d79d --- /dev/null +++ b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{8e615e81-25ad-4c2a-a3c6-bf218e0a061d}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{20f46654-0d24-490d-b218-796e96870756}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Test Scripts"> + <UniqueIdentifier>{bd82aadd-ffea-4758-b76b-076667552825}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pmem2_vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_utils.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\common\ravl.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\pmem2_utils.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\errormsg.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\config.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\map.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\map_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\libpmem2.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\persist.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\persist_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\x86_64\cpu.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\x86_64\init.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\memops_generic.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_source.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\deep_flush_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_setup.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\ravl_interval.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\libpmem2\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\pmem2_utils.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\map.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\pmem2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\unittest\ut_pmem2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\ravl_interval.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\vm_reservation.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="TESTS.py"> + <Filter>Test Scripts</Filter> + </None> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/src/test/scope/out13.log.match b/src/test/scope/out13.log.match index 925fa482dcba0e11f2da2a8bfd1e3bc794607c4c..c95fcca7cf796e49146e7e55a69e3f94050fc00e 100644 --- a/src/test/scope/out13.log.match +++ b/src/test/scope/out13.log.match @@ -34,4 +34,6 @@ pmem2_source_from_anon$(nW) pmem2_source_from_fd$(nW) pmem2_source_size$(nW) pmem2_vm_reservation_delete$(nW) +pmem2_vm_reservation_get_address$(nW) +pmem2_vm_reservation_get_size$(nW) pmem2_vm_reservation_new$(nW) diff --git a/src/test/scope/out14.log.match b/src/test/scope/out14.log.match index 31d27c9e5098ab37f0f4d348648598b3c0e90def..5cdcc3df9946ba73f32d33c4609383b34a8ae54a 100644 --- a/src/test/scope/out14.log.match +++ b/src/test/scope/out14.log.match @@ -38,4 +38,6 @@ pmem2_source_from_fd pmem2_source_from_handle pmem2_source_size pmem2_vm_reservation_delete +pmem2_vm_reservation_get_address +pmem2_vm_reservation_get_size pmem2_vm_reservation_new diff --git a/src/test/test_debug.props b/src/test/test_debug.props index f95d41782d313bb1cc336c9336da7c69e2aab2e8..b0deaea438f0c1df31730ca4f35bb42d4a6bcf34 100644 --- a/src/test/test_debug.props +++ b/src/test/test_debug.props @@ -16,14 +16,14 @@ <ItemDefinitionGroup> <ClCompile> <TreatWarningAsError>true</TreatWarningAsError> - <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS4;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)\windows\include;$(SolutionDir)\include;$(SolutionDir)\common;$(SolutionDir)\core;$(SolutionDir)\test\unittest</AdditionalIncludeDirectories> <CompileAs>CompileAsC</CompileAs> <ForcedIncludeFiles>platform.h</ForcedIncludeFiles> </ClCompile> <Link> <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors> - <AdditionalDependencies>DbgHelp.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>DbgHelp.lib;Shlwapi.lib;mincore.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem>Console</SubSystem> </Link> </ItemDefinitionGroup> diff --git a/src/test/test_release.props b/src/test/test_release.props index 8983615546960fdf99dd8dd25bdd0ecd63d8d189..e7876b215b15247236311f58c9c6e27a103dacca 100644 --- a/src/test/test_release.props +++ b/src/test/test_release.props @@ -10,7 +10,7 @@ </PropertyGroup> <ItemDefinitionGroup> <ClCompile> - <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS4;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)\windows\include;$(SolutionDir)\include;$(SolutionDir)\common;$(SolutionDir)\core;$(SolutionDir)\test\unittest</AdditionalIncludeDirectories> <WarningLevel>Level3</WarningLevel> <TreatWarningAsError>true</TreatWarningAsError> @@ -19,7 +19,7 @@ </ClCompile> <Link> <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors> - <AdditionalDependencies>DbgHelp.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>DbgHelp.lib;mincore.lib;%(AdditionalDependencies)</AdditionalDependencies> <SubSystem>Console</SubSystem> </Link> </ItemDefinitionGroup> diff --git a/src/test/util_sds/util_sds.vcxproj b/src/test/util_sds/util_sds.vcxproj index e7487b158b50a1c3818e27d9a6c3f84390a02098..efde48c9a6e9d80b07c46a9af4a70a29e41c93e0 100644 --- a/src/test/util_sds/util_sds.vcxproj +++ b/src/test/util_sds/util_sds.vcxproj @@ -83,6 +83,8 @@ </ClCompile> <ClCompile Include="..\..\libpmem2\source.c" /> <ClCompile Include="..\..\libpmem2\source_windows.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> <ClCompile Include="..\..\libpmem2\x86_64\memcpy\memcpy_nt_avx.c"> diff --git a/src/test/util_sds/util_sds.vcxproj.filters b/src/test/util_sds/util_sds.vcxproj.filters index 926593c46105c491a57e619fa024f34e0b78b864..b50fbbb87248b46cc24bac7790f66d63886c1f35 100644 --- a/src/test/util_sds/util_sds.vcxproj.filters +++ b/src/test/util_sds/util_sds.vcxproj.filters @@ -112,6 +112,12 @@ <ClCompile Include="..\..\libpmem2\ravl_interval.c"> <Filter>Source Files\pmem2</Filter> </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files\pmem2</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files\pmem2</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="mocks_windows.h"> diff --git a/src/windows/libs_debug.props b/src/windows/libs_debug.props index daae341b75f624d8464f8a10e8fd40a317718b06..32d4306b00ec28d31c7c5d6cfb14ca8bfa53125f 100644 --- a/src/windows/libs_debug.props +++ b/src/windows/libs_debug.props @@ -9,7 +9,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(SolutionDir)\common;$(SolutionDir)\core;$(SolutionDir)\$(TargetName)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_CRT_SECURE_NO_WARNINGS;_WINDLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS4;_CRT_SECURE_NO_WARNINGS;_WINDLL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <CompileAs>CompileAsC</CompileAs> <BrowseInformation>true</BrowseInformation> <ForcedIncludeFiles>platform.h</ForcedIncludeFiles> @@ -20,7 +20,7 @@ </ClCompile> <Link> <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors> - <AdditionalDependencies>shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>shlwapi.lib;ntdll.lib;mincore.lib;%(AdditionalDependencies)</AdditionalDependencies> <ModuleDefinitionFile>$(TargetName).def</ModuleDefinitionFile> <GenerateDebugInformation>true</GenerateDebugInformation> <GenerateMapFile>true</GenerateMapFile> diff --git a/src/windows/libs_release.props b/src/windows/libs_release.props index cf2041d4fe8a51cb8aac5e7015d27fc833c781ad..20728c2aa8e1719bc7314c2f31b00c1896b9e177 100644 --- a/src/windows/libs_release.props +++ b/src/windows/libs_release.props @@ -9,7 +9,7 @@ <ItemDefinitionGroup> <ClCompile> <AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(SolutionDir)\common;$(SolutionDir)\core;$(SolutionDir)\$(TargetName)</AdditionalIncludeDirectories> - <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_CRT_SECURE_NO_WARNINGS;_WINDLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS4;_CRT_SECURE_NO_WARNINGS;_WINDLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <CompileAs>CompileAsC</CompileAs> <BrowseInformation>true</BrowseInformation> <ForcedIncludeFiles>platform.h</ForcedIncludeFiles> @@ -21,7 +21,7 @@ </ClCompile> <Link> <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors> - <AdditionalDependencies>shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>shlwapi.lib;ntdll.lib;mincore.lib;%(AdditionalDependencies)</AdditionalDependencies> <ModuleDefinitionFile>$(TargetName).def</ModuleDefinitionFile> <GenerateDebugInformation>DebugFastLink</GenerateDebugInformation> <GenerateMapFile>false</GenerateMapFile>