diff --git a/doc/Makefile b/doc/Makefile index c0b4e4bec29c2d652d4481a29b24f665150fb32e..d05bc8a5ed008561bc3ce90f863ba30afe05f918 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -107,7 +107,8 @@ MANPAGES_3_MD_PMEM2 = libpmem2/pmem2_errormsg.3.md libpmem2/pmem2_config_new.3.m 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 \ libpmem2/pmem2_deep_flush.3.md libpmem2/pmem2_source_from_anon.3.md \ - libpmem2/pmem2_source_device_id.3.md libpmem2/pmem2_source_device_usc.3.md + libpmem2/pmem2_source_device_id.3.md libpmem2/pmem2_source_device_usc.3.md \ + libpmem2/pmem2_map_from_existing.3.md MANPAGES_1_MD_PMEM2 = ifeq ($(PMEM2_INSTALL),y) MANPAGES_3_DUMMY += libpmem2/pmem2_config_delete.3 libpmem2/pmem2_source_from_handle.3 libpmem2/pmem2_source_delete.3 \ diff --git a/doc/libpmem2/.gitignore b/doc/libpmem2/.gitignore index 82f48e6f39b8c9cd0b541d90513c6951eee345ce..822fbc50cd187cf87030924ccc24a75fb374968b 100644 --- a/doc/libpmem2/.gitignore +++ b/doc/libpmem2/.gitignore @@ -19,6 +19,7 @@ pmem2_get_flush_fn.3 pmem2_get_memmove_fn.3 pmem2_get_persist_fn.3 pmem2_map_delete.3 +pmem2_map_from_existing.3 pmem2_map_new.3 pmem2_map_get_address.3 pmem2_map_get_size.3 diff --git a/doc/libpmem2/pmem2_map_delete.3.md b/doc/libpmem2/pmem2_map_delete.3.md index 04dbfae48ddcfbc07514a18425e88fd1180a2594..4ecf123850f0980e5c053bcab78a59e83f8b5662 100644 --- a/doc/libpmem2/pmem2_map_delete.3.md +++ b/doc/libpmem2/pmem2_map_delete.3.md @@ -42,6 +42,10 @@ If the function fails, the *map_ptr* variable and the map object itself are left unmodified and appropriate error value is returned. For a list of possible return values please see [RETURN VALUE](#return-value). +The **pmem2_map_delete**() function will not unmap mapping provided by the user +by **pmem2_map_from_existing**() function. In such case it will only free +*struct pmem2_map* object. + # RETURN VALUE # The **pmem2_map_delete**() function returns 0 on success diff --git a/doc/libpmem2/pmem2_map_from_existing.3.md b/doc/libpmem2/pmem2_map_from_existing.3.md new file mode 100644 index 0000000000000000000000000000000000000000..002fad9d7dc9772f1c800bed6e66013fc45a4650 --- /dev/null +++ b/doc/libpmem2/pmem2_map_from_existing.3.md @@ -0,0 +1,63 @@ +--- +layout: manual +Content-Style: 'text/css' +title: _MP(PMEM2_MAP_FROM_EXISTING, 3) +collection: libpmem2 +header: PMDK +date: pmem2 API version 1.0 +... + +[comment]: <> (SPDX-License-Identifier: BSD-3-Clause) +[comment]: <> (Copyright 2020, Intel Corporation) + +[comment]: <> (pmem2_map_from_existing.3 -- man page for libpmem2 pmem2_map_from_existing operation) + +[NAME](#name)<br /> +[SYNOPSIS](#synopsis)<br /> +[DESCRIPTION](#description)<br /> +[RETURN VALUE](#return-value)<br /> +[ERRORS](#errors)<br /> +[SEE ALSO](#see-also)<br /> + +# NAME # + +**pmem2_map_from_existing**() - creates a pmem2_map object from an existing mapping + +# SYNOPSIS # + +```c +#include <libpmem2.h> + +int pmem2_map_from_existing(struct pmem2_map **map, const struct pmem2_source *src, + void *addr, size_t len, enum pmem2_granularity gran); + +``` + +# DESCRIPTION # + +The **pmem2_map_from_existing**() returns a new *struct pmem2_map** for mapping +provided by the user. This function allows usage of **libpmem2**(7) API without **pmem2_map_new**(3) for mapping file. +Mapping is defined by *addr* and *len*. You have to specify underlying file as a *src*, and define granularity of this mapping. +See **pmem2_config_set_required_store_granularity**(3) and **libpmem2**(7) for more details. + +For the *pmem2_map* object created by the **pmem2_map_from_existing**(3) function, the **pmem2_map_delete**(3) will only destroy the object, +but it won't unmap the mapping this object describes. + +# RETURN VALUE # + +The **pmem2_map_from_existing**() function returns 0 when it succeeds +or a negative error code on failure. + +# ERRORS # + +The **pmem2_map_from_existing**() can fail with the following errors: + +**PMEM2_E_MAPPING_EXISTS** - when contiguous region (*addr*, *addr* + *len*) +is all ready registered by *libpmem2* + +It can also return **-ENOMEM** from the underlying **malloc**(2) function. + +# SEE ALSO # + +**malloc(2)**, **pmem2_map_delete**(3), **pmem2_map_new**(3), +**pmem2_source_from_fd**(3), **libpmem2**(7) and **<http://pmem.io>** diff --git a/src/PMDK.sln b/src/PMDK.sln index 7a5569642e1dc74ed34932b89f9df93919cf27c2..f80df13226cfaa9e1910d1f5aa6604907268c637 100644 --- a/src/PMDK.sln +++ b/src/PMDK.sln @@ -747,6 +747,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem_is_pmem", "test\pmem_i EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "util_poolset_foreach", "test\util_poolset_foreach\util_poolset_foreach.vcxproj", "{E648732D-78FA-427A-928C-9A59222D37B7}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmem2_map_from_existing", "test\pmem2_map_from_existing\pmem2_map_from_existing.vcxproj", "{E660218B-3B2D-4378-A2CD-78B865764CF1}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "log_pool_lock", "test\log_pool_lock\log_pool_lock.vcxproj", "{E68DEB59-C709-4945-AF80-EEBCADDED944}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_constructor", "test\obj_constructor\obj_constructor.vcxproj", "{E7691F81-86EF-467D-82E1-F5B9416386F9}" @@ -1785,6 +1787,10 @@ Global {E648732D-78FA-427A-928C-9A59222D37B7}.Debug|x64.Build.0 = Debug|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Release|x64.ActiveCfg = Release|x64 {E648732D-78FA-427A-928C-9A59222D37B7}.Release|x64.Build.0 = Release|x64 + {E660218B-3B2D-4378-A2CD-78B865764CF1}.Debug|x64.ActiveCfg = Debug|x64 + {E660218B-3B2D-4378-A2CD-78B865764CF1}.Debug|x64.Build.0 = Debug|x64 + {E660218B-3B2D-4378-A2CD-78B865764CF1}.Release|x64.ActiveCfg = Release|x64 + {E660218B-3B2D-4378-A2CD-78B865764CF1}.Release|x64.Build.0 = Release|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Debug|x64.ActiveCfg = Debug|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Debug|x64.Build.0 = Debug|x64 {E68DEB59-C709-4945-AF80-EEBCADDED944}.Release|x64.ActiveCfg = Release|x64 @@ -2183,6 +2189,7 @@ Global {E3229AF7-1FA2-4632-BB0B-B74F709F1A33} = {F42C09CD-ABA5-4DA9-8383-5EA40FA4D763} {E4E2EC33-7902-45D0-9C3C-ADBAFA46874A} = {F8373EDD-1B9E-462D-BF23-55638E23E98B} {E648732D-78FA-427A-928C-9A59222D37B7} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} + {E660218B-3B2D-4378-A2CD-78B865764CF1} = {A14A4556-9092-430D-B9CA-B2B1223D56CB} {E68DEB59-C709-4945-AF80-EEBCADDED944} = {1A36B57B-2E88-4D81-89C0-F575C9895E36} {E7691F81-86EF-467D-82E1-F5B9416386F9} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {E796AA20-D664-4D05-ABD9-C93A4FBE3E5C} = {4C291EEB-3874-4724-9CC2-1335D13FF0EE} diff --git a/src/include/libpmem2.h b/src/include/libpmem2.h index 3c2fcb77c4aa9ea4165980ff3a036a3928e5afbf..f57cf7e7073c53ddc46bb1385af3410cce941443 100644 --- a/src/include/libpmem2.h +++ b/src/include/libpmem2.h @@ -69,6 +69,7 @@ extern "C" { #define PMEM2_E_INVALID_PROT_FLAG (-100031) #define PMEM2_E_NO_ACCESS (-100032) #define PMEM2_E_VM_RESERVATION_NOT_EMPTY (-100033) +#define PMEM2_E_MAP_EXISTS (-100034) /* source setup */ @@ -153,6 +154,9 @@ void pmem2_config_clear_address(struct pmem2_config *cfg); /* mapping */ struct pmem2_map; +int pmem2_map_from_existing(struct pmem2_map **map, + const struct pmem2_source *src, void *addr, size_t len, + enum pmem2_granularity gran); int pmem2_map_new(struct pmem2_map **map_ptr, const struct pmem2_config *cfg, const struct pmem2_source *src); diff --git a/src/libpmem2/libpmem2.def b/src/libpmem2/libpmem2.def index 86a2d6b5bb88df2ef51a5911e613758254e241dc..1f3beb6f6f0c2e5d59b13bac575359f2461ae444 100644 --- a/src/libpmem2/libpmem2.def +++ b/src/libpmem2/libpmem2.def @@ -35,6 +35,7 @@ EXPORTS pmem2_map_get_size pmem2_map_get_store_granularity pmem2_map_new + pmem2_map_from_existing pmem2_perrorU pmem2_perrorW pmem2_source_alignment diff --git a/src/libpmem2/libpmem2.link.in b/src/libpmem2/libpmem2.link.in index d9a9674c2ccd692613fa39e65e3544eecc2d93c0..ba6ea7e2e788599bafe90986f84b42917192ba49 100644 --- a/src/libpmem2/libpmem2.link.in +++ b/src/libpmem2/libpmem2.link.in @@ -33,6 +33,7 @@ LIBPMEM2_1.0 { pmem2_map_get_size; pmem2_map_get_store_granularity; pmem2_map_new; + pmem2_map_from_existing; pmem2_perror; pmem2_source_alignment; pmem2_source_delete; diff --git a/src/libpmem2/map.c b/src/libpmem2/map.c index edea3131c20164a85858d486ce340c852a8b3e38..514bed7ec06a1b4061817205b847b4500cc251bd 100644 --- a/src/libpmem2/map.c +++ b/src/libpmem2/map.c @@ -7,15 +7,18 @@ #include "out.h" +#include "alloc.h" #include "config.h" #include "map.h" #include "ravl_interval.h" #include "os.h" #include "os_thread.h" +#include "persist.h" #include "pmem2.h" #include "pmem2_utils.h" #include "ravl.h" #include "sys_util.h" +#include "valgrind_internal.h" #include <libpmem2.h> @@ -234,3 +237,52 @@ pmem2_map_find(const void *addr, size_t len) return (struct pmem2_map *)ravl_interval_data(node); } + +/* + * pmem2_map_from_existing -- create map object for exisiting mapping + */ +int +pmem2_map_from_existing(struct pmem2_map **map_ptr, + const struct pmem2_source *src, void *addr, size_t len, + enum pmem2_granularity gran) +{ + int ret; + struct pmem2_map *map = + (struct pmem2_map *)pmem2_malloc(sizeof(*map), &ret); + + if (!map) + return ret; + + map->reserv = NULL; + map->addr = addr; + map->reserved_length = 0; + map->content_length = len; + map->effective_granularity = gran; + pmem2_set_flush_fns(map); + pmem2_set_mem_fns(map); + map->source = *src; + +#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 mappping(addr %p len %zu) is already registered by libpmem2", + addr, len); + return PMEM2_E_MAP_EXISTS; + } + return ret; + } +#ifndef _WIN32 + if (src->type == PMEM2_SOURCE_FD) { + VALGRIND_REGISTER_PMEM_MAPPING(map->addr, + map->content_length); + } +#endif + *map_ptr = map; + return 0; +} diff --git a/src/libpmem2/map_posix.c b/src/libpmem2/map_posix.c index 90e69466612aca18ecc71eecac498b52ab1e0e69..176257d81e2dd84c9e22da2cfa37a49f1651b119 100644 --- a/src/libpmem2/map_posix.c +++ b/src/libpmem2/map_posix.c @@ -584,21 +584,28 @@ pmem2_map_delete(struct pmem2_map **map_ptr) if (ret) return ret; - VALGRIND_REMOVE_PMEM_MAPPING(map->addr, map->content_length); - - if (map->reserv) { - ret = vm_reservation_map_unregister(map->reserv, map); - if (ret) - return ret; - - ret = vm_reservation_mend(map->reserv, map->addr, - map->reserved_length); - if (ret) - return ret; - } else { - ret = unmap(map->addr, map->reserved_length); - if (ret) - return ret; + /* + * when reserved_length==0 mapping is created by pmem2_map_from_existing + * such mappings are provided by the users and shouldn't be unmapped + * by pmem2. + */ + if (map->reserved_length) { + VALGRIND_REMOVE_PMEM_MAPPING(map->addr, map->content_length); + + if (map->reserv) { + ret = vm_reservation_map_unregister(map->reserv, map); + if (ret) + return ret; + + ret = vm_reservation_mend(map->reserv, map->addr, + map->reserved_length); + if (ret) + return ret; + } else { + ret = unmap(map->addr, map->reserved_length); + if (ret) + return ret; + } } Free(map); diff --git a/src/libpmem2/map_windows.c b/src/libpmem2/map_windows.c index 315dffbcd1b7e0ef7e7d6add3e858a0bac42f193..d009fc031a300fed7683dfa3d10c532c68b4813b 100644 --- a/src/libpmem2/map_windows.c +++ b/src/libpmem2/map_windows.c @@ -529,21 +529,23 @@ pmem2_map_delete(struct pmem2_map **map_ptr) if (ret) return ret; - if (map->reserv) { - util_rwlock_wrlock(&split_merge_lock); - ret = reservation_mend(map->reserv, map->addr, + if (map->reserved_length != 0) { + if (map->reserv) { + util_rwlock_wrlock(&split_merge_lock); + ret = reservation_mend(map->reserv, map->addr, map->reserved_length); - util_rwlock_unlock(&split_merge_lock); - if (ret) - return ret; + util_rwlock_unlock(&split_merge_lock); + if (ret) + return ret; - ret = vm_reservation_map_unregister(map->reserv, map); - if (ret) - return ret; - } else { - if (!UnmapViewOfFile(map->addr)) { - ERR("!!UnmapViewOfFile"); - return pmem2_lasterror_to_err(); + ret = vm_reservation_map_unregister(map->reserv, map); + if (ret) + return ret; + } else { + if (!UnmapViewOfFile(map->addr)) { + ERR("!!UnmapViewOfFile"); + return pmem2_lasterror_to_err(); + } } } diff --git a/src/test/Makefile b/src/test/Makefile index 0568d5ff13c24f120a6716c4ece5a11ce04f72ba..d07df8e40d32e58cf57099c45cb6df12f0685020 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -207,6 +207,7 @@ PMEM2_TESTS = \ pmem2_integration\ pmem2_granularity_detection\ pmem2_map\ + pmem2_map_from_existing\ pmem2_map_prot\ pmem2_persist\ pmem2_persist_valgrind\ diff --git a/src/test/pmem2_integration/TESTS.py b/src/test/pmem2_integration/TESTS.py index 24ba2991c8a6d06b0187d7f046fb82e71eb9212c..faf90e8cdcaf4f7937986e7b89722f5ac3feab3e 100755 --- a/src/test/pmem2_integration/TESTS.py +++ b/src/test/pmem2_integration/TESTS.py @@ -287,3 +287,19 @@ class TEST37(PMEM2_INTEGRATION_DEV_DAXES): class TEST38(PMEM2_INTEGRATION): """test for unaligned persists""" test_case = "test_unaligned_persist" + + +class TEST39(PMEM2_INTEGRATION): + """compare normal map vs map_from_existing""" + test_case = "test_map_from_existing" + + +class TES40(PMEM2_INTEGRATION): + """test map_from_existing from pmem2_mapping""" + test_case = "test_map_from_existing_map" + + +@t.windows_exclude +class TEST41(PMEM2_INTEGRATION_DEV_DAXES): + """compare normal map vs map_from_existing on devdax""" + test_case = "test_map_from_existing" diff --git a/src/test/pmem2_integration/pmem2_integration.c b/src/test/pmem2_integration/pmem2_integration.c index d7fc7aed82a6f4a8c7b274b4f206ef534c67e49d..8b186a24835127cc2965cfc0f1192f6b7bf90ece 100644 --- a/src/test/pmem2_integration/pmem2_integration.c +++ b/src/test/pmem2_integration/pmem2_integration.c @@ -897,6 +897,94 @@ test_source_anon_too_small(const struct test_case *tc, int argc, char *argv[]) return 1; } +/* + * test_map_from_existing_map -- compare normal map with map_from_existing + */ +static int +test_map_from_existing_map(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: map_from_existing_map <file>"); + + char *file = argv[0]; + int fd = OPEN(file, O_RDWR); + + struct pmem2_config *cfg; + struct pmem2_source *src; + PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd, + PMEM2_GRANULARITY_PAGE); + + size_t size; + UT_ASSERTeq(pmem2_source_size(src, &size), 0); + + struct pmem2_map *map1 = map_valid(cfg, src, size); + + /* cleanup after the test */ + struct pmem2_map *map2; + UT_PMEM2_EXPECT_RETURN(pmem2_map_from_existing(&map2, src, + pmem2_map_get_address(map1), pmem2_map_get_size(map1), + pmem2_map_get_store_granularity(map1)), + PMEM2_E_MAP_EXISTS); + + pmem2_map_delete(&map1); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 1; +} + +/* + * test_map_from_existing -- compare normal map with map_from_existing + */ +static int +test_map_from_existing(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: test_map_from_existing <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); + + size_t size; + UT_ASSERTeq(pmem2_source_size(src, &size), 0); + + struct pmem2_map *map = map_valid(cfg, src, size); + enum pmem2_granularity gran = pmem2_map_get_store_granularity(map); + + void *persist = pmem2_get_persist_fn(map); + void *flush = pmem2_get_flush_fn(map); + void *drain = pmem2_get_drain_fn(map); + void *memmove = pmem2_get_memmove_fn(map); + void *memcpy = pmem2_get_memcpy_fn(map); + void *memset = pmem2_get_memset_fn(map); + + UT_PMEM2_EXPECT_RETURN(pmem2_map_delete(&map), 0); + void *addr = FILE_MAP(fd, size); + UT_ASSERTeq(pmem2_map_from_existing(&map, src, + addr, size, gran), 0); + UT_ASSERTeq(pmem2_map_get_address(map), addr); + UT_ASSERTeq(pmem2_map_get_size(map), size); + UT_ASSERTeq(pmem2_map_get_store_granularity(map), gran); + UT_ASSERTeq(pmem2_get_persist_fn(map), persist); + UT_ASSERTeq(pmem2_get_flush_fn(map), flush); + UT_ASSERTeq(pmem2_get_drain_fn(map), drain); + UT_ASSERTeq(pmem2_get_memmove_fn(map), memmove); + UT_ASSERTeq(pmem2_get_memcpy_fn(map), memcpy); + UT_ASSERTeq(pmem2_get_memset_fn(map), memset); + + pmem2_map_delete(&map); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 1; +} +#undef COMPARE_FUNCS + /* * test_cases -- available test cases */ @@ -922,6 +1010,8 @@ static struct test_case test_cases[] = { TEST_CASE(test_source_anon_too_small), TEST_CASE(test_source_anon_zero_len), TEST_CASE(test_unaligned_persist), + TEST_CASE(test_map_from_existing_map), + TEST_CASE(test_map_from_existing) }; #define NTESTS (sizeof(test_cases) / sizeof(test_cases[0])) diff --git a/src/test/pmem2_map_from_existing/.gitignore b/src/test/pmem2_map_from_existing/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..264b9b7af6ebd17ed5c10ae0f91b159276ef8cfd --- /dev/null +++ b/src/test/pmem2_map_from_existing/.gitignore @@ -0,0 +1 @@ +pmem2_map_from_existing diff --git a/src/test/pmem2_map_from_existing/Makefile b/src/test/pmem2_map_from_existing/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cc28900ba0ae8352ac367b4bf4a1d9838a9a3348 --- /dev/null +++ b/src/test/pmem2_map_from_existing/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation +# + +# +# src/test/pmem2_map_from_existing/Makefile -- build pmem2_map unit test +# +TOP = ../../.. + +vpath %.c $(TOP)/src/test/unittest + +INCS += -I$(TOP)/src/libpmem2 +TARGET = pmem2_map_from_existing +OBJS += pmem2_map_from_existing.o\ + ut_pmem2_utils.o\ + ut_pmem2_source.o + +LIBPMEM2=internal-debug +LIBPMEMCORE=y +include ../Makefile.inc diff --git a/src/test/pmem2_map_from_existing/TESTS.py b/src/test/pmem2_map_from_existing/TESTS.py new file mode 100644 index 0000000000000000000000000000000000000000..7fbb6ca7bc72d878539ccf624417f35b69bf6780 --- /dev/null +++ b/src/test/pmem2_map_from_existing/TESTS.py @@ -0,0 +1,42 @@ +#!../env.py +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation +# + + +import testframework as t +from testframework import granularity as g + + +@g.require_granularity(g.ANY) +class Pmem2_from_existing(t.Test): + test_type = t.Short + + def run(self, ctx): + filepath = ctx.create_holey_file(16 * t.MiB, 'testfile1') + ctx.exec('pmem2_map_from_existing', self.test_case, filepath) + + +class TEST0(Pmem2_from_existing): + """try to create two the same mappings""" + test_case = "test_two_same_mappings" + + +class TEST1(Pmem2_from_existing): + """try to map which overlap bottom part of exisiting mapping""" + test_case = "test_mapping_overlap_bottom" + + +class TEST2(Pmem2_from_existing): + """try to map which overlap upper part of exisiting mapping""" + test_case = "test_mapping_overlap_upper" + + +class TEST3(Pmem2_from_existing): + """inject enomem in to allocation of map object""" + test_case = "test_map_allocation_enomem" + + +class TEST4(Pmem2_from_existing): + """inject enomem during adding map to ravl""" + test_case = "test_register_mapping_enomem" diff --git a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.c b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.c new file mode 100644 index 0000000000000000000000000000000000000000..5382c7c81908c3e44a26353dd20e4ef5824b7da5 --- /dev/null +++ b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2020, Intel Corporation */ + +/* + * pmem2_map_from_existing.c -- pmem2_map_from_existing unittests + */ + +#include <stdbool.h> +#include "fault_injection.h" +#include "unittest.h" +#include "ut_pmem2_utils.h" + +/* + * test_two_same_mappings - try to create two the same mappings + */ +static int +test_two_same_mappings(const struct test_case *tc, int argc, char *argv[]) +{ + struct pmem2_map *map1 = NULL; + struct pmem2_map *map2 = NULL; + struct pmem2_source *src; + + int fd = OPEN(argv[0], O_RDWR); + int ret = pmem2_source_from_fd(&src, fd); + UT_ASSERTeq(ret, 0); + + ret = pmem2_map_from_existing(&map1, src, (void *)0xFFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, 0); + UT_ASSERTne(map1, NULL); + + ret = pmem2_map_from_existing(&map2, src, (void *)0xFFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAP_EXISTS); + UT_ASSERTeq(map2, NULL); + + pmem2_map_delete(&map1); + CLOSE(fd); + return 1; +} + +/* + * test_mapping_overlap_bottom - try to map which overlap + * bottom part of exisiting mapping + */ +static int +test_mapping_overlap_bottom(const struct test_case *tc, int argc, char *argv[]) +{ + struct pmem2_map *map1 = NULL; + struct pmem2_map *map2 = NULL; + struct pmem2_source *src; + + int fd = OPEN(argv[0], O_RDWR); + int ret = pmem2_source_from_fd(&src, fd); + UT_ASSERTeq(ret, 0); + + ret = pmem2_map_from_existing(&map1, src, (void *)0xFFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, 0); + UT_ASSERTne(map1, NULL); + + ret = pmem2_map_from_existing(&map2, src, (void *)0xFFF0, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAP_EXISTS); + UT_ASSERTeq(map2, NULL); + + pmem2_map_delete(&map1); + CLOSE(fd); + return 1; +} + +/* + * test_mapping_overlap_upper - try to map which overlap + * upper part of exisiting mapping + */ +static int +test_mapping_overlap_upper(const struct test_case *tc, int argc, char *argv[]) +{ + struct pmem2_map *map1 = NULL; + struct pmem2_map *map2 = NULL; + struct pmem2_source *src; + + int fd = OPEN(argv[0], O_RDWR); + int ret = pmem2_source_from_fd(&src, fd); + UT_ASSERTeq(ret, 0); + + ret = pmem2_map_from_existing(&map1, src, (void *)0x0FFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, 0); + UT_ASSERTne(map1, NULL); + + ret = pmem2_map_from_existing(&map2, src, (void *)(0x0FFFF + 0x1), + 0xFFFF, PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, PMEM2_E_MAP_EXISTS); + UT_ASSERTeq(map2, NULL); + + pmem2_map_delete(&map1); + CLOSE(fd); + return 1; +} + +/* + * test_map_allocation_enomem - inject enomem in to allocation of map object + */ +static int +test_map_allocation_enomem(const struct test_case *tc, int argc, char *argv[]) +{ + struct pmem2_map *map = NULL; + struct pmem2_source *src; + + if (!core_fault_injection_enabled()) { + return 1; + } + + int fd = OPEN(argv[0], O_RDWR); + int ret = pmem2_source_from_fd(&src, fd); + UT_ASSERTeq(ret, 0); + + core_inject_fault_at(PMEM_MALLOC, 1, "pmem2_malloc"); + ret = pmem2_map_from_existing(&map, src, (void *)0x0FFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, -ENOMEM); + UT_ASSERTeq(map, NULL); + + CLOSE(fd); + return 1; +} + +/* + * test_register_mapping_enomem - inject enomem during adding map to ravl + */ +static int +test_register_mapping_enomem(const struct test_case *tc, int argc, char *argv[]) +{ + struct pmem2_map *map = NULL; + struct pmem2_source *src; + + if (!core_fault_injection_enabled()) { + return 1; + } + + int fd = OPEN(argv[0], O_RDWR); + int ret = pmem2_source_from_fd(&src, fd); + UT_ASSERTeq(ret, 0); + + core_inject_fault_at(PMEM_MALLOC, 1, "ravl_new_node"); + ret = pmem2_map_from_existing(&map, src, (void *)0x0FFFF, 0xFF, + PMEM2_GRANULARITY_PAGE); + + UT_PMEM2_EXPECT_RETURN(ret, -ENOMEM); + UT_ASSERTeq(map, NULL); + + CLOSE(fd); + return 1; +} + +/* + * test_cases -- available test cases + */ +static struct test_case test_cases[] = { + TEST_CASE(test_two_same_mappings), + TEST_CASE(test_mapping_overlap_bottom), + TEST_CASE(test_mapping_overlap_upper), + TEST_CASE(test_map_allocation_enomem), + TEST_CASE(test_register_mapping_enomem), + +}; + +#define NTESTS (sizeof(test_cases) / sizeof(test_cases[0])) + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "pmem2_map_from_existing"); + TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); + DONE(NULL); +} + +#ifdef _MSC_VER +MSVC_CONSTR(libpmem2_init) +MSVC_DESTR(libpmem2_fini) +#endif diff --git a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..8fadc4080abee88e8b2d0751d4472f5bfeb46ca8 --- /dev/null +++ b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{E660218B-3B2D-4378-A2CD-78B865764CF1}</ProjectGuid> + <RootNamespace>pmem2_map_from_existing</RootNamespace> + <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_debug.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_release.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>SSE2_AVAILABLE=0;AVX_AVAILABLE=0;AVX512F_AVAILABLE=0;PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalIncludeDirectories>$(SolutionDir)\libpmem2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <AdditionalIncludeDirectories>$(SolutionDir)\libpmem2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>SSE2_AVAILABLE=0;AVX_AVAILABLE=0;AVX512F_AVAILABLE=0;PMDK_UTF8_API;SDS_ENABLED;NTDDI_VERSION=NTDDI_WIN10_RS1;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectReference Include="..\..\common\libpmemcommon.vcxproj"> + <Project>{492baa3d-0d5d-478e-9765-500463ae69aa}</Project> + </ProjectReference> + <ProjectReference Include="..\unittest\libut.vcxproj"> + <Project>{ce3f2dfb-8470-4802-ad37-21caf6cb2681}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\..\common\ravl.c" /> + <ClCompile Include="..\..\libpmem2\config.c" /> + <ClCompile Include="..\..\libpmem2\deep_flush_windows.c" /> + <ClCompile Include="..\..\libpmem2\errormsg.c" /> + <ClCompile Include="..\..\libpmem2\libpmem2.c" /> + <ClCompile Include="..\..\libpmem2\map.c" /> + <ClCompile Include="..\..\libpmem2\map_windows.c" /> + <ClCompile Include="..\..\libpmem2\memops_generic.c" /> + <ClCompile Include="..\..\libpmem2\persist.c" /> + <ClCompile Include="..\..\libpmem2\persist_windows.c" /> + <ClCompile Include="..\..\libpmem2\pmem2_utils.c" /> + <ClCompile Include="..\..\libpmem2\ravl_interval.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation.c" /> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c" /> + <ClCompile Include="..\..\libpmem2\x86_64\cpu.c" /> + <ClCompile Include="..\..\libpmem2\x86_64\init.c" /> + <ClCompile Include="..\unittest\ut_pmem2_setup.c" /> + <ClCompile Include="..\unittest\ut_pmem2_source.c" /> + <ClCompile Include="..\unittest\ut_pmem2_utils.c" /> + <ClCompile Include="pmem2_map_from_existing.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\libpmem2\config.h" /> + <ClInclude Include="..\..\libpmem2\map.h" /> + <ClInclude Include="..\..\libpmem2\pmem2.h" /> + <ClInclude Include="..\..\libpmem2\pmem2_utils.h" /> + <ClInclude Include="..\..\libpmem2\ravl_interval.h" /> + <ClInclude Include="..\..\libpmem2\vm_reservation.h" /> + <ClInclude Include="..\unittest\ut_pmem2.h" /> + </ItemGroup> + <ItemGroup> + <None Include="TESTS.py" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> \ No newline at end of file diff --git a/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..62a83a5b08b4c1e2d7d27c99e60d4bcc269b2a6b --- /dev/null +++ b/src/test/pmem2_map_from_existing/pmem2_map_from_existing.vcxproj.filters @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{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>{4557bbd3-f8c2-4d53-821f-ec79100e2b50}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="pmem2_map_from_existing.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_utils.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\common\ravl.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\pmem2_utils.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\errormsg.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\config.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\map.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\map_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\libpmem2.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\persist.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\persist_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\x86_64\cpu.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\x86_64\init.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\memops_generic.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_source.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\deep_flush_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\unittest\ut_pmem2_setup.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\ravl_interval.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\libpmem2\vm_reservation.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\libpmem2\config.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\pmem2_utils.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\map.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\pmem2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\unittest\ut_pmem2.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\ravl_interval.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\libpmem2\vm_reservation.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="TESTS.py"> + <Filter>Test Scripts</Filter> + </None> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/src/test/scope/out13.log.match b/src/test/scope/out13.log.match index c95fcca7cf796e49146e7e55a69e3f94050fc00e..dc6a99df08adddd8fcc6280efaf7ca8aa77eae6a 100644 --- a/src/test/scope/out13.log.match +++ b/src/test/scope/out13.log.match @@ -21,6 +21,7 @@ pmem2_get_memmove_fn$(nW) pmem2_get_memset_fn$(nW) pmem2_get_persist_fn$(nW) pmem2_map_delete$(nW) +pmem2_map_from_existing$(nW) pmem2_map_get_address$(nW) pmem2_map_get_size$(nW) pmem2_map_get_store_granularity$(nW) diff --git a/src/test/scope/out14.log.match b/src/test/scope/out14.log.match index 5cdcc3df9946ba73f32d33c4609383b34a8ae54a..2eb857499dc6f1f8ac98b6892fece82ee1cdf611 100644 --- a/src/test/scope/out14.log.match +++ b/src/test/scope/out14.log.match @@ -22,6 +22,7 @@ pmem2_get_memmove_fn pmem2_get_memset_fn pmem2_get_persist_fn pmem2_map_delete +pmem2_map_from_existing pmem2_map_get_address pmem2_map_get_size pmem2_map_get_store_granularity diff --git a/src/test/unittest/unittest.h b/src/test/unittest/unittest.h index 1be17390de4fb8390ba15f7e14575fb309b1548b..96db8a1c808f0cedcbcfe7705fc4534531f4ff39 100644 --- a/src/test/unittest/unittest.h +++ b/src/test/unittest/unittest.h @@ -399,6 +399,9 @@ int ut_mprotect(const char *file, int line, const char *func, void *addr, int ut_ftruncate(const char *file, int line, const char *func, int fd, os_off_t length); +void *ut_file_map(const char *file, int line, const char *func, int fd, + size_t size); + long long ut_strtoll(const char *file, int line, const char *func, const char *nptr, char **endptr, int base); @@ -483,6 +486,9 @@ int ut_snprintf(const char *file, int line, const char *func, #define FTRUNCATE(fd, length)\ ut_ftruncate(__FILE__, __LINE__, __func__, fd, length) +#define FILE_MAP(fd, size)\ + ut_file_map(__FILE__, __LINE__, __func__, fd, size); + #define ATOU(nptr) STRTOU(nptr, NULL, 10) #define ATOUL(nptr) STRTOUL(nptr, NULL, 10) #define ATOULL(nptr) STRTOULL(nptr, NULL, 10) diff --git a/src/test/unittest/ut_file.c b/src/test/unittest/ut_file.c index 26f5cbda69312f047f2535971bf647e7115910fe..54cb1bb6fbeadc46edd7e0cf6aefa7de80989a75 100644 --- a/src/test/unittest/ut_file.c +++ b/src/test/unittest/ut_file.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2014-2018, Intel Corporation */ +/* Copyright 2014-2020, Intel Corporation */ /* * ut_file.c -- unit test file operations @@ -327,3 +327,53 @@ ut_ftruncate(const char *file, int line, const char *func, int fd, return retval; } + +#ifdef _WIN32 +/* + * file_map -- map file without using pmdk api + */ +void * +ut_file_map(const char *file, int line, const char *func, int fd, size_t size) +{ + void *addr = NULL; + HANDLE handle = (HANDLE)_get_osfhandle(fd); + UT_ASSERTne(handle, INVALID_HANDLE_VALUE); + + HANDLE mh = CreateFileMapping(handle, + NULL, + PAGE_READWRITE, + size >> 32, + size & 0xFFFFFFFF, + NULL); + + if (mh == INVALID_HANDLE_VALUE) + ut_fatal(file, line, func, "!!CreateFileMapping"); + + addr = MapViewOfFileEx(mh, + FILE_MAP_ALL_ACCESS, + 0, + 0, + size, + NULL); + + if (addr == NULL) + ut_fatal(file, line, func, "!!CreateFileMapping"); + + if (CloseHandle(mh) == 0) + ut_fatal(file, line, func, "!!CloseHandle"); + + return addr; +} +#else +/* + * file_map -- map file without using pmdk api + */ +void * +ut_file_map(const char *file, int line, const char *func, int fd, size_t size) +{ + void *addr = NULL; + ut_mmap(file, line, func, addr, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + return addr; +} +#endif