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>