diff --git a/.cirrus.yml b/.cirrus.yml
index 3b337a56950afa7368817ca9d32e720c80e18c2d..4757d0a5625de5a4edbd3bc28c65cf0ef4201372 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -4,7 +4,7 @@ freebsd_instance:
 task:
   install_script: ASSUME_ALWAYS_YES=yes pkg bootstrap -f;
     pkg install -y
-    autoconf bash binutils coreutils e2fsprogs-libuuid
+    autoconf bash binutils cmake coreutils e2fsprogs-libuuid
     git gmake libunwind ncurses pkgconf hs-pandoc
 
   script: CFLAGS="-Wno-unused-value" gmake
diff --git a/doc/Makefile b/doc/Makefile
index edf36b2f13c09420af41ac9c650a6eb30a74a90c..1c03ab892e15b2b998621be2bf04039d01e86d48 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -101,8 +101,8 @@ MANPAGES_3_MD_PMEM2 = libpmem2/pmem2_errormsg.3.md libpmem2/pmem2_config_new.3.m
 		libpmem2/pmem2_config_set_length.3.md libpmem2/pmem2_config_set_offset.3.md \
 		libpmem2/pmem2_map_get_store_granularity.3.md libpmem2/pmem2_get_flush_fn.3.md \
 		libpmem2/pmem2_get_drain_fn.3.md libpmem2/pmem2_get_persist_fn.3.md \
-		libpmem2/pmem2_perror.3.md libpmem2/pmem2_get_memmove_fn.3.md libpmem2/pmem2_config_set_sharing.3.md \
-		libpmem2/pmem2_config_set_vm_reservation.3.md libpmem2/pmem2_vm_reservation_new.3.md \
+		libpmem2/pmem2_perror.3.md libpmem2/pmem2_get_memmove_fn.3.md libpmem2/pmem2_memcpy_async.3.md\
+		libpmem2/pmem2_config_set_sharing.3.md libpmem2/pmem2_config_set_vm_reservation.3.md libpmem2/pmem2_vm_reservation_new.3.md \
 		libpmem2/pmem2_vm_reservation_get_address.3.md libpmem2/pmem2_vm_reservation_get_size.3.md \
 		libpmem2/pmem2_badblock_context_new.3.md libpmem2/pmem2_badblock_next.3.md \
 		libpmem2/pmem2_badblock_clear.3.md libpmem2/pmem2_config_set_protection.3.md \
@@ -113,7 +113,7 @@ MANPAGES_3_MD_PMEM2 = libpmem2/pmem2_errormsg.3.md libpmem2/pmem2_config_new.3.m
 		libpmem2/pmem2_vm_reservation_map_find.3.md libpmem2/pmem2_source_pread_mcsafe.3.md \
 
 MANPAGES_1_MD_PMEM2 =
-MANPAGES_3_DUMMY += libpmem2/pmem2_config_delete.3 libpmem2/pmem2_source_from_handle.3 libpmem2/pmem2_source_delete.3 \
+MANPAGES_3_DUMMY += libpmem2/pmem2_config_delete.3 libpmem2/pmem2_config_set_vdm.3 libpmem2/pmem2_source_from_handle.3 libpmem2/pmem2_source_delete.3 \
 	libpmem2/pmem2_get_memset_fn.3 libpmem2/pmem2_get_memcpy_fn.3 libpmem2/pmem2_vm_reservation_delete.3 \
 	libpmem2/pmem2_badblock_context_delete.3 libpmem2/pmem2_vm_reservation_shrink.3 \
 	libpmem2/pmem2_vm_reservation_map_find_first.3 libpmem2/pmem2_vm_reservation_map_find_last.3 \
diff --git a/doc/libpmem2/.gitignore b/doc/libpmem2/.gitignore
index a37e30efeaab1c35b8b7753317508a27751c144f..a1b3a358cfaeb4aed5e47516d620811a27b0cd1c 100644
--- a/doc/libpmem2/.gitignore
+++ b/doc/libpmem2/.gitignore
@@ -22,6 +22,7 @@ pmem2_map_new.3
 pmem2_map_get_address.3
 pmem2_map_get_size.3
 pmem2_map_get_store_granularity.3
+pmem2_memcpy_async.3
 pmem2_source_alignment.3
 pmem2_source_from_fd.3
 pmem2_source_from_anon.3
diff --git a/doc/libpmem2/pmem2_config_set_vdm.3 b/doc/libpmem2/pmem2_config_set_vdm.3
new file mode 100644
index 0000000000000000000000000000000000000000..8e81274f85cd1576b8bc70188ae53d6c0d5fa9cd
--- /dev/null
+++ b/doc/libpmem2/pmem2_config_set_vdm.3
@@ -0,0 +1 @@
+.so pmem2_memcpy_async.3
diff --git a/doc/libpmem2/pmem2_get_memmove_fn.3.md b/doc/libpmem2/pmem2_get_memmove_fn.3.md
index f40063fda38c0ba164145d43aa8f33f658ebb0db..6148ac596c82d70a6d472519d89bb6e757b9ec53 100644
--- a/doc/libpmem2/pmem2_get_memmove_fn.3.md
+++ b/doc/libpmem2/pmem2_get_memmove_fn.3.md
@@ -44,7 +44,6 @@ pmem2_memcpy_fn pmem2_get_memcpy_fn(struct pmem2_map *map);
 ```
 
 # DESCRIPTION #
-
 The **pmem2_get_memmove_fn**(), **pmem2_get_memset_fn**(),
 **pmem2_get_memcpy_fn**() functions return a pointer to a function
 responsible for efficient storing and flushing of data for mapping *map*.
diff --git a/doc/libpmem2/pmem2_memcpy_async.3.md b/doc/libpmem2/pmem2_memcpy_async.3.md
new file mode 100644
index 0000000000000000000000000000000000000000..050813bca51f761574a5118f1f5618faaab14b65
--- /dev/null
+++ b/doc/libpmem2/pmem2_memcpy_async.3.md
@@ -0,0 +1,60 @@
+---
+layout: manual
+Content-Style: 'text/css'
+title: _MP(PMEM2_MEMCPY_ASYNC, 3)
+collection: libpmem2
+header: PMDK
+date: pmem2 API version 1.0
+...
+
+[comment]: <> (SPDX-License-Identifier: BSD-3-Clause
+[comment]: <> (Copyright 2022, Intel Corporation)
+
+[comment]: <> (pmem2_memcpy_async.3 -- man page for pmem2_memcpy_async)
+
+[NAME](#name)<br />
+[SYNOPSIS](#synopsis)<br />
+[DESCRIPTION](#description)<br />
+[RETURN VALUE](#return-value)<br />
+[SEE ALSO](#see-also)<br />
+
+# NAME #
+**pmem2_config_set_vdm**(), **pmem2_memcpy_async**() - asynchronous data movement operations
+
+# SYNOPSIS #
+
+```c
+#define PMEM2_USE_MINIASYNC 1
+#include <libpmem2.h>
+int pmem2_config_set_vdm(struct pmem2_config *cfg, struct vdm *vdm);
+
+struct vdm_operation_future pmem2_memcpy_async(struct pmem2_map *map,
+	void *pmemdest, const void *src, size_t len, unsigned flags);
+```
+
+# DESCRIPTION #
+To use those functions, you must have *libminiasync* installed. Those functions use futures
+and vdm (virtual data mover) concepts from this library. Please check **miniasync**(7) for more details.
+
+The **pmem2_config_set_vdm** sets a vdm structure in the *pmem2_config*.
+This structure will be used by pmem2_memcpy_async function, to create a *vdm_operation_future*.
+If vdm is not set in the config, pmem2_map_new will use a default one which uses a
+pmem2 memory movement functions to perform memory operations. (**pmem2_get_memcpy_fn**(3), **pmem2_get_memmove_fn**(3), **pmem2_get_memsety_fn**(3)).
+
+The **pmem2_memcpy_async** uses *vdm* structure held inside of the *pmem2_map* structure to initialise and return **vdm_operation_future**.
+This future will perform memcpy operation from *vdm* to copy *len* bytes from *src* to *pmemdest*. In the current implementation *flags* are ignored.
+
+# RETURN VALUE #
+
+The **pmem2_config_set_vdm** always return 0.
+
+The **pmem2_memcpy_async** returns a new instance of **vdm_operation_future** which will copy *len* bytes from *src* to *pmemdest*.
+You can execute returned structure using methods from the **libminiasync**() library.
+
+# SEE ALSO #
+
+**memcpy**(3), **memmove**(3), **memset**(3), **pmem2_get_drain_fn**(3),
+**pmem2_get_memcpy_fn**(3), **pmem2_get_memset_fn**(3), **pmem2_map_new**(3),
+**pmem2_get_persist_fn**(3), **vdm_memcpy**(3), **miniasync**(7), **miniasync_future**(7),
+**libpmem2**(7) and **<https://pmem.io>**
+
diff --git a/src/Makefile b/src/Makefile
index efc1a81cb83c274e6b8ea94f62b002748cb2887b..ee2fb2e78df7801a32a5ab67321c323d3b823a7b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2021, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 
 #
 # src/Makefile -- Makefile for PMDK
diff --git a/src/PMDK.sln b/src/PMDK.sln
index c267aa1d7c8daed0a65b805873175b3b02c45f61..d3a46c5ae7552db54384978666787f0ac2fd37fd 100644
--- a/src/PMDK.sln
+++ b/src/PMDK.sln
@@ -263,6 +263,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_lookup", "test\obj
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_pool_open_mt", "test\obj_pool_open_mt\obj_pool_open_mt.vcxproj", "{4850F425-9128-4E91-973C-5AE7BD97395C}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem2_mover", "test\pmem2_mover\pmem2_mover.vcxproj", "{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}"
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmemcommon", "common\libpmemcommon.vcxproj", "{492BAA3D-0D5D-478E-9765-500463AE69AA}"
 	ProjectSection(ProjectDependencies) = postProject
 		{901F04DB-E1A5-4A41-8B81-9D31C19ACD59} = {901F04DB-E1A5-4A41-8B81-9D31C19ACD59}
@@ -915,6 +917,9 @@ EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_vecq", "test\util_vecq\util_vecq.vcxproj", "{FD726AA3-D4FA-4597-B435-08CC7752888E}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basic", "examples\libpmemset\basic\basic.vcxproj", "{FE9C5A1D-7DEB-4549-A25B-2F975F3AD641}"
+	ProjectSection(ProjectDependencies) = postProject
+		{FBAEFC34-D221-4203-8BF6-162DE1A5BE1C} = {FBAEFC34-D221-4203-8BF6-162DE1A5BE1C}
+	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mmap_fixed", "test\mmap_fixed\mmap_fixed.vcxproj", "{FEA09B48-34C2-4963-8A5A-F97BDA136D72}"
 EndProject
@@ -980,7 +985,9 @@ Global
 		{07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Release|x64.ActiveCfg = Release|x64
 		{07A153D9-DF17-4DE8-A3C2-EBF171B961AE}.Release|x64.Build.0 = Release|x64
 		{082C1588-003E-4217-B41B-49BF4409BF83}.Debug|x64.ActiveCfg = Debug|x64
+		{082C1588-003E-4217-B41B-49BF4409BF83}.Debug|x64.Build.0 = Debug|x64
 		{082C1588-003E-4217-B41B-49BF4409BF83}.Release|x64.ActiveCfg = Release|x64
+		{082C1588-003E-4217-B41B-49BF4409BF83}.Release|x64.Build.0 = Release|x64
 		{08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Debug|x64.ActiveCfg = Debug|x64
 		{08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Debug|x64.Build.0 = Debug|x64
 		{08B62E36-63D2-4FF1-A605-4BBABAEE73FB}.Release|x64.ActiveCfg = Release|x64
@@ -1233,6 +1240,10 @@ Global
 		{4850F425-9128-4E91-973C-5AE7BD97395C}.Debug|x64.Build.0 = Debug|x64
 		{4850F425-9128-4E91-973C-5AE7BD97395C}.Release|x64.ActiveCfg = Release|x64
 		{4850F425-9128-4E91-973C-5AE7BD97395C}.Release|x64.Build.0 = Release|x64
+		{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}.Debug|x64.ActiveCfg = Debug|x64
+		{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}.Debug|x64.Build.0 = Debug|x64
+		{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}.Release|x64.ActiveCfg = Release|x64
+		{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}.Release|x64.Build.0 = Release|x64
 		{492BAA3D-0D5D-478E-9765-500463AE69AA}.Debug|x64.ActiveCfg = Debug|x64
 		{492BAA3D-0D5D-478E-9765-500463AE69AA}.Debug|x64.Build.0 = Debug|x64
 		{492BAA3D-0D5D-478E-9765-500463AE69AA}.Release|x64.ActiveCfg = Release|x64
@@ -2175,6 +2186,7 @@ Global
 		{47E7DAFC-4EDA-4007-BB7B-4BEB6D63C222} = {6F52D216-031F-4E5D-9E35-2EB517CE7FB4}
 		{4850F425-9128-4E91-973C-5AE7BD97395B} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6}
 		{4850F425-9128-4E91-973C-5AE7BD97395C} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6}
+		{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F} = {A14A4556-9092-430D-B9CA-B2B1223D56CB}
 		{492BAA3D-0D5D-478E-9765-500463AE69AA} = {853D45D8-980C-4991-B62A-DAC6FD245402}
 		{49A7CC5A-D5E7-4A07-917F-C6918B982BE8} = {BD6CC700-B36B-435B-BAF9-FC5AFCD766C9}
 		{4C291EEB-3874-4724-9CC2-1335D13FF0EE} = {746BA101-5C93-42A5-AC7A-64DCEB186572}
diff --git a/src/common.inc b/src/common.inc
index 80ff663028ac0987d980550ca6d9269ebbb4d029..70da589251f3ce627e925cf70d1c77c4e6ce2787 100644
--- a/src/common.inc
+++ b/src/common.inc
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 #
 # src/common.inc -- common Makefile rules for PMDK
 #
@@ -342,6 +342,9 @@ export USE_LIBUNWIND
 export LIBUNWIND_LIBS
 endif
 
+export MINIASYNC_CFLAGS := -I$(TOP)/src/deps/miniasync/src/include/
+export MINIASYNC_LIBS := -lminiasync
+
 ifeq ($(OS_KERNEL_NAME),FreeBSD)
 
 GLIBC_CXXFLAGS=-D_GLIBCXX_USE_C99
diff --git a/src/common/Makefile b/src/common/Makefile
index 2b2e5bfa4b2d1442c4e9e05b134652abbbf074bb..3a9b25ab1160108aca90a783eb9e3c59922bcccb 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -11,7 +11,7 @@ include pmemcommon.inc
 
 include ../Makefile.inc
 
-CFLAGS += $(LIBNDCTL_CFLAGS)
+CFLAGS += $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 CFLAGS += -DUSE_LIBDL
 # Librpmem is deprecated.
 # This flag allows to build tests, examples and benchmarks
diff --git a/src/common/libpmemcommon.vcxproj b/src/common/libpmemcommon.vcxproj
index 2ea3f8a80a5efb5b8467df66e05a5ceb81c5fb9f..0095e37c55621c99899cf44e215f17d8866ef79e 100644
--- a/src/common/libpmemcommon.vcxproj
+++ b/src/common/libpmemcommon.vcxproj
@@ -97,12 +97,12 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <LinkIncremental>true</LinkIncremental>
     <TargetExt>.lib</TargetExt>
-    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;</IncludePath>
+    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;$(SolutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <LinkIncremental>true</LinkIncremental>
     <TargetExt>.lib</TargetExt>
-    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;</IncludePath>
+    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;$(SolutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
@@ -160,4 +160,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/core/libpmemcore.vcxproj b/src/core/libpmemcore.vcxproj
index 58269d828cc3465a6d55a71640106cb10ceb679c..ddebb9561e3d6d4fe480562d91ea08b2bbabb4d7 100644
--- a/src/core/libpmemcore.vcxproj
+++ b/src/core/libpmemcore.vcxproj
@@ -73,12 +73,12 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <LinkIncremental>true</LinkIncremental>
     <TargetExt>.lib</TargetExt>
-    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;</IncludePath>
+    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;$(SolutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <LinkIncremental>true</LinkIncremental>
     <TargetExt>.lib</TargetExt>
-    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;</IncludePath>
+    <IncludePath>$(SolutionDir)\include;$(SolutionDir)\windows\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);.;$(SolutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
@@ -134,4 +134,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/core/membuf.c b/src/core/membuf.c
new file mode 100644
index 0000000000000000000000000000000000000000..bd471d4d1b7f7d691f4f3344f1008f6e8dd59d23
--- /dev/null
+++ b/src/core/membuf.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright 2022, Intel Corporation */
+
+/*
+ * membuf.c -- membuf implementation
+ */
+
+#include "membuf.h"
+#include "os_thread.h"
+#include "out.h"
+
+#define MEMBUF_ALIGNMENT (1 << 21) /* 2MB */
+#define MEMBUF_LEN (1 << 21) /* 2MB */
+
+struct threadbuf {
+	struct threadbuf *next; /* next threadbuf */
+	struct threadbuf *unused_next; /* next unused threadbuf */
+
+	struct membuf *membuf;
+
+	void *user_data; /* user-specified pointer */
+	size_t size; /* size of the buf variable */
+	size_t offset; /* current allocation offset */
+	size_t available; /* free space available in front of the offset */
+	size_t leftovers; /* space left unused on wraparound */
+	char buf[]; /* buffer with data */
+};
+
+struct membuf {
+	os_mutex_t lists_lock; /* protects both lists */
+	struct threadbuf *tbuf_first; /* linked-list of threadbufs, cleanup */
+	struct threadbuf *tbuf_unused_first; /* list of threadbufs for reuse */
+
+	os_tls_key_t bufkey; /* TLS key for threadbuf */
+	void *user_data; /* user-provided buffer data */
+};
+
+struct membuf_entry {
+	int32_t allocated; /* 1 - allocated, 0 - unused */
+	uint32_t size; /* size of the entry */
+	char data[]; /* user data */
+};
+
+/*
+ * membuf_key_destructor -- thread destructor for threadbuf
+ */
+static void
+membuf_key_destructor(void *data)
+{
+	/*
+	 * Linux TLS calls this callback only when a thread exits, but
+	 * the Windows FLS implementation also calls it when the key itself
+	 * is destroyed. To handle this difference, membuf only actually
+	 * deallocates thread buffers on module delete and this callback
+	 * puts the now unused thread buffer on a list to be reused.
+	 */
+	struct threadbuf *tbuf = data;
+	struct membuf *membuf = tbuf->membuf;
+
+	os_mutex_lock(&membuf->lists_lock);
+	tbuf->unused_next = membuf->tbuf_unused_first;
+	membuf->tbuf_unused_first = tbuf;
+	os_mutex_unlock(&membuf->lists_lock);
+}
+
+/*
+ * membuf_new -- allocates and initializes a new membuf instance
+ */
+struct membuf *
+membuf_new(void *user_data)
+{
+	struct membuf *membuf = malloc(sizeof(struct membuf));
+	if (membuf == NULL)
+		return NULL;
+
+	membuf->user_data = user_data;
+	membuf->tbuf_first = NULL;
+	membuf->tbuf_unused_first = NULL;
+	os_mutex_init(&membuf->lists_lock);
+
+	os_tls_key_create(&membuf->bufkey, membuf_key_destructor);
+
+	return membuf;
+}
+
+/*
+ * membuf_delete -- deallocates and cleans up a membuf instance
+ */
+void
+membuf_delete(struct membuf *membuf)
+{
+	os_tls_key_delete(membuf->bufkey);
+	for (struct threadbuf *tbuf = membuf->tbuf_first; tbuf != NULL; ) {
+		struct threadbuf *next = tbuf->next;
+		util_aligned_free(tbuf);
+		tbuf = next;
+	}
+	os_mutex_destroy(&membuf->lists_lock);
+	free(membuf);
+}
+
+/*
+ * membuf_entry_get_size -- returns the size of an entry
+ */
+static size_t
+membuf_entry_get_size(void *real_ptr)
+{
+	struct membuf_entry *entry = real_ptr;
+
+	uint32_t size;
+	util_atomic_load_explicit32(&entry->size, &size, memory_order_acquire);
+
+	return size;
+}
+
+/*
+ * membuf_entry_is_allocated -- checks whether the entry is allocated
+ */
+static int
+membuf_entry_is_allocated(void *real_ptr)
+{
+	struct membuf_entry *entry = real_ptr;
+	int32_t allocated;
+	util_atomic_load_explicit32(&entry->allocated,
+		&allocated, memory_order_acquire);
+
+	return allocated;
+}
+
+/*
+ * membuf_get_threadbuf -- returns thread-local buffer for allocations
+ */
+static struct threadbuf *
+membuf_get_threadbuf(struct membuf *membuf)
+{
+	struct threadbuf *tbuf = os_tls_get(membuf->bufkey);
+	if (tbuf != NULL)
+		return tbuf;
+
+	os_mutex_lock(&membuf->lists_lock);
+
+	if (membuf->tbuf_unused_first != NULL) {
+		tbuf = membuf->tbuf_unused_first;
+		membuf->tbuf_unused_first = tbuf->unused_next;
+	} else {
+		/*
+		 * Make sure buffer is aligned to 2MB so that we can align down
+		 * from contained pointers to access metadata (like user_data).
+		 */
+		tbuf = util_aligned_malloc(MEMBUF_ALIGNMENT, MEMBUF_LEN);
+		if (tbuf == NULL) {
+			os_mutex_unlock(&membuf->lists_lock);
+			return NULL;
+		}
+
+		tbuf->next = membuf->tbuf_first;
+		membuf->tbuf_first = tbuf;
+	}
+
+	tbuf->size = MEMBUF_LEN - sizeof(*tbuf);
+	tbuf->offset = 0;
+	tbuf->leftovers = 0;
+	tbuf->unused_next = NULL;
+	tbuf->membuf = membuf;
+	tbuf->available = tbuf->size;
+	tbuf->user_data = membuf->user_data;
+	os_tls_set(membuf->bufkey, tbuf);
+
+	os_mutex_unlock(&membuf->lists_lock);
+
+	return tbuf;
+}
+
+/*
+ * membuf_threadbuf_prune -- reclaims available buffer space
+ */
+static void
+membuf_threadbuf_prune(struct threadbuf *tbuf)
+{
+	while (tbuf->available != tbuf->size) {
+		/* reuse leftovers after a wraparound */
+		if (tbuf->leftovers != 0 &&
+			(tbuf->size - (tbuf->offset + tbuf->available))
+				== tbuf->leftovers) {
+			tbuf->available += tbuf->leftovers;
+			tbuf->leftovers = 0;
+
+			continue;
+		}
+
+		/* check the next object after the available memory */
+		size_t next_loc = (tbuf->offset + tbuf->available) % tbuf->size;
+		void *next = &tbuf->buf[next_loc];
+		if (membuf_entry_is_allocated(next))
+			return;
+
+		tbuf->available += membuf_entry_get_size(next);
+	}
+}
+
+/*
+ * membuf_alloc -- allocate linearly from the available memory location.
+ */
+void *
+membuf_alloc(struct membuf *membuf, size_t size)
+{
+	struct threadbuf *tbuf = membuf_get_threadbuf(membuf);
+	if (tbuf == NULL)
+		return NULL;
+
+	size_t real_size = size + sizeof(struct membuf_entry);
+
+	if (real_size > tbuf->size)
+		return NULL;
+
+	if (tbuf->offset + real_size > tbuf->size) {
+		tbuf->leftovers = tbuf->available;
+		tbuf->offset = 0;
+		tbuf->available = 0;
+	}
+
+	/* wait until enough memory becomes available */
+	if (real_size > tbuf->available) {
+		membuf_threadbuf_prune(tbuf);
+		/*
+		 * Fail if not enough space was reclaimed and no
+		 * memory is available for further reclamation.
+		 */
+		if (real_size > tbuf->available)
+			return NULL;
+	}
+
+	size_t pos = tbuf->offset;
+	tbuf->offset += real_size;
+	tbuf->available -= real_size;
+
+	struct membuf_entry *entry = (struct membuf_entry *)&tbuf->buf[pos];
+	entry->size = (uint32_t)real_size;
+	entry->allocated = 1;
+
+	return &entry->data;
+}
+
+/*
+ * membuf_free -- deallocates an entry
+ */
+void
+membuf_free(void *ptr)
+{
+	struct membuf_entry *entry = (struct membuf_entry *)
+		((uintptr_t)ptr - sizeof(struct membuf_entry));
+
+	util_atomic_store_explicit64(&entry->allocated, 0,
+		memory_order_release);
+}
+
+/*
+ * membuf_ptr_user_data -- return the user data pointer for membuf associated
+ * with the given allocation.
+ */
+void *
+membuf_ptr_user_data(void *ptr)
+{
+	struct threadbuf *tbuf = (struct threadbuf *)ALIGN_DOWN((ptrdiff_t)ptr,
+		MEMBUF_ALIGNMENT);
+
+	return tbuf->user_data;
+}
diff --git a/src/core/membuf.h b/src/core/membuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..e85264373cc5a8ff9c6e67f5e5a7eec4ae883def
--- /dev/null
+++ b/src/core/membuf.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright 2022, Intel Corporation */
+
+/*
+ * membuf.h -- definitions for "membuf" module.
+ *
+ * Membuf is a circular object buffer. Each instance uses an internal
+ * per-thread buffer to avoid heavyweight synchronization.
+ *
+ * Allocation is linear and very cheap. The expectation is that objects within
+ * the buffer will be reclaimable long before the linear allocator might need
+ * to wraparound to reuse memory.
+ */
+
+#ifndef MEMBUF_H
+#define MEMBUF_H
+
+#include <stddef.h>
+
+struct membuf;
+
+struct membuf *membuf_new(void *user_data);
+void membuf_delete(struct membuf *membuf);
+
+void *membuf_alloc(struct membuf *membuf, size_t size);
+void membuf_free(void *ptr);
+
+void *membuf_ptr_user_data(void *ptr);
+
+#endif
diff --git a/src/core/pmemcore.inc b/src/core/pmemcore.inc
index d701ab0cb97bc25a39419308259c3d7a66018e52..df08c15ae858df8b6ec60465af7ca1f8b05d69be 100644
--- a/src/core/pmemcore.inc
+++ b/src/core/pmemcore.inc
@@ -34,6 +34,7 @@
 SOURCE +=\
 	$(CORE)/alloc.c\
 	$(CORE)/fs_posix.c\
+	$(CORE)/membuf.c\
 	$(CORE)/os_posix.c\
 	$(CORE)/os_thread_posix.c\
 	$(CORE)/out.c\
diff --git a/src/deps/Makefile b/src/deps/Makefile
index 8cad8f73f7906032f1db8a21d5bf99f83643cf7f..69523ba20c40a74e3efa38d98edaeb400b944078 100644
--- a/src/deps/Makefile
+++ b/src/deps/Makefile
@@ -1,10 +1,14 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2021, Intel Corporation
+# Copyright 2022, Intel Corporation
 
 #
 # src/deps/makefile -- build miniasync
 #
 
+OS_KERNEL_NAME := $(shell uname -s)
+# XXX: miniasync works only on Linux (and Windows)
 all clean clobber:
+ifeq ($(OS_KERNEL_NAME),Linux)
 	$(MAKE) -C miniasync $@
+endif
 cstyle check:
diff --git a/src/deps/miniasync/Libminiasync.vcxproj b/src/deps/miniasync/Libminiasync.vcxproj
index d2928118b1e4bd1537198b8935c2036ade1e35af..42b5736ef729e35b25a9a300281d0775b145baca 100644
--- a/src/deps/miniasync/Libminiasync.vcxproj
+++ b/src/deps/miniasync/Libminiasync.vcxproj
@@ -15,18 +15,19 @@
     <Keyword>Win32Proj</Keyword>
     <ProjectGuid>{082c1588-003e-4217-b41b-49bf4409bf83}</ProjectGuid>
     <RootNamespace>Libminiasync</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Utility</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
@@ -69,7 +70,7 @@
       <Command>(IF NOT EXIST "build\*.sln" ( cmake -H"." -B"build" ))</Command>
     </PreBuildEvent>
     <PostBuildEvent>
-      <Command>cmake --build "build" --config "$(Configuration)"</Command>
+      <Command>cmake --build "build" --config "Release"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -87,11 +88,11 @@
       <OptimizeReferences>true</OptimizeReferences>
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
-	<PreBuildEvent>
+    <PreBuildEvent>
       <Command>(IF NOT EXIST "build\*.sln" ( cmake -H"." -B"build" ))</Command>
     </PreBuildEvent>
     <PostBuildEvent>
-      <Command>cmake --build "build" --config "$(Configuration)"</Command>
+      <Command>cmake --build "build" --config "Release"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemGroup>
diff --git a/src/deps/miniasync/Makefile b/src/deps/miniasync/Makefile
index c3f625da41075701b51f3ea8bf9014afc31db4c6..18a5458a8817744474c9bc6501071c3802cb0d87 100644
--- a/src/deps/miniasync/Makefile
+++ b/src/deps/miniasync/Makefile
@@ -1,12 +1,12 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2021, Intel Corporation
+# Copyright 2022, Intel Corporation
 
 #
-# src/deps/miniasyc/makefile -- build miniasync
+# src/deps/miniasync/makefile -- build miniasync
 #
 
 # WARNING: This file is created in the pmdk repository
-# and doens't belong to the pmem/miniasyc repository.
+# and doesn't belong to the pmem/miniasync repository.
 #
 
 dir = build
diff --git a/src/examples/examples_debug.props b/src/examples/examples_debug.props
index f0ab61104d402986716996d7f2e660173ba64bb3..651496d2570a8c160e663cb147f9685a57dff707 100644
--- a/src/examples/examples_debug.props
+++ b/src/examples/examples_debug.props
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ImportGroup Label="PropertySheets"/>
+  <ImportGroup Label="PropertySheets" />
   <PropertyGroup>
     <IntDir>$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
     <TargetName>ex_$(RootNamespace)_$(ProjectName)</TargetName>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\examples\</OutDir>
-    <IncludePath>.;$(solutionDir)include;$(solutionDir)..\include;$(ProjectDir)..\..\;$(ProjectDir)..\;$(IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
+    <IncludePath>.;$(solutionDir)include;$(solutionDir)..\include;$(ProjectDir)..\..\;$(ProjectDir)..\;$(IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
     <LibraryPath>$(ProjectDir)..\..\x64\$(Configuration)\libs;$(ProjectDir)..\..\..\x64\$(Configuration)\libs;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
   </PropertyGroup>
   <ItemDefinitionGroup>
@@ -21,4 +21,4 @@
       <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
     </Link>
   </ItemDefinitionGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/examples/examples_release.props b/src/examples/examples_release.props
index cabc9f75b57062461dc9999557314cdfb87cae28..a83199e28e01bb66aa41d1bf440e3bd9780d696f 100644
--- a/src/examples/examples_release.props
+++ b/src/examples/examples_release.props
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ImportGroup Label="PropertySheets"/>
+  <ImportGroup Label="PropertySheets" />
   <PropertyGroup>
     <IntDir>$(Platform)\$(Configuration)\$(TargetName)\</IntDir>
     <TargetName>ex_$(RootNamespace)_$(ProjectName)</TargetName>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\examples\</OutDir>
     <LibraryPath>$(ProjectDir)..\..\x64\$(Configuration)\libs;$(ProjectDir)..\..\..\x64\$(Configuration)\libs;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
-    <IncludePath>.;$(solutionDir)include;$(solutionDir)..\include;$(ProjectDir)..\..\;$(ProjectDir)..\;$(IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
+    <IncludePath>.;$(solutionDir)include;$(solutionDir)..\include;$(ProjectDir)..\..\;$(ProjectDir)..\;$(IncludePath);$(WindowsSDK_IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
@@ -25,4 +25,4 @@
       <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
     </Link>
   </ItemDefinitionGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/include/libpmem2.h b/src/include/libpmem2.h
index 1ebab3620af1a06419b65390df9e079d01981899..162c336dfed5dcefd311fcf70dc3d25b27f1b41d 100644
--- a/src/include/libpmem2.h
+++ b/src/include/libpmem2.h
@@ -16,7 +16,9 @@
 
 #include <stddef.h>
 #include <stdint.h>
-
+#ifdef PMEM2_USE_MINIASYNC
+#include <libminiasync/vdm.h>
+#endif
 #ifdef _WIN32
 #include <pmemcompat.h>
 
@@ -175,7 +177,6 @@ int pmem2_config_set_vm_reservation(struct pmem2_config *cfg,
 		struct pmem2_vm_reservation *rsv, size_t offset);
 
 /* mapping */
-
 struct pmem2_map;
 int pmem2_map_from_existing(struct pmem2_map **map,
 	const struct pmem2_source *src, void *addr, size_t len,
@@ -276,6 +277,13 @@ void pmem2_badblock_context_delete(
 int pmem2_badblock_clear(struct pmem2_badblock_context *bbctx,
 		const struct pmem2_badblock *bb);
 
+#ifdef PMEM2_USE_MINIASYNC
+int pmem2_config_set_vdm(struct pmem2_config *cfg, struct vdm *vdm);
+
+struct vdm_operation_future pmem2_memcpy_async(struct pmem2_map *map,
+	void *pmemdest, const void *src, size_t len, unsigned flags);
+#endif
+
 /* error handling */
 
 #ifndef _WIN32
diff --git a/src/libpmem/Makefile b/src/libpmem/Makefile
index 534bdefbc81764f3b74cc313ced7a08558b4205e..af674e2422dc519d19b1a7cd139b9c91d090cf18 100644
--- a/src/libpmem/Makefile
+++ b/src/libpmem/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 
 #
 # src/libpmem/Makefile -- Makefile for libpmem
@@ -68,5 +68,5 @@ include ../Makefile.inc
 
 include $(PMEM2)/$(ARCH)/flags.inc
 
-CFLAGS += -I.
+CFLAGS += -I. $(MINIASYNC_CFLAGS)
 LIBS += -pthread
diff --git a/src/libpmem/libpmem.vcxproj b/src/libpmem/libpmem.vcxproj
index 7df5ebd890f6d269e92aa6989a8e84ed2c1b3af9..f6da94913240cf4553416ecbc2f46b41e85e0ef7 100644
--- a/src/libpmem/libpmem.vcxproj
+++ b/src/libpmem/libpmem.vcxproj
@@ -141,10 +141,10 @@
     <Import Project="..\windows\libs_release.props" />
   </ImportGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\src\libpmem2\x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\src\libpmem2\x86_64\;$(solutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\src\libpmem2\x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\src\libpmem2\x86_64\;$(solutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
diff --git a/src/libpmem2/Makefile b/src/libpmem2/Makefile
index cd7e50509ff00ea9b7ec8b523927f6da90271a17..f172b9eff0c7fd3c84ddb48be5aa80c727ad4e31 100644
--- a/src/libpmem2/Makefile
+++ b/src/libpmem2/Makefile
@@ -19,6 +19,7 @@ SOURCE =\
 	errormsg.c\
 	map.c\
 	map_posix.c\
+	mover.c\
 	mcsafe_ops_posix.c\
 	memops_generic.c\
 	persist.c\
@@ -65,5 +66,5 @@ include ../Makefile.inc
 
 include $(PMEM2)/$(ARCH)/flags.inc
 
-CFLAGS += -I. $(LIBNDCTL_CFLAGS)
+CFLAGS += -I. $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 LIBS += -pthread $(LIBNDCTL_LIBS)
diff --git a/src/libpmem2/config.c b/src/libpmem2/config.c
index 8f2cdd5e3d175ac406920fe7e79db73becc02055..35a196d362efb77d243481d4210e8368579d8cf5 100644
--- a/src/libpmem2/config.c
+++ b/src/libpmem2/config.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: BSD-3-Clause
-/* Copyright 2019-2021, Intel Corporation */
+/* Copyright 2019-2022, Intel Corporation */
 
 /*
  * config.c -- pmem2_config implementation
@@ -9,6 +9,7 @@
 #include "alloc.h"
 #include "config.h"
 #include "libpmem2.h"
+#include "libminiasync/vdm.h"
 #include "out.h"
 #include "pmem2.h"
 #include "pmem2_utils.h"
@@ -26,6 +27,7 @@ pmem2_config_init(struct pmem2_config *cfg)
 	cfg->protection_flag = PMEM2_PROT_READ | PMEM2_PROT_WRITE;
 	cfg->reserv = NULL;
 	cfg->reserv_offset = 0;
+	cfg->vdm = NULL;
 }
 
 /*
@@ -213,3 +215,15 @@ pmem2_config_set_protection(struct pmem2_config *cfg,
 	cfg->protection_flag = prot;
 	return 0;
 }
+
+/*
+ * pmem2_config_set_vdm -- set virtual data mover in the config struct
+ */
+int
+pmem2_config_set_vdm(struct pmem2_config *cfg, struct vdm *vdm)
+{
+	PMEM2_ERR_CLR();
+	cfg->vdm = vdm;
+
+	return 0;
+}
diff --git a/src/libpmem2/config.h b/src/libpmem2/config.h
index beb693c436de393c1e68fbcf55795b399831dd76..3e5108657d4b269ce0b8419b8e6e79875b42be13 100644
--- a/src/libpmem2/config.h
+++ b/src/libpmem2/config.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause */
-/* Copyright 2019-2020, Intel Corporation */
+/* Copyright 2019-2022, Intel Corporation */
 
 /*
  * config.h -- internal definitions for pmem2_config
@@ -24,6 +24,7 @@ struct pmem2_config {
 	unsigned protection_flag;
 	struct pmem2_vm_reservation *reserv;
 	size_t reserv_offset;
+	struct vdm *vdm;
 };
 
 void pmem2_config_init(struct pmem2_config *cfg);
diff --git a/src/libpmem2/libpmem2.def b/src/libpmem2/libpmem2.def
index b932078bb8134ce788cf45bb8f6268ba795f4376..47692d2bfbcc43bbcbc69fef299fa5f08d11fd9a 100644
--- a/src/libpmem2/libpmem2.def
+++ b/src/libpmem2/libpmem2.def
@@ -19,6 +19,7 @@ EXPORTS
 	pmem2_config_set_protection
 	pmem2_config_set_required_store_granularity
 	pmem2_config_set_sharing
+	pmem2_config_set_vdm
 	pmem2_config_set_vm_reservation
 	pmem2_deep_flush
 	pmem2_errormsgU
@@ -33,8 +34,9 @@ EXPORTS
 	pmem2_map_get_address
 	pmem2_map_get_size
 	pmem2_map_get_store_granularity
-	pmem2_map_new
 	pmem2_map_from_existing
+	pmem2_map_new
+	pmem2_memcpy_async
 	pmem2_perrorU
 	pmem2_perrorW
 	pmem2_source_alignment
diff --git a/src/libpmem2/libpmem2.link.in b/src/libpmem2/libpmem2.link.in
index 3017d9b6dbfbfcc5f4b7ae87976a53c21967d7bd..1e59becc84223b50920a19ec83baec67969b19c1 100644
--- a/src/libpmem2/libpmem2.link.in
+++ b/src/libpmem2/libpmem2.link.in
@@ -17,6 +17,7 @@ LIBPMEM2_1.0 {
 		pmem2_config_set_protection;
 		pmem2_config_set_required_store_granularity;
 		pmem2_config_set_sharing;
+		pmem2_config_set_vdm;
 		pmem2_config_set_vm_reservation;
 		pmem2_deep_flush;
 		pmem2_errormsg;
@@ -32,6 +33,7 @@ LIBPMEM2_1.0 {
 		pmem2_map_get_store_granularity;
 		pmem2_map_new;
 		pmem2_map_from_existing;
+		pmem2_memcpy_async;
 		pmem2_perror;
 		pmem2_source_alignment;
 		pmem2_source_delete;
diff --git a/src/libpmem2/libpmem2.vcxproj b/src/libpmem2/libpmem2.vcxproj
index d680afac91d6e347966e348e86bd0583dbe1bce4..12fa556df42d25ca970ad0c80a0ade62eae45c24 100644
--- a/src/libpmem2/libpmem2.vcxproj
+++ b/src/libpmem2/libpmem2.vcxproj
@@ -12,6 +12,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\core\alloc.c" />
+    <ClCompile Include="..\core\membuf.c" />
     <ClCompile Include="..\core\os_thread_windows.c" />
     <ClCompile Include="..\core\os_windows.c" />
     <ClCompile Include="..\core\out.c" />
@@ -31,6 +32,7 @@
     <ClCompile Include="map_windows.c" />
     <ClCompile Include="mcsafe_ops_windows.c" />
     <ClCompile Include="memops_generic.c" />
+    <ClCompile Include="mover.c" />
     <ClCompile Include="numa_none.c" />
     <ClCompile Include="persist.c" />
     <ClCompile Include="persist_windows.c" />
@@ -72,6 +74,7 @@
     <ClInclude Include="deep_flush.h" />
     <ClInclude Include="config.h" />
     <ClInclude Include="map.h" />
+    <ClInclude Include="mover.h" />
     <ClInclude Include="persist.h" />
     <ClInclude Include="pmem2.h" />
     <ClInclude Include="pmem2_arch.h" />
@@ -135,10 +138,10 @@
     <Import Project="..\windows\libs_release.props" />
   </ImportGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(solutionDir)deps\miniasync\src\include;x86_64\</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(solutionDir)deps\miniasync\src\include;x86_64\</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
diff --git a/src/libpmem2/libpmem2.vcxproj.filters b/src/libpmem2/libpmem2.vcxproj.filters
index 0358a1f917905f4fa73327695f7f4d80e9043cd4..d8f7c1c76bf038eab963497a59f02203cafb7cc1 100644
--- a/src/libpmem2/libpmem2.vcxproj.filters
+++ b/src/libpmem2/libpmem2.vcxproj.filters
@@ -141,6 +141,12 @@
     <ClCompile Include="mcsafe_ops_windows.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\core\membuf.c">
+      <Filter>Source Files\common</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\core\os_thread.h">
@@ -215,6 +221,15 @@
     <ClInclude Include="vm_reservation.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="x86_64\memset\memset_movdir64b.h">
+      <Filter>Header Files\x86_64</Filter>
+    </ClInclude>
+    <ClInclude Include="x86_64\memcpy\memcpy_movdir64b.h">
+      <Filter>Header Files\x86_64</Filter>
+    </ClInclude>
+    <ClInclude Include="mover.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="libpmem2.def">
diff --git a/src/libpmem2/map.c b/src/libpmem2/map.c
index e617093fb3247b264e07d573da0ba0230d132d3a..5ec0b84ea700d34d29d7bdd3b3e8405c326eadd3 100644
--- a/src/libpmem2/map.c
+++ b/src/libpmem2/map.c
@@ -10,13 +10,14 @@
 #include "alloc.h"
 #include "config.h"
 #include "map.h"
-#include "ravl_interval.h"
+#include "mover.h"
 #include "os.h"
 #include "os_thread.h"
 #include "persist.h"
 #include "pmem2.h"
 #include "pmem2_utils.h"
 #include "ravl.h"
+#include "ravl_interval.h"
 #include "sys_util.h"
 #include "valgrind_internal.h"
 
@@ -269,20 +270,26 @@ pmem2_map_from_existing(struct pmem2_map **map_ptr,
 	pmem2_set_mem_fns(map);
 	map->source = *src;
 
+	/* XXX: there is no way to set custom vdm in this function */
+	ret = mover_new(map, &map->vdm);
+	if (ret) {
+		goto err_map;
+	}
+	map->custom_vdm = false;
+
 #ifndef _WIN32
 	/* fd should not be used after map */
 	map->source.value.fd = INVALID_FD;
 #endif
 	ret = pmem2_register_mapping(map);
 	if (ret) {
-		Free(map);
 		if (ret == -EEXIST) {
 			ERR(
 				"Provided mapping(addr %p len %zu) is already registered by libpmem2",
 				addr, len);
-			return PMEM2_E_MAP_EXISTS;
+			ret = PMEM2_E_MAP_EXISTS;
 		}
-		return ret;
+		goto err_vdm;
 	}
 #ifndef _WIN32
 	if (src->type == PMEM2_SOURCE_FD) {
@@ -292,4 +299,10 @@ pmem2_map_from_existing(struct pmem2_map **map_ptr,
 #endif
 	*map_ptr = map;
 	return 0;
+err_vdm:
+	mover_delete(map->vdm);
+err_map:
+	Free(map);
+
+	return ret;
 }
diff --git a/src/libpmem2/map.h b/src/libpmem2/map.h
index 9cc172905208627b1be87d37ad7a8f147c849db0..7f2ff847ab95dcdbcdd825b502d31a78cffe29e5 100644
--- a/src/libpmem2/map.h
+++ b/src/libpmem2/map.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause */
-/* Copyright 2019-2020, Intel Corporation */
+/* Copyright 2019-2022, Intel Corporation */
 
 /*
  * map.h -- internal definitions for libpmem2
@@ -12,6 +12,7 @@
 #include "libpmem2.h"
 #include "os.h"
 #include "source.h"
+#include "libminiasync/vdm.h"
 #include "vm_reservation.h"
 
 #ifdef _WIN32
@@ -43,6 +44,9 @@ struct pmem2_map {
 
 	struct pmem2_source source;
 	struct pmem2_vm_reservation *reserv;
+
+	struct vdm *vdm;
+	bool custom_vdm;
 };
 
 enum pmem2_granularity get_min_granularity(bool eADR, bool is_pmem,
diff --git a/src/libpmem2/map_posix.c b/src/libpmem2/map_posix.c
index f6113393815e1bc765c1b7f5a8b06ca4a48498e2..b487655bab7c6e6dedc7840bc04acc95e6c96302 100644
--- a/src/libpmem2/map_posix.c
+++ b/src/libpmem2/map_posix.c
@@ -17,6 +17,7 @@
 #include "config.h"
 #include "file.h"
 #include "map.h"
+#include "mover.h"
 #include "out.h"
 #include "persist.h"
 #include "pmem2_utils.h"
@@ -510,9 +511,25 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg,
 	map->source = *src;
 	map->source.value.fd = INVALID_FD; /* fd should not be used after map */
 
+	map->custom_vdm = true;
+	struct vdm *vdm = cfg->vdm;
+
+	if (vdm == NULL) {
+		/*
+		 * user did not provided custom vdm,
+		 * so we have to use the fallback one.
+		 */
+		ret = mover_new(map, &vdm);
+		if (ret)
+			goto err_free_map_struct;
+		map->custom_vdm = false;
+	}
+
+	map->vdm = vdm;
 	ret = pmem2_register_mapping(map);
+
 	if (ret) {
-		goto err_free_map_struct;
+		goto err_free_vdm;
 	}
 
 	if (rsv) {
@@ -533,6 +550,9 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg,
 
 err_unregister_map:
 	pmem2_unregister_mapping(map);
+err_free_vdm:
+	if (!map->custom_vdm)
+		mover_delete(map->vdm);
 err_free_map_struct:
 	Free(map);
 err_undo_mapping:
@@ -598,8 +618,10 @@ pmem2_map_delete(struct pmem2_map **map_ptr)
 			if (ret)
 				goto err_register_map;
 		}
-	}
 
+		if (!map->custom_vdm)
+			mover_delete(map->vdm);
+	}
 	Free(map);
 	*map_ptr = NULL;
 
diff --git a/src/libpmem2/map_windows.c b/src/libpmem2/map_windows.c
index b5359d3023649904d91f4ac9646c933a26bad726..1473d95d64a2156dd880b84791d6fd4d4e6ade8e 100644
--- a/src/libpmem2/map_windows.c
+++ b/src/libpmem2/map_windows.c
@@ -13,6 +13,7 @@
 #include "auto_flush.h"
 #include "config.h"
 #include "map.h"
+#include "mover.h"
 #include "os_thread.h"
 #include "out.h"
 #include "persist.h"
@@ -381,6 +382,22 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg,
 	if (!map)
 		goto err_undo_mapping;
 
+	map->custom_vdm = true;
+	struct vdm *vdm = cfg->vdm;
+
+	if (vdm == NULL) {
+		/*
+		 * user did not provided custom vdm,
+		 * so we have to use the fallback one.
+		 */
+		ret = mover_new(map, &vdm);
+		if (ret)
+			goto err_free_map_struct;
+		map->custom_vdm = false;
+	}
+
+	map->vdm = vdm;
+
 	map->addr = base;
 	/*
 	 * XXX probably in some cases the reserved length > the content length.
@@ -396,7 +413,7 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg,
 
 	ret = pmem2_register_mapping(map);
 	if (ret) {
-		goto err_free_map_struct;
+		goto err_free_vdm;
 	}
 
 	if (rsv) {
@@ -412,6 +429,9 @@ pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg,
 
 err_unregister_map:
 	pmem2_unregister_mapping(map);
+err_free_vdm:
+	if (!map->custom_vdm)
+		mover_delete(map->vdm);
 err_free_map_struct:
 	free(map);
 err_undo_mapping:
diff --git a/src/libpmem2/mover.c b/src/libpmem2/mover.c
new file mode 100644
index 0000000000000000000000000000000000000000..f57549d2c88ae85726ccc6da99bebe4423b9daf4
--- /dev/null
+++ b/src/libpmem2/mover.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright 2021-2022, Intel Corporation */
+
+/*
+ * mover.c -- default pmem2 data mover
+ */
+
+#include "libpmem2.h"
+#include "mover.h"
+#include "map.h"
+#include "membuf.h"
+#include "out.h"
+#include "pmem2_utils.h"
+#include "util.h"
+#include <inttypes.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+struct data_mover {
+	struct vdm base; /* must be first */
+	struct pmem2_map *map;
+	struct membuf *membuf;
+};
+
+struct data_mover_op {
+	struct vdm_operation op;
+	int complete;
+};
+
+/*
+ * sync_operation_check -- always returns COMPLETE because sync mover operations
+ * are complete immediately after starting.
+ */
+static enum future_state
+sync_operation_check(void *data, const struct vdm_operation *operation)
+{
+	LOG(3, "data %p", data);
+	SUPPRESS_UNUSED(operation);
+
+	struct data_mover_op *sync_op = data;
+
+	int complete;
+	util_atomic_load_explicit32(&sync_op->complete, &complete,
+		memory_order_acquire);
+
+	return complete ? FUTURE_STATE_COMPLETE : FUTURE_STATE_IDLE;
+}
+
+/*
+ * sync_operation_new -- creates a new sync operation
+ */
+static void *
+sync_operation_new(struct vdm *vdm, const enum vdm_operation_type type)
+{
+	LOG(3, "vdm %p", vdm);
+
+	SUPPRESS_UNUSED(type);
+
+	struct data_mover *vdm_sync = (struct data_mover *)vdm;
+	struct data_mover_op *sync_op = membuf_alloc(vdm_sync->membuf,
+		sizeof(struct data_mover_op));
+
+	if (sync_op == NULL)
+		return NULL;
+
+	sync_op->complete = 0;
+
+	return sync_op;
+}
+
+/*
+ * sync_operation_delete -- deletes sync operation
+ */
+static void
+sync_operation_delete(void *data, const struct vdm_operation *operation,
+	struct vdm_operation_output *output)
+{
+	output->result = VDM_SUCCESS;
+
+	switch (operation->type) {
+	case VDM_OPERATION_MEMCPY:
+		output->type = VDM_OPERATION_MEMCPY;
+		output->output.memcpy.dest =
+			operation->data.memcpy.dest;
+		break;
+	case VDM_OPERATION_MEMMOVE:
+		output->type = VDM_OPERATION_MEMMOVE;
+		output->output.memmove.dest =
+			operation->data.memcpy.dest;
+		break;
+	default:
+		FATAL("unsupported operation type");
+
+	}
+	membuf_free(data);
+}
+
+/*
+ * sync_operation_start -- start (and perform) a synchronous memory operation
+ */
+static int
+sync_operation_start(void *data, const struct vdm_operation *operation,
+	struct future_notifier *n)
+{
+	LOG(3, "data %p op %p, notifier %p", data, operation, n);
+	struct data_mover_op *sync_data =
+		(struct data_mover_op *)data;
+	struct data_mover *mover = membuf_ptr_user_data(data);
+	if (n)
+		n->notifier_used = FUTURE_NOTIFIER_NONE;
+
+	switch (operation->type) {
+		case VDM_OPERATION_MEMCPY: {
+			pmem2_memcpy_fn memcpy_fn;
+			memcpy_fn = pmem2_get_memcpy_fn(mover->map);
+
+			memcpy_fn(operation->data.memcpy.dest,
+				operation->data.memcpy.src,
+				operation->data.memcpy.n,
+				PMEM2_F_MEM_NONTEMPORAL);
+			break;
+		}
+		case VDM_OPERATION_MEMMOVE: {
+			pmem2_memmove_fn memmove_fn;
+			memmove_fn = pmem2_get_memmove_fn(mover->map);
+
+			memmove_fn(operation->data.memcpy.dest,
+				operation->data.memcpy.src,
+				operation->data.memcpy.n,
+				PMEM2_F_MEM_NONTEMPORAL);
+			break;
+		}
+		default:
+			FATAL("unsupported operation type");
+	}
+	util_atomic_store_explicit32(&sync_data->complete,
+		1, memory_order_release);
+
+	return 0;
+}
+
+static struct vdm data_mover_vdm = {
+	.op_new = sync_operation_new,
+	.op_delete = sync_operation_delete,
+	.op_check = sync_operation_check,
+	.op_start = sync_operation_start,
+};
+
+/*
+ * mover_new -- creates a new synchronous data mover
+ */
+int
+mover_new(struct pmem2_map *map, struct vdm **vdm)
+{
+	LOG(3, "map %p, vdm %p", map, vdm);
+	int ret;
+	struct data_mover *dms = pmem2_malloc(sizeof(*dms), &ret);
+	if (dms == NULL)
+		return ret;
+
+	dms->base = data_mover_vdm;
+	dms->map = map;
+	*vdm = (struct vdm *)dms;
+
+	dms->membuf = membuf_new(dms);
+	if (dms->membuf == NULL) {
+		ret = PMEM2_E_ERRNO;
+		goto membuf_failed;
+	}
+
+	return 0;
+
+membuf_failed:
+	free(dms);
+	return ret;
+}
+
+/*
+ * mover_delete -- deletes a synchronous data mover
+ */
+void
+mover_delete(struct vdm *dms)
+{
+	membuf_delete(((struct data_mover *)dms)->membuf);
+	free((struct data_mover *)dms);
+}
+
+/*
+ * pmem2_memcpy_async -- returns a memcpy future
+ */
+struct vdm_operation_future
+pmem2_memcpy_async(struct pmem2_map *map,
+	void *pmemdest,	const void *src, size_t len, unsigned flags)
+{
+	LOG(3, "map %p, pmemdest %p, src %p, len %" PRIu64 ", flags %u",
+		map, pmemdest, src, len, flags);
+	SUPPRESS_UNUSED(flags);
+	return vdm_memcpy(map->vdm, pmemdest, (void *)src, len, 0);
+}
diff --git a/src/libpmem2/mover.h b/src/libpmem2/mover.h
new file mode 100644
index 0000000000000000000000000000000000000000..294f6881e5cd96c04e35b6a4ecb5df5b4a5318d1
--- /dev/null
+++ b/src/libpmem2/mover.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright 2022, Intel Corporation */
+
+/*
+ * mover.h -- implementation of default datamover
+ */
+#ifndef PMEM2_MOVER_H
+#define PMEM2_MOVER_H
+
+#include "libpmem2.h"
+#include "libminiasync/vdm.h"
+
+int mover_new(struct pmem2_map *map, struct vdm **vdm);
+void mover_delete(struct vdm *vdm);
+
+#endif /* PMEM2_MOVER_H */
diff --git a/src/libpmemblk/Makefile b/src/libpmemblk/Makefile
index 8f5d99ecd403cbb45eebef31614ae7377c14e015..1181828d992da1cda77c28c3f4b226dc7bf69038 100644
--- a/src/libpmemblk/Makefile
+++ b/src/libpmemblk/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 
 #
 # src/libpmemblk/Makefile -- Makefile for libpmemblk
@@ -18,5 +18,5 @@ SOURCE +=\
 
 include ../Makefile.inc
 
-CFLAGS += $(LIBNDCTL_CFLAGS)
+CFLAGS += $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 LIBS += -pthread -lpmem $(LIBNDCTL_LIBS)
diff --git a/src/libpmemlog/Makefile b/src/libpmemlog/Makefile
index 25fa84d1fe8c4736e969cf03fc0b2c2f42fc198b..dc345d88c3f7358253b879b3cf75a6e8e515425f 100644
--- a/src/libpmemlog/Makefile
+++ b/src/libpmemlog/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 
 #
 # src/libpmemlog/Makefile -- Makefile for libpmemlog
@@ -18,6 +18,6 @@ SOURCE +=\
 
 include ../Makefile.inc
 
-CFLAGS += $(LIBNDCTL_CFLAGS)
+CFLAGS += $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 
 LIBS += -pthread -lpmem $(LIBNDCTL_LIBS)
diff --git a/src/libpmemobj/Makefile b/src/libpmemobj/Makefile
index 6ad3d73e4899861ec1791cfd900a2efc7fa93e10..808904f0da3bec22169947945320dc8a3476e331 100644
--- a/src/libpmemobj/Makefile
+++ b/src/libpmemobj/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 
 #
 # src/libpmemobj/Makefile -- Makefile for libpmemobj
@@ -36,6 +36,6 @@ SOURCE +=\
 
 include ../Makefile.inc
 
-CFLAGS += -DUSE_LIBDL -D_PMEMOBJ_INTRNL $(LIBNDCTL_CFLAGS)
+CFLAGS += -DUSE_LIBDL -D_PMEMOBJ_INTRNL $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 
 LIBS += -pthread -lpmem $(LIBDL) $(LIBNDCTL_LIBS)
diff --git a/src/libpmempool/Makefile b/src/libpmempool/Makefile
index 0ae33de4c4d6330520320de1b2f297d3b722ba4f..e34e8bab54e5ea827c84344df0ca2aab07b81d10 100644
--- a/src/libpmempool/Makefile
+++ b/src/libpmempool/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2016-2020, Intel Corporation
+# Copyright 2016-2022, Intel Corporation
 
 #
 # src/libpmempool/Makefile -- Makefile for libpmempool
@@ -51,7 +51,7 @@ LIBPMEMBLK_PRIV_FUNCS=btt_info_set btt_arena_datasize btt_flog_size\
 
 include ../Makefile.inc
 
-CFLAGS += $(LIBNDCTL_CFLAGS)
+CFLAGS += $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS) -DPMEM2_USE_MINIASYNC=1
 LIBS += -pthread -lpmem $(LIBDL) $(LIBNDCTL_LIBS)
 CFLAGS += -DUSE_LIBDL
 CFLAGS += -DUSE_RPMEM
diff --git a/src/libpmemset/libpmemset.vcxproj b/src/libpmemset/libpmemset.vcxproj
index 7cd0b0496dbdceb8ac700b0106d9c8b3fb25711c..d47bbc81b6f7b7fa85333379743b526f0ec8436b 100644
--- a/src/libpmemset/libpmemset.vcxproj
+++ b/src/libpmemset/libpmemset.vcxproj
@@ -86,10 +86,10 @@
     <Import Project="..\windows\libs_release.props" />
   </ImportGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\;$(solutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\</IncludePath>
+    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);x86_64\;$(solutionDir)deps\miniasync\src\include</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
diff --git a/src/test/Makefile b/src/test/Makefile
index d2645bf86c59fdb21225e9d62c54e93f99c4fe2d..31de91fd9147cb7b48954896d226210f5ce58c6a 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -225,7 +225,7 @@ PMEM2_TESTS = \
 	pmem2_vm_reservation\
 	pmem2_usc
 
-ifeq ($(OS_DIMM),ndctl)
+ifeq ($(OS_DIMM),ndctf)
 PMEM2_TESTS += \
 	pmem2_badblock_mocks\
 	pmem2_source_numa
@@ -234,6 +234,13 @@ $(info NOTE: Skipping tests because libndctl is disabled (see NDCTL_ENABLE)\
 		Skipped tests: pmem2_badblock_mocks pmem2_source_numa)
 endif
 
+ifeq ($(OS_KERNEL_NAME),Linux)
+PMEM2_TESTS += pmem2_mover
+else
+$(info NOTE: Skipping tests because miniasync is not supported on this os.\
+		Skipped tests: pmem2_mover)
+endif
+
 PMEMPOOL_TESTS = \
 	pmempool_check\
 	pmempool_create\
diff --git a/src/test/Makefile.inc b/src/test/Makefile.inc
index 6efea208f0f20b2ffa5b91037fe2f09488a3478e..90ffd5c3e2ebbfb1a6e34d8ef5e7c3f10b5ce906 100644
--- a/src/test/Makefile.inc
+++ b/src/test/Makefile.inc
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2021, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 #
 
 #
@@ -210,6 +210,7 @@ OBJS +=\
 	$(TOP)/src/debug/libpmem2/config.o\
 	$(TOP)/src/debug/libpmem2/errormsg.o\
 	$(TOP)/src/debug/libpmem2/libpmem2.o\
+	$(TOP)/src/debug/libpmem2/mover.o\
 	$(TOP)/src/debug/libpmem2/map.o\
 	$(TOP)/src/debug/libpmem2/mcsafe_ops_posix.o\
 	$(TOP)/src/debug/libpmem2/map_posix.o\
@@ -255,6 +256,8 @@ OBJS += $(addprefix $(TOP)/src/nondebug/libpmem2/, ${OBJS_MEM})
 INCS += -I$(TOP)/src/common
 INCS += -I$(TOP)/src/libpmem2
 INCS += -I$(TOP)/src/libpmem2/$(ARCH)
+INCS += $(MINIASYNC_CFLAGS)
+
 endif
 
 ifeq ($(LIBPMEM2), internal-nondebug)
@@ -268,6 +271,7 @@ OBJS +=\
 	$(TOP)/src/nondebug/libpmem2/source_posix.o\
 	$(TOP)/src/nondebug/libpmem2/errormsg.o\
 	$(TOP)/src/nondebug/libpmem2/map.o\
+	$(TOP)/src/nondebug/libpmem2/mover.o\
 	$(TOP)/src/nondebug/libpmem2/mcsafe_ops_posix.o\
 	$(TOP)/src/nondebug/libpmem2/map_posix.o\
 	$(TOP)/src/nondebug/libpmem2/memops_generic.o\
@@ -310,12 +314,14 @@ OBJS += $(addprefix $(TOP)/src/debug/libpmem2/, ${OBJS_MEM})
 INCS += -I$(TOP)/src/common
 INCS += -I$(TOP)/src/libpmem2
 INCS += -I$(TOP)/src/libpmem2/$(ARCH)
+INCS += $(MINIASYNC_CFLAGS)
 endif
 
 ifeq ($(LIBPMEM2),y)
 DYNAMIC_LIBS += -lpmem2
 STATIC_DEBUG_LIBS += $(LIBS_DIR)/debug/libpmem2.a
 STATIC_NONDEBUG_LIBS += $(LIBS_DIR)/nondebug/libpmem2.a
+INCS += $(MINIASYNC_CFLAGS)
 endif
 
 ifeq ($(LIBPMEMCOMMON), y)
@@ -445,12 +451,14 @@ ifeq ($(LIBPMEMCORE), y)
 LIBPMEM=y
 OBJS += $(LIBS_DIR)/debug/libpmemcore.a
 INCS += -I$(TOP)/src/core
+INCS += $(MINIASYNC_CFLAGS)
 endif
 
 ifeq ($(LIBPMEMCORE), internal-nondebug)
 OBJS +=\
 	$(TOP)/src/nondebug/core/alloc.o\
 	$(TOP)/src/nondebug/core/fs_posix.o\
+	$(TOP)/src/nondebug/core/membuf.o\
 	$(TOP)/src/nondebug/core/os_posix.o\
 	$(TOP)/src/nondebug/core/os_thread_posix.o\
 	$(TOP)/src/nondebug/core/out.o\
@@ -460,12 +468,14 @@ OBJS +=\
 	$(TOP)/src/nondebug/core/util_posix.o
 
 INCS += -I$(TOP)/src/core
+INCS += $(MINIASYNC_CFLAGS)
 endif
 
 ifeq ($(LIBPMEMCORE), internal-debug)
 OBJS +=\
 	$(TOP)/src/debug/core/alloc.o\
 	$(TOP)/src/debug/core/fs_posix.o\
+	$(TOP)/src/debug/core/membuf.o\
 	$(TOP)/src/debug/core/os_posix.o\
 	$(TOP)/src/debug/core/os_thread_posix.o\
 	$(TOP)/src/debug/core/out.o\
@@ -475,6 +485,7 @@ OBJS +=\
 	$(TOP)/src/debug/core/util_posix.o
 
 INCS += -I$(TOP)/src/core
+INCS += $(MINIASYNC_CFLAGS)
 endif
 
 ifeq ($(LIBPMEM),y)
@@ -502,6 +513,12 @@ CFLAGS += $(LIBNDCTL_CFLAGS)
 LIBS += $(LIBNDCTL_LIBS)
 endif
 
+ifeq ($(LINMINIASYNC),y)
+LIBS += -lminiasync
+# XXX: remover when we will swich to installed libminiasync
+LIBS += -L$(TOP)/src/deps/miniasync/build/out
+endif
+
 #
 # This is a helper function to be combined with usage of macros available
 # in the unittest framework. It scans the code for functions that should be
diff --git a/src/test/pmem2_granularity/pmem2_granularity.vcxproj b/src/test/pmem2_granularity/pmem2_granularity.vcxproj
index a908e8f4069060176d6bcbbe562378fca211ea43..27a3974550f065e78f18a65664feb2ec4b936007 100644
--- a/src/test/pmem2_granularity/pmem2_granularity.vcxproj
+++ b/src/test/pmem2_granularity/pmem2_granularity.vcxproj
@@ -76,6 +76,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\libpmem2\auto_flush_windows.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
@@ -84,6 +85,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\core\ravl_interval.c" />
@@ -103,6 +105,7 @@
     <ClCompile Include="pmem2_granularity.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\map.h" />
     <ClInclude Include="..\..\core\ravl_interval.h" />
diff --git a/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters b/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters
index 9824b9990135dee3fc745a6af142042cd255b4a9..5ded3e4fe7cedf1ddeeb4a8c70e0eb02b13a7591 100644
--- a/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters
+++ b/src/test/pmem2_granularity/pmem2_granularity.vcxproj.filters
@@ -74,6 +74,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\unittest\ut_pmem2_utils.h">
@@ -100,6 +106,9 @@
     <ClInclude Include="..\..\core\ravl_interval.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\membuf.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="TESTS.py">
diff --git a/src/test/pmem2_map/pmem2_map.c b/src/test/pmem2_map/pmem2_map.c
index 95eb79b98c3e171175a99ffa67686622c8b05786..6a2803c12f9bbc3d1ecebeb5a8e571ab6102b8f4 100644
--- a/src/test/pmem2_map/pmem2_map.c
+++ b/src/test/pmem2_map/pmem2_map.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: BSD-3-Clause
-/* Copyright 2019-2021, Intel Corporation */
+/* Copyright 2019-2022, Intel Corporation */
 
 /*
  * pmem2_map.c -- pmem2_map unittests
@@ -11,6 +11,7 @@
 #include "pmem2_utils.h"
 #include "source.h"
 #include "map.h"
+#include "mover.h"
 #include "out.h"
 #include "pmem2.h"
 #include "unittest.h"
@@ -50,6 +51,12 @@ prepare_map(struct pmem2_map **map_ptr,
 	UT_ASSERTne(mh, NULL);
 	UT_ASSERTne(GetLastError(), ERROR_ALREADY_EXISTS);
 
+	struct vdm *vdm;
+	mover_new(map, &vdm);
+	UT_ASSERTne(map, NULL);
+	map->custom_vdm = true;
+	map->vdm = vdm;
+
 	map->addr = MapViewOfFileEx(mh,
 		FILE_MAP_ALL_ACCESS,
 		HIDWORD(cfg->offset),
@@ -91,6 +98,12 @@ prepare_map(struct pmem2_map **map_ptr,
 	struct pmem2_map *map = malloc(sizeof(*map));
 	UT_ASSERTne(map, NULL);
 
+	struct vdm *vdm;
+	mover_new(map, &vdm);
+	UT_ASSERTne(map, NULL);
+	map->custom_vdm = true;
+	map->vdm = vdm;
+
 	UT_ASSERTeq(src->type, PMEM2_SOURCE_FD);
 	map->addr = mmap(NULL, cfg->length, proto, flags,
 		src->value.fd, offset);
diff --git a/src/test/pmem2_map/pmem2_map.vcxproj b/src/test/pmem2_map/pmem2_map.vcxproj
index d20080c24979d67b2fde576c05dea6f5eb045c63..ee41737bee068f73d896e7e726201fcf7dc959bc 100644
--- a/src/test/pmem2_map/pmem2_map.vcxproj
+++ b/src/test/pmem2_map/pmem2_map.vcxproj
@@ -77,6 +77,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\libpmem2\config.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
@@ -85,6 +86,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\pmem2_utils.c" />
@@ -99,6 +101,7 @@
     <ClCompile Include="pmem2_map.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\map.h" />
     <ClInclude Include="..\..\libpmem2\pmem2.h" />
diff --git a/src/test/pmem2_map/pmem2_map.vcxproj.filters b/src/test/pmem2_map/pmem2_map.vcxproj.filters
index 4ada61888341d78ca459791847b18cbe0d6d6886..1bf51fef5768bc51c0541c1e9901f949cc989264 100644
--- a/src/test/pmem2_map/pmem2_map.vcxproj.filters
+++ b/src/test/pmem2_map/pmem2_map.vcxproj.filters
@@ -74,6 +74,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\libpmem2\config.h">
@@ -97,6 +103,9 @@
     <ClInclude Include="..\..\core\ravl_interval.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\membuf.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="TESTS.py">
diff --git a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj
index 6fe48e661f0c0080d8913de5a283b22ddf2ba084..5f5c042d94d851239ee4ae04b490397605f98395 100644
--- a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj
+++ b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj
@@ -77,6 +77,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\libpmem2\config.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
@@ -85,6 +86,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\pmem2_utils.c" />
@@ -99,6 +101,8 @@
     <ClCompile Include="pmem2_map_from_existing.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
+    <ClInclude Include="..\..\core\os_thread.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\map.h" />
     <ClInclude Include="..\..\libpmem2\pmem2.h" />
diff --git a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters
index 6e69d84763302ebf7116011060fa94d04d7665e3..35c07a45708b7eb2d4f12957208b1de84a78f10d 100644
--- a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters
+++ b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters
@@ -74,6 +74,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\libpmem2\config.h">
@@ -97,6 +103,12 @@
     <ClInclude Include="..\..\core\ravl_interval.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\os_thread.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\core\membuf.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 ac8097fec77bcde90501175a8f5dd9546635b7b5..7c9a14a9a7b09c6de90aa0708f16bfd168b54d27 100644
--- a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj
+++ b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj
@@ -77,6 +77,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\libpmem2\config.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
@@ -85,6 +86,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\pmem2_utils.c" />
@@ -100,6 +102,7 @@
     <ClCompile Include="pmem2_map_prot.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\map.h" />
     <ClInclude Include="..\..\libpmem2\pmem2.h" />
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 7f7ebf89f68a88f4086101b55bb01f4dae75a9c7..6ea043e07868bbf941202723e42e1f0dc6749a76 100644
--- a/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters
+++ b/src/test/pmem2_map_prot/pmem2_map_prot.vcxproj.filters
@@ -77,6 +77,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\libpmem2\config.h">
@@ -97,6 +103,9 @@
     <ClInclude Include="..\..\core\ravl_interval.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\membuf.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="TESTS.py">
diff --git a/src/test/pmem2_mover/.gitignore b/src/test/pmem2_mover/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1890223048165b35604fb630798de4f7f1b46a0f
--- /dev/null
+++ b/src/test/pmem2_mover/.gitignore
@@ -0,0 +1 @@
+pmem2_mover
diff --git a/src/test/pmem2_mover/Makefile b/src/test/pmem2_mover/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1aed2bcefff0c0ea33fdc0601797bbd986be409f
--- /dev/null
+++ b/src/test/pmem2_mover/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2022, Intel Corporation
+
+#
+# src/test/pmem2_mover/Makefile -- build pmem2_mover test
+#
+TOP = ../../..
+
+vpath %.c $(TOP)/src/test/unittest
+
+TARGET = pmem2_mover
+OBJS = pmem2_mover.o\
+	ut_pmem2_utils.o\
+	ut_pmem2_config.o\
+	ut_pmem2_source.o\
+	ut_pmem2_setup_integration.o
+
+LIBPMEM2=y
+LINMINIASYNC=y
+include ../Makefile.inc
diff --git a/src/test/pmem2_mover/TESTS.py b/src/test/pmem2_mover/TESTS.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0243780a6779904d0bac1ba549a466f881897bf
--- /dev/null
+++ b/src/test/pmem2_mover/TESTS.py
@@ -0,0 +1,61 @@
+#!../env.py
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2022, Intel Corporation
+#
+
+
+import sys
+
+import testframework as t
+from testframework import granularity as g
+from consts import MINIASYNC_LIBDIR
+
+
+@t.freebsd_exclude
+class PMEM2_MOVER(t.Test):
+    test_type = t.Medium
+
+    def setup(self, ctx):
+        super().setup(ctx)
+        if sys.platform == 'win32':
+            env_dir = 'PATH'
+            path = ctx.env[env_dir]
+            ctx.env[env_dir] = path + ";" + MINIASYNC_LIBDIR
+        else:
+            env_dir = 'LD_LIBRARY_PATH'
+            path = ctx.env[env_dir]
+            ctx.env[env_dir] = path + ":" + MINIASYNC_LIBDIR
+        self.filepath = ctx.create_holey_file(16 * t.MiB, 'testfile')
+
+    def run(self, ctx):
+        ctx.exec('pmem2_mover', self.test_case, self.filepath)
+
+
+@g.require_granularity(g.BYTE, g.CACHELINE)
+class PMEM2_MOVER_MT(PMEM2_MOVER):
+    thread_num = 2
+
+    def run(self, ctx):
+        ctx.exec('pmem2_mover', self.test_case, self.filepath, self.thread_num)
+
+
+class TEST0(PMEM2_MOVER):
+    """verify pmem2 mover functionality"""
+    test_case = "test_mover_basic"
+
+
+class TEST1(PMEM2_MOVER_MT):
+    """verify pmem2 mover multi-threaded functionality"""
+    test_case = "test_mover_multithreaded"
+
+
+class TEST2(PMEM2_MOVER_MT):
+    test_type = t.Long
+    thread_num = 16
+    """verify pmem2 mover multi-threaded functionality (Long)"""
+    test_case = "test_mover_multithreaded"
+
+
+class TEST3(PMEM2_MOVER):
+    """verify pmem2 mover functionality"""
+    test_case = "test_miniasync_mover"
diff --git a/src/test/pmem2_mover/pmem2_mover.c b/src/test/pmem2_mover/pmem2_mover.c
new file mode 100644
index 0000000000000000000000000000000000000000..99db7807b692bee29100acd8fd5240565e52f7d5
--- /dev/null
+++ b/src/test/pmem2_mover/pmem2_mover.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright 2019-2022, Intel Corporation */
+
+/*
+ * pmem2_mover.c -- pmem2 mover tests
+ */
+
+#define PMEM2_USE_MINIASYNC 1
+#include "libpmem2.h"
+#include "unittest.h"
+#include "ut_pmem2.h"
+#include "ut_pmem2_setup_integration.h"
+
+#include <libminiasync.h>
+/*
+ * map_valid -- return valid mapped pmem2_map
+ */
+static struct pmem2_map *
+map_valid(struct pmem2_config *cfg, struct pmem2_source *src)
+{
+	struct pmem2_map *map = NULL;
+	int ret = pmem2_map_new(&map, cfg, src);
+	UT_PMEM2_EXPECT_RETURN(ret, 0);
+	UT_ASSERTne(map, NULL);
+
+	return map;
+}
+
+/*
+ * test_mover_basic -- test basic functionality of pmem2 default mover
+ */
+static int
+test_mover_basic(const struct test_case *tc, int argc, char *argv[])
+{
+	if (argc < 1)
+		UT_FATAL("usage: test_mover_basic <file>");
+
+	char *file = argv[0];
+	int fd = OPEN(file, O_RDWR);
+
+	struct pmem2_source *src;
+	struct pmem2_config *cfg;
+	PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd,
+		PMEM2_GRANULARITY_PAGE);
+
+	struct pmem2_map *map = map_valid(cfg, src);
+	char *data = pmem2_map_get_address(map);
+	pmem2_memset_fn memset_fn = pmem2_get_memset_fn(map);
+	memset_fn(data, 0xBA, 4096, 0);
+	memset_fn(data + 4096, 0xAB, 4096, 0);
+	struct vdm_operation_future cpy =
+		pmem2_memcpy_async(map, data, data + 4096, 4096, 0);
+
+	FUTURE_BUSY_POLL(&cpy);
+
+	if (memcmp(data, data + 4096, 4096))
+		UT_FATAL("data should be equal");
+
+	pmem2_map_delete(&map);
+	pmem2_config_delete(&cfg);
+	pmem2_source_delete(&src);
+	CLOSE(fd);
+	return 1;
+}
+
+#define WORKER_RUNS 20000
+#define TEST_SIZE 4096
+struct thread_arg {
+	struct pmem2_map *map;
+	void *addr;
+	unsigned threads;
+	unsigned thread_id;
+};
+
+/*
+ * thread_worker -- thread worker for test_mover_multithread
+ */
+static void *
+thread_worker(void *arg)
+{
+	struct thread_arg *targ = arg;
+	unsigned *pattern1, *pattern2;
+
+	UT_COMPILE_ERROR_ON(TEST_SIZE % sizeof(*pattern1) != 0);
+	unsigned array_size = TEST_SIZE / sizeof(*pattern1);
+
+	pattern1 = MALLOC(array_size * sizeof(*pattern1));
+	pattern2 = MALLOC(array_size * sizeof(*pattern2));
+
+	for (unsigned j = 0; j < array_size; j++) {
+		pattern1[j] = targ->thread_id + 1 * targ->threads;
+		pattern2[j] = targ->thread_id + 2 * targ->threads;
+	}
+
+	for (int i = 0; i < WORKER_RUNS; i++) {
+		unsigned *pattern = i % 2 ? pattern1 : pattern2;
+		struct vdm_operation_future cpy =
+			pmem2_memcpy_async(targ->map, targ->addr, pattern,
+				TEST_SIZE, 0);
+
+		FUTURE_BUSY_POLL(&cpy);
+
+		if (memcmp(pattern, targ->addr, TEST_SIZE))
+			UT_FATAL("data should be equal");
+	}
+	FREE(pattern1);
+	FREE(pattern2);
+	return NULL;
+}
+
+/*
+ * test_mover_multithreaded -- multi-threaded test for the memcpy
+ */
+static int
+test_mover_multithreaded(const struct test_case *tc, int argc, char *argv[])
+{
+	if (argc < 2)
+		UT_FATAL("usage: test_mover_basic <file> <threads>");
+
+	char *file = argv[0];
+	int fd = OPEN(file, O_RDWR);
+	unsigned long num_threads = STRTOUL(argv[1], NULL, 10);
+
+	struct pmem2_source *src;
+	struct pmem2_config *cfg;
+	PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd,
+		PMEM2_GRANULARITY_PAGE);
+
+	struct pmem2_map *map = map_valid(cfg, src);
+
+	UT_ASSERT(pmem2_map_get_size(map) >= TEST_SIZE * num_threads);
+
+	os_thread_t *threads
+		= MALLOC(num_threads * sizeof(*threads));
+	struct thread_arg *args = MALLOC(num_threads * sizeof(*args));
+
+	char *data = pmem2_map_get_address(map);
+	for (unsigned i = 0; i < num_threads; i++) {
+		args[i].map = map;
+		args[i].addr = data + i * TEST_SIZE;
+		args[i].threads = num_threads;
+		args[i].thread_id = i;
+
+		THREAD_CREATE(&threads[i], NULL, thread_worker,
+			&args[i]);
+	}
+
+	for (unsigned i = 0; i < num_threads; i++) {
+		THREAD_JOIN(&threads[i], NULL);
+	}
+
+	FREE(threads);
+	FREE(args);
+
+	pmem2_map_delete(&map);
+	pmem2_config_delete(&cfg);
+	pmem2_source_delete(&src);
+	CLOSE(fd);
+	return 2;
+}
+
+/*
+ * test_miniasync_mover -- test memcpy async with miniasync mover
+ */
+static int
+test_miniasync_mover(const struct test_case *tc, int argc, char *argv[])
+{
+	if (argc < 1)
+		UT_FATAL("usage: test_miniasync_mover <file>");
+
+	char *file = argv[0];
+	int fd = OPEN(file, O_RDWR);
+
+	struct pmem2_source *src;
+	struct pmem2_config *cfg;
+	PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd,
+		PMEM2_GRANULARITY_PAGE);
+	struct data_mover_sync *dms = data_mover_sync_new();
+	UT_ASSERTne(dms, NULL);
+
+	struct vdm *vdm = data_mover_sync_get_vdm(dms);
+	UT_ASSERTne(vdm, NULL);
+
+	pmem2_config_set_vdm(cfg, vdm);
+	struct pmem2_map *map = map_valid(cfg, src);
+	char *data = pmem2_map_get_address(map);
+	pmem2_memset_fn memset_fn = pmem2_get_memset_fn(map);
+	memset_fn(data, 0xBA, 4096, 0);
+	memset_fn(data + 4096, 0xAB, 4096, 0);
+	struct vdm_operation_future cpy =
+		pmem2_memcpy_async(map, data, data + 4096, 4096, 0);
+
+	FUTURE_BUSY_POLL(&cpy);
+
+	if (memcmp(data, data + 4096, 4096))
+		UT_FATAL("data should be equal");
+
+	pmem2_map_delete(&map);
+	pmem2_config_delete(&cfg);
+	pmem2_source_delete(&src);
+	CLOSE(fd);
+	return 1;
+}
+
+/*
+ * test_cases -- available test cases
+ */
+static struct test_case test_cases[] = {
+	TEST_CASE(test_mover_basic),
+	TEST_CASE(test_mover_multithreaded),
+	TEST_CASE(test_miniasync_mover)
+};
+
+#define NTESTS (sizeof(test_cases) / sizeof(test_cases[0]))
+
+int
+main(int argc, char *argv[])
+{
+	START(argc, argv, "pmem2_mover");
+	TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS);
+	DONE(NULL);
+}
diff --git a/src/test/pmem2_mover/pmem2_mover.vcxproj b/src/test/pmem2_mover/pmem2_mover.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..f3b4ff1d13fd45051aa61d9312422275622f8266
--- /dev/null
+++ b/src/test/pmem2_mover/pmem2_mover.vcxproj
@@ -0,0 +1,105 @@
+<?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>{4870E3C3-63A1-4702-9E61-47ABCFF3AB0F}</ProjectGuid>
+    <RootNamespace>pmem2_mover</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.22000.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>v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LibraryPath>$(solutionDir)deps\miniasync\build\src\Release;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LibraryPath>$(solutionDir)deps\miniasync\build\src\Release;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)\libpmem2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>miniasync.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </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>
+    </ClCompile>
+    <Link>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>miniasync.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\unittest\ut_pmem2_config.c" />
+    <ClCompile Include="..\unittest\ut_pmem2_source.c" />
+    <ClCompile Include="..\unittest\ut_pmem2_utils.c" />
+    <ClCompile Include="..\unittest\ut_pmem2_setup_integration.c" />
+    <ClCompile Include="pmem2_mover.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\unittest\unittest.h" />
+    <ClInclude Include="..\unittest\ut_pmem2.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\libpmem2\libpmem2.vcxproj">
+      <Project>{f596c36c-5c96-4f08-b420-8908af500954}</Project>
+    </ProjectReference>
+    <ProjectReference Include="..\unittest\libut.vcxproj">
+      <Project>{ce3f2dfb-8470-4802-ad37-21caf6cb2681}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="pmemcheck4.log.match" />
+    <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_mover/pmem2_mover.vcxproj.filters b/src/test/pmem2_mover/pmem2_mover.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..d4d81fa2b56ebbd569b5d67267de23a2b36357c4
--- /dev/null
+++ b/src/test/pmem2_mover/pmem2_mover.vcxproj.filters
@@ -0,0 +1,52 @@
+<?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>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Test Scripts">
+      <UniqueIdentifier>{4c1dd0a5-269b-43ca-aadb-69c54b295dc2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Match Files">
+      <UniqueIdentifier>{92f1ac35-e06e-4934-8606-adae8fb61b52}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\unittest\ut_pmem2_utils.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pmem2_mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\unittest\ut_pmem2_config.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\unittest\ut_pmem2_source.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\unittest\ut_pmem2_setup_integration.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\unittest\unittest.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\unittest\ut_pmem2.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="TESTS.py">
+      <Filter>Test Scripts</Filter>
+    </None>
+    <None Include="pmemcheck4.log.match">
+      <Filter>Match Files</Filter>
+    </None>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/test/pmem2_source/pmem2_source.vcxproj b/src/test/pmem2_source/pmem2_source.vcxproj
index 08467dddbb6a975212c5b4ef22546ee9bb968ef1..9cbc79c87e47d32a3b989764e4025dfe7a04f405 100644
--- a/src/test/pmem2_source/pmem2_source.vcxproj
+++ b/src/test/pmem2_source/pmem2_source.vcxproj
@@ -77,6 +77,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\libpmem2\config.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
     <ClCompile Include="..\..\libpmem2\libpmem2.c" />
@@ -84,6 +85,7 @@
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\mcsafe_ops_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\source.c" />
@@ -99,6 +101,7 @@
     <ClCompile Include="pmem2_source.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\pmem2.h" />
     <ClInclude Include="..\..\libpmem2\pmem2_utils.h" />
diff --git a/src/test/pmem2_source/pmem2_source.vcxproj.filters b/src/test/pmem2_source/pmem2_source.vcxproj.filters
index cc96ba9957f320fd5f7accf894416a6911afa7b6..034d8fd643d43df46bea5a1d964d208dfb012cf6 100644
--- a/src/test/pmem2_source/pmem2_source.vcxproj.filters
+++ b/src/test/pmem2_source/pmem2_source.vcxproj.filters
@@ -21,6 +21,8 @@
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" />
     <ClCompile Include="..\..\libpmem2\libpmem2.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
+    <ClCompile Include="..\..\core\membuf.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\libpmem2\config.h" />
@@ -28,5 +30,6 @@
     <ClInclude Include="..\..\libpmem2\pmem2_utils.h" />
     <ClInclude Include="..\unittest\ut_pmem2_config.h" />
     <ClInclude Include="..\unittest\ut_pmem2_utils.h" />
+    <ClInclude Include="..\..\core\membuf.h" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj
index 885fd9eeec0f8890eda09da8a8cabdcd43dc868a..4bb81a2f26a5b36d913cc8243ec7db179e1b74b7 100644
--- a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj
+++ b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj
@@ -77,6 +77,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\libpmem2\config.c" />
     <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" />
@@ -85,6 +86,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\pmem2_utils.c" />
@@ -99,6 +101,7 @@
     <ClCompile Include="pmem2_vm_reservation.c" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\..\libpmem2\config.h" />
     <ClInclude Include="..\..\libpmem2\map.h" />
     <ClInclude Include="..\..\libpmem2\pmem2.h" />
diff --git a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters
index 3a04d1e6e84f2c96a37cbf003b7bf7f2300a9999..0077b85a9e9e0d2317ba83cf7ae864ceb667d7c6 100644
--- a/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters
+++ b/src/test/pmem2_vm_reservation/pmem2_vm_reservation.vcxproj.filters
@@ -74,6 +74,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\libpmem2\config.h">
@@ -97,6 +103,9 @@
     <ClInclude Include="..\..\core\ravl_interval.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\membuf.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="TESTS.py">
diff --git a/src/test/scope/out13.log.match b/src/test/scope/out13.log.match
index a611e3206f332fbe9b8f10ae0951323d07d90d05..0cd04d146f37ec950b02696c3bbb98ba2135fd1c 100644
--- a/src/test/scope/out13.log.match
+++ b/src/test/scope/out13.log.match
@@ -9,6 +9,7 @@ pmem2_config_set_offset$(nW)
 pmem2_config_set_protection$(nW)
 pmem2_config_set_required_store_granularity$(nW)
 pmem2_config_set_sharing$(nW)
+pmem2_config_set_vdm$(nW)
 pmem2_config_set_vm_reservation$(nW)
 pmem2_deep_flush$(nW)
 pmem2_errormsg$(nW)
@@ -24,6 +25,7 @@ pmem2_map_get_address$(nW)
 pmem2_map_get_size$(nW)
 pmem2_map_get_store_granularity$(nW)
 pmem2_map_new$(nW)
+pmem2_memcpy_async$(nW)
 pmem2_perror$(nW)
 pmem2_source_alignment$(nW)
 pmem2_source_delete$(nW)
diff --git a/src/test/scope/out14.log.match b/src/test/scope/out14.log.match
index 51ce91ee402688632c7115f102baa25ca198eab6..e64fd58b04d723535c18e607bbd1f613e6878adb 100644
--- a/src/test/scope/out14.log.match
+++ b/src/test/scope/out14.log.match
@@ -10,6 +10,7 @@ pmem2_config_set_offset
 pmem2_config_set_protection
 pmem2_config_set_required_store_granularity
 pmem2_config_set_sharing
+pmem2_config_set_vdm
 pmem2_config_set_vm_reservation
 pmem2_deep_flush
 pmem2_errormsgU
@@ -26,6 +27,7 @@ pmem2_map_get_address
 pmem2_map_get_size
 pmem2_map_get_store_granularity
 pmem2_map_new
+pmem2_memcpy_async
 pmem2_perrorU
 pmem2_perrorW
 pmem2_source_alignment
diff --git a/src/test/test_debug.props b/src/test/test_debug.props
index b0deaea438f0c1df31730ca4f35bb42d4a6bcf34..7055be2adb0d460bb64d37f0e3cb41f45ae47391 100644
--- a/src/test/test_debug.props
+++ b/src/test/test_debug.props
@@ -7,6 +7,7 @@
   <PropertyGroup>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\tests\</OutDir>
     <ExecutablePath>$(FrameworkSDKdir)bin\$(TargetPlatformVersion)\$(Platform);$(ExecutablePath)</ExecutablePath>
+    <IncludePath>$(solutionDir)deps\miniasync\src\include;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
diff --git a/src/test/test_release.props b/src/test/test_release.props
index e7876b215b15247236311f58c9c6e27a103dacca..785c963b8c22450ce52e6a84d6b034b3363c5af0 100644
--- a/src/test/test_release.props
+++ b/src/test/test_release.props
@@ -7,6 +7,7 @@
   <PropertyGroup>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\tests\</OutDir>
     <ExecutablePath>$(FrameworkSDKdir)bin\$(TargetPlatformVersion)\$(Platform);$(ExecutablePath)</ExecutablePath>
+    <IncludePath>$(solutionDir)deps\miniasync\src\include;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
diff --git a/src/test/unittest/consts.py b/src/test/unittest/consts.py
index d8f923d0a2c8a23618bb05b5db07123740e2705f..e90d40c8438ee25a06cc928b452b81dfc19dc829 100644
--- a/src/test/unittest/consts.py
+++ b/src/test/unittest/consts.py
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2020, Intel Corporation
+# Copyright 2020-2022, Intel Corporation
 
 """Test framework constants."""
 
@@ -21,9 +21,13 @@ WIN_RELEASE_EXEDIR = abspath(join(WIN_RELEASE_BUILDDIR, 'tests'))
 if sys.platform == 'win32':
     DEBUG_LIBDIR = abspath(join(WIN_DEBUG_BUILDDIR, 'libs'))
     RELEASE_LIBDIR = abspath(join(WIN_RELEASE_BUILDDIR, 'libs'))
+    MINIASYNC_LIBDIR = abspath(join(ROOTDIR, '..', 'deps', 'miniasync',
+                               'build', 'out', 'Release'))
 else:
     DEBUG_LIBDIR = abspath(join(ROOTDIR, '..', 'debug'))
     RELEASE_LIBDIR = abspath(join(ROOTDIR, '..', 'nondebug'))
+    MINIASYNC_LIBDIR = abspath(join(ROOTDIR, '..', 'deps', 'miniasync',
+                               'build', 'out'))
 
 HEADER_SIZE = 4096
 
diff --git a/src/test/util_sds/util_sds.vcxproj b/src/test/util_sds/util_sds.vcxproj
index fc3bd218ff94d1e8e1068bc3c8df5938eef8f7d5..fbc7c85f14d6cc25654c69181b76e23046a9e0fc 100644
--- a/src/test/util_sds/util_sds.vcxproj
+++ b/src/test/util_sds/util_sds.vcxproj
@@ -62,6 +62,7 @@
     </ClCompile>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\..\core\membuf.c" />
     <ClCompile Include="..\..\core\ravl.c" />
     <ClCompile Include="..\..\common\shutdown_state.c" />
     <ClCompile Include="..\..\libpmem2\auto_flush_windows.c" />
@@ -73,6 +74,7 @@
     <ClCompile Include="..\..\libpmem2\map.c" />
     <ClCompile Include="..\..\libpmem2\map_windows.c" />
     <ClCompile Include="..\..\libpmem2\memops_generic.c" />
+    <ClCompile Include="..\..\libpmem2\mover.c" />
     <ClCompile Include="..\..\libpmem2\persist.c" />
     <ClCompile Include="..\..\libpmem2\persist_windows.c" />
     <ClCompile Include="..\..\libpmem2\pmem2_utils.c" />
@@ -124,6 +126,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\core\membuf.h" />
     <ClInclude Include="..\unittest\ut_pmem2.h" />
     <ClInclude Include="mocks_windows.h" />
   </ItemGroup>
diff --git a/src/test/util_sds/util_sds.vcxproj.filters b/src/test/util_sds/util_sds.vcxproj.filters
index b072210a4fb7932294f25c9b81a4592febfdb982..a90e98e543d2e77fa9908d0087adebf0bbe840f0 100644
--- a/src/test/util_sds/util_sds.vcxproj.filters
+++ b/src/test/util_sds/util_sds.vcxproj.filters
@@ -118,6 +118,12 @@
     <ClCompile Include="..\..\core\ravl_interval.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\libpmem2\mover.c">
+      <Filter>Source Files\pmem2</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\core\membuf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="mocks_windows.h">
@@ -126,5 +132,8 @@
     <ClInclude Include="..\unittest\ut_pmem2.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\core\membuf.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/tools/Makefile.inc b/src/tools/Makefile.inc
index 4713952cf3615e32b7377b57f81c7388c4eb30ab..509057a8923dcec4749f353c901b0f25313449dd 100644
--- a/src/tools/Makefile.inc
+++ b/src/tools/Makefile.inc
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: BSD-3-Clause
-# Copyright 2014-2020, Intel Corporation
+# Copyright 2014-2022, Intel Corporation
 #
 # src/tools/Makefile.inc -- Makefile include for all tools
 #
@@ -176,7 +176,7 @@ ifeq ($(LIBPMEM2),y)
 DYNAMIC_LIBS += -lpmem2
 STATIC_DEBUG_LIBS += $(LIBSDIR_DEBUG)/libpmem2.a
 STATIC_NONDEBUG_LIBS += $(LIBSDIR_NONDEBUG)/libpmem2.a
-CFLAGS += $(LIBNDCTL_CFLAGS)
+CFLAGS += $(LIBNDCTL_CFLAGS) $(MINIASYNC_CFLAGS)
 LIBS += $(LIBNDCTL_LIBS)
 endif
 
diff --git a/src/windows/libs_debug.props b/src/windows/libs_debug.props
index 32d4306b00ec28d31c7c5d6cfb14ca8bfa53125f..1f1704fbf501962d8fd1250b455ecf46819162b4 100644
--- a/src/windows/libs_debug.props
+++ b/src/windows/libs_debug.props
@@ -5,6 +5,7 @@
   <PropertyGroup>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\libs\</OutDir>
     <ExecutablePath>$(FrameworkSDKdir)bin\$(TargetPlatformVersion)\$(Platform);$(ExecutablePath)</ExecutablePath>
+    <IncludePath>$(solutionDir)deps\miniasync\src\include;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
diff --git a/src/windows/libs_release.props b/src/windows/libs_release.props
index 20728c2aa8e1719bc7314c2f31b00c1896b9e177..877536bc9861d9f21c60a484e340fecbac4bd84f 100644
--- a/src/windows/libs_release.props
+++ b/src/windows/libs_release.props
@@ -5,6 +5,7 @@
   <PropertyGroup>
     <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\libs\</OutDir>
     <ExecutablePath>$(FrameworkSDKdir)bin\$(TargetPlatformVersion)\$(Platform);$(ExecutablePath)</ExecutablePath>
+    <IncludePath>$(solutionDir)deps\miniasync\src\include;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>