From 5ef2a8d5bf7b54f41b1ae7ff85c3b9a4d9e59799 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 10 Feb 2021 15:41:50 +0100 Subject: [PATCH] rpma: mmap() memory for rpma_mr_reg() in rpma_flush_apm_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The memory region passed to rpma_mr_reg() (ibv_mr_reg()) cannot be allocated from the heap (using malloc() or posix_memalign()), but should be mapped using mmap(). Rationale: If ibv_fork_init() was called, the memory region passed to ibv_mr_reg() is marked by this function with flag “do not copy on fork” and after having called fork(), the child process does not receive this range of virtual addresses. If this memory region was allocated from the heap, the child process receives a corrupted heap with a “hole” of inaccessible addresses inside. A memory allocator knows nothing about this “hole” and if it tries to access (read or write) that range of virtual addresses, it causes a segfault. Ref: #751 --- src/flush.c | 31 +++++-- src/flush.h | 7 +- src/include/librpma.h | 2 +- tests/integration/common/mocks.c | 48 +++++++++- tests/integration/common/mocks.h | 7 +- .../example-01-connection/CMakeLists.txt | 4 +- .../example-01-connection.c | 20 +++-- .../CMakeLists.txt | 4 +- .../example-02-read-to-volatile.c | 20 +++-- .../CMakeLists.txt | 4 +- .../example-04-write-to-persistent.c | 20 +++-- tests/unit/common/mocks-rpma-mr.c | 10 ++- tests/unit/common/mocks-stdlib.c | 50 ++++++++--- tests/unit/common/mocks-stdlib.h | 7 +- tests/unit/conn/conn-new.c | 35 +++++++- tests/unit/flush/CMakeLists.txt | 4 +- tests/unit/flush/flush-common.c | 18 ++-- tests/unit/flush/flush-common.h | 5 +- tests/unit/flush/flush-new.c | 87 ++++++++++++++++--- 19 files changed, 299 insertions(+), 84 deletions(-) diff --git a/src/flush.c b/src/flush.c index 1ea9b29fd9..15fd0c7c5c 100644 --- a/src/flush.c +++ b/src/flush.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * flush.c -- librpma flush-related implementations @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef TEST_MOCK_ALLOC #include "cmocka_alloc.h" @@ -40,6 +41,7 @@ struct rpma_flush_internal { struct flush_apm { void *raw; /* buffer for read-after-write memory region */ + size_t mmap_size; /* size of the mmap()'ed memory */ struct rpma_mr_local *raw_mr; /* read-after-write memory region */ }; @@ -51,6 +53,8 @@ struct flush_apm { static int rpma_flush_apm_new(struct rpma_peer *peer, struct rpma_flush *flush) { + int ret; + /* a memory registration has to be page-aligned */ long pagesize = sysconf(_SC_PAGESIZE); if (pagesize < 0) { @@ -59,29 +63,32 @@ rpma_flush_apm_new(struct rpma_peer *peer, struct rpma_flush *flush) return RPMA_E_PROVIDER; } + size_t mmap_size = (size_t)pagesize; + /* allocate memory for the read-after-write buffer (RAW) */ - void *raw = NULL; - int ret = posix_memalign(&raw, (size_t)pagesize, RAW_SIZE); - if (ret) + void *raw = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (raw == MAP_FAILED) return RPMA_E_NOMEM; /* register the RAW buffer */ struct rpma_mr_local *raw_mr = NULL; ret = rpma_mr_reg(peer, raw, RAW_SIZE, RPMA_MR_USAGE_READ_DST, &raw_mr); if (ret) { - free(raw); + (void) munmap(raw, mmap_size); return ret; } struct flush_apm *flush_apm = malloc(sizeof(struct flush_apm)); if (flush_apm == NULL) { (void) rpma_mr_dereg(&raw_mr); - free(raw); + (void) munmap(raw, mmap_size); return RPMA_E_NOMEM; } flush_apm->raw = raw; flush_apm->raw_mr = raw_mr; + flush_apm->mmap_size = mmap_size; struct rpma_flush_internal *flush_internal = (struct rpma_flush_internal *)flush; @@ -102,12 +109,18 @@ rpma_flush_apm_delete(struct rpma_flush *flush) (struct rpma_flush_internal *)flush; struct flush_apm *flush_apm = (struct flush_apm *)flush_internal->context; - int ret = rpma_mr_dereg(&flush_apm->raw_mr); - free(flush_apm->raw); + int ret_dereg = rpma_mr_dereg(&flush_apm->raw_mr); + int ret_unmap = munmap(flush_apm->raw, flush_apm->mmap_size); free(flush_apm); - return ret; + if (ret_dereg) + return ret_dereg; + + if (ret_unmap) + return RPMA_E_INVAL; + + return 0; } /* diff --git a/src/flush.h b/src/flush.h index 6053e9b733..b1e8715572 100644 --- a/src/flush.h +++ b/src/flush.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * flush.h -- librpma flush-related internal definitions @@ -24,7 +24,7 @@ struct rpma_flush { * ERRORS * rpma_flush_new() can fail with the following errors: * - * - RPMA_E_NOMEM - out of memory + * - RPMA_E_NOMEM - out of memory (mmap() failed) * - RPMA_E_PROVIDER - sysconf() or ibv_reg_mr() failed */ int rpma_flush_new(struct rpma_peer *peer, struct rpma_flush **flush_ptr); @@ -33,7 +33,8 @@ int rpma_flush_new(struct rpma_peer *peer, struct rpma_flush **flush_ptr); * ERRORS * rpma_flush_delete() can fail with the following error: * - * - RPMA_E_PROVIDER ibv_dereg_mr() failed + * - RPMA_E_PROVIDER - ibv_dereg_mr() failed + * - RPMA_E_INVAL - munmap() failed */ int rpma_flush_delete(struct rpma_flush **flush_ptr); diff --git a/src/include/librpma.h b/src/include/librpma.h index 50c52b9414..a3999cb0f1 100644 --- a/src/include/librpma.h +++ b/src/include/librpma.h @@ -1637,7 +1637,7 @@ int rpma_conn_disconnect(struct rpma_conn *conn); * * ERRORS * rpma_conn_delete() can fail with the following errors: - * - RPMA_E_INVAL - conn_ptr is NULL + * - RPMA_E_INVAL - conn_ptr is NULL or munmap() failed * - RPMA_E_PROVIDER - ibv_destroy_cq() or rdma_destroy_id() failed * * SEE ALSO diff --git a/tests/integration/common/mocks.c b/tests/integration/common/mocks.c index 7c4b9a68c2..89557ae8fd 100644 --- a/tests/integration/common/mocks.c +++ b/tests/integration/common/mocks.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * mocks.c -- common mocks for integration tests @@ -7,6 +7,8 @@ #include #include +#include +#include #include "cmocka_headers.h" #include "conn_cfg.h" @@ -758,3 +760,47 @@ create_descriptor(void *desc, return 0; } + +/* + * __wrap_mmap -- mmap() mock + */ +void * +__wrap_mmap(void *__addr, size_t __len, int __prot, + int __flags, int __fd, off_t __offset) +{ + void *ret = mock_type(void *); + if (ret != (void *)MOCK_OK) + return MAP_FAILED; + + struct mmap_args *args = mock_type(struct mmap_args *); + + void *memptr = __real__test_malloc(__len); + + /* + * Save the address and length of the allocated memory + * in order to verify it later. + */ + args->addr = memptr; + args->len = __len; + + return memptr; +} + +/* + * __wrap_munmap -- munmap() mock + */ +int +__wrap_munmap(void *__addr, size_t __len) +{ + struct mmap_args *args = mock_type(struct mmap_args *); + assert_ptr_equal(__addr, args->addr); + assert_int_equal(__len, args->len); + + test_free(__addr); + + errno = mock_type(int); + if (errno) + return -1; + + return 0; +} diff --git a/tests/integration/common/mocks.h b/tests/integration/common/mocks.h index 7d71ac52a0..7fac29ad85 100644 --- a/tests/integration/common/mocks.h +++ b/tests/integration/common/mocks.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * mocks.h -- common mocks for integration tests @@ -62,6 +62,11 @@ struct posix_memalign_args { void *ptr; }; +struct mmap_args { + void *addr; + size_t len; +}; + #ifdef ON_DEMAND_PAGING_SUPPORTED int ibv_query_device_ex_mock(struct ibv_context *context, const struct ibv_query_device_ex_input *input, diff --git a/tests/integration/example-01-connection/CMakeLists.txt b/tests/integration/example-01-connection/CMakeLists.txt index 6dc472f6dc..4748610604 100644 --- a/tests/integration/example-01-connection/CMakeLists.txt +++ b/tests/integration/example-01-connection/CMakeLists.txt @@ -1,6 +1,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2020, Intel Corporation +# Copyright 2020-2021, Intel Corporation # include(../../cmake/ctest_helpers.cmake) @@ -34,7 +34,7 @@ target_include_directories(${TARGET} PRIVATE set_target_properties(${TARGET} PROPERTIES - LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=fprintf") + LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=mmap,--wrap=munmap,--wrap=fprintf") target_compile_definitions(${TARGET} PUBLIC TEST_MOCK_MAIN diff --git a/tests/integration/example-01-connection/example-01-connection.c b/tests/integration/example-01-connection/example-01-connection.c index ec1c663364..8de59f29d5 100644 --- a/tests/integration/example-01-connection/example-01-connection.c +++ b/tests/integration/example-01-connection/example-01-connection.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * example-01-connection.c -- connection integration tests @@ -92,13 +92,14 @@ test_client__success(void **unused) expect_value(rdma_migrate_id, channel, MOCK_EVCH); will_return(rdma_migrate_id, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &allocated_raw.ptr); + will_return(ibv_reg_mr, &allocated_raw.addr); will_return(ibv_reg_mr, MOCK_MR); expect_value(rdma_connect, id, &id); @@ -133,6 +134,8 @@ test_client__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &id); @@ -244,13 +247,14 @@ test_server__success(void **unused) expect_value(rdma_migrate_id, channel, MOCK_EVCH); will_return(rdma_migrate_id, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &allocated_raw.ptr); + will_return(ibv_reg_mr, &allocated_raw.addr); will_return(ibv_reg_mr, MOCK_MR); /* configure mocks for rpma_conn_next_event() */ @@ -283,6 +287,8 @@ test_server__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &id); diff --git a/tests/integration/example-02-read-to-volatile/CMakeLists.txt b/tests/integration/example-02-read-to-volatile/CMakeLists.txt index 412724aca8..54b4ffb909 100644 --- a/tests/integration/example-02-read-to-volatile/CMakeLists.txt +++ b/tests/integration/example-02-read-to-volatile/CMakeLists.txt @@ -1,6 +1,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2020, Intel Corporation +# Copyright 2020-2021, Intel Corporation # include(../../cmake/ctest_helpers.cmake) @@ -35,7 +35,7 @@ target_include_directories(${TARGET} PRIVATE set_target_properties(${TARGET} PROPERTIES - LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=fprintf") + LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=fprintf,--wrap=mmap,--wrap=munmap") target_compile_definitions(${TARGET} PUBLIC TEST_MOCK_MAIN diff --git a/tests/integration/example-02-read-to-volatile/example-02-read-to-volatile.c b/tests/integration/example-02-read-to-volatile/example-02-read-to-volatile.c index aef113be35..5301250717 100644 --- a/tests/integration/example-02-read-to-volatile/example-02-read-to-volatile.c +++ b/tests/integration/example-02-read-to-volatile/example-02-read-to-volatile.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * example-02-read-to-volatile.c -- 'read to volatile' integration tests @@ -107,13 +107,14 @@ test_client__success(void **unused) expect_value(rdma_migrate_id, channel, MOCK_EVCH); will_return(rdma_migrate_id, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &allocated_raw.ptr); + will_return(ibv_reg_mr, &allocated_raw.addr); will_return(ibv_reg_mr, MOCK_MR_RAW); expect_value(rdma_connect, id, &Cm_id); @@ -180,6 +181,8 @@ test_client__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR_RAW); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &Cm_id); @@ -304,13 +307,14 @@ test_server__success(void **unused) expect_value(rdma_migrate_id, channel, MOCK_EVCH); will_return(rdma_migrate_id, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &allocated_raw.ptr); + will_return(ibv_reg_mr, &allocated_raw.addr); will_return(ibv_reg_mr, MOCK_MR_RAW); /* configure mocks for rpma_conn_next_event() */ @@ -343,6 +347,8 @@ test_server__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR_RAW); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &Cm_id); diff --git a/tests/integration/example-04-write-to-persistent/CMakeLists.txt b/tests/integration/example-04-write-to-persistent/CMakeLists.txt index 4865f48183..7c3ccf5b15 100644 --- a/tests/integration/example-04-write-to-persistent/CMakeLists.txt +++ b/tests/integration/example-04-write-to-persistent/CMakeLists.txt @@ -1,6 +1,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2020, Intel Corporation +# Copyright 2020-2021, Intel Corporation # include(../../cmake/ctest_helpers.cmake) @@ -35,7 +35,7 @@ target_include_directories(${TARGET} PRIVATE set_target_properties(${TARGET} PROPERTIES - LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=fprintf") + LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=fprintf,--wrap=mmap,--wrap=munmap") target_compile_definitions(${TARGET} PUBLIC TEST_MOCK_MAIN diff --git a/tests/integration/example-04-write-to-persistent/example-04-write-to-persistent.c b/tests/integration/example-04-write-to-persistent/example-04-write-to-persistent.c index 7bbd9f9f7b..7aef9b48e0 100644 --- a/tests/integration/example-04-write-to-persistent/example-04-write-to-persistent.c +++ b/tests/integration/example-04-write-to-persistent/example-04-write-to-persistent.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * example-04-write-to-persistent.c -- 'write to persistent' integration tests @@ -111,13 +111,14 @@ test_client__success(void **unused) will_return(rdma_migrate_id, MOCK_OK); /* allocate memory for the rpma_flush_apm_new */ - struct posix_memalign_args flush = {0}; - will_return(__wrap_posix_memalign, &flush); + struct mmap_args flush = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &flush); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &flush.ptr); + will_return(ibv_reg_mr, &flush.addr); will_return(ibv_reg_mr, MOCK_MR_FLUSH); expect_value(rdma_connect, id, &Cm_id); @@ -219,6 +220,8 @@ test_client__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR_FLUSH); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &flush); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &Cm_id); @@ -341,13 +344,14 @@ test_server__success(void **unused) expect_value(rdma_migrate_id, channel, MOCK_EVCH); will_return(rdma_migrate_id, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(ibv_reg_mr, pd, MOCK_IBV_PD); expect_value(ibv_reg_mr, length, MOCK_RAW_SIZE); expect_value(ibv_reg_mr, access, IBV_ACCESS_LOCAL_WRITE); - will_return(ibv_reg_mr, &allocated_raw.ptr); + will_return(ibv_reg_mr, &allocated_raw.addr); will_return(ibv_reg_mr, MOCK_MR_RAW); /* configure mocks for rpma_conn_next_event() */ @@ -380,6 +384,8 @@ test_server__success(void **unused) /* configure mocks for rpma_conn_delete() */ expect_value(ibv_dereg_mr, mr, MOCK_MR_RAW); will_return(ibv_dereg_mr, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rdma_destroy_qp, id, &Cm_id); diff --git a/tests/unit/common/mocks-rpma-mr.c b/tests/unit/common/mocks-rpma-mr.c index fcea4da061..f49406c6cb 100644 --- a/tests/unit/common/mocks-rpma-mr.c +++ b/tests/unit/common/mocks-rpma-mr.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * mocks-rpma-mr.c -- librpma mr.c module mocks @@ -99,8 +99,14 @@ rpma_mr_dereg(struct rpma_mr_local **mr_ptr) assert_non_null(mr_ptr); check_expected_ptr(*mr_ptr); + int ret = mock_type(int); + /* XXX validate the errno handling */ + if (ret == RPMA_E_PROVIDER) + errno = mock_type(int); + *mr_ptr = NULL; - return 0; + + return ret; } /* diff --git a/tests/unit/common/mocks-stdlib.c b/tests/unit/common/mocks-stdlib.c index 51944d711b..d397db0517 100644 --- a/tests/unit/common/mocks-stdlib.c +++ b/tests/unit/common/mocks-stdlib.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * mocks-stdlib.c -- stdlib mocks @@ -7,9 +7,12 @@ #include #include +#include +#include #include "cmocka_headers.h" #include "mocks-stdlib.h" +#include "test-common.h" void *__real__test_malloc(size_t size); @@ -28,22 +31,45 @@ __wrap__test_malloc(size_t size) } /* - * __wrap_posix_memalign -- posix_memalign() mock + * __wrap_mmap -- mmap() mock */ -int -__wrap_posix_memalign(void **memptr, size_t alignment, size_t size) +void * +__wrap_mmap(void *__addr, size_t __len, int __prot, + int __flags, int __fd, off_t __offset) { - int err = mock_type(int); - if (err) - return err; + void *ret = mock_type(void *); + if (ret != (void *)MOCK_OK) + return MAP_FAILED; - struct posix_memalign_args *args = - mock_type(struct posix_memalign_args *); + struct mmap_args *args = mock_type(struct mmap_args *); - *memptr = __real__test_malloc(size); + void *memptr = __real__test_malloc(__len); - /* save the address of the allocated memory to verify it later */ - args->ptr = *memptr; + /* + * Save the address and length of the allocated memory + * in order to verify it later. + */ + args->addr = memptr; + args->len = __len; + + return memptr; +} + +/* + * __wrap_munmap -- munmap() mock + */ +int +__wrap_munmap(void *__addr, size_t __len) +{ + struct mmap_args *args = mock_type(struct mmap_args *); + assert_ptr_equal(__addr, args->addr); + assert_int_equal(__len, args->len); + + test_free(__addr); + + errno = mock_type(int); + if (errno) + return -1; return 0; } diff --git a/tests/unit/common/mocks-stdlib.h b/tests/unit/common/mocks-stdlib.h index 5840969a4e..d6fcfe8be5 100644 --- a/tests/unit/common/mocks-stdlib.h +++ b/tests/unit/common/mocks-stdlib.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * mocks-stdlib.h -- the stdlib mocks' header @@ -8,8 +8,9 @@ #ifndef MOCKS_STDLIB_H #define MOCKS_STDLIB_H -struct posix_memalign_args { - void *ptr; +struct mmap_args { + void *addr; + size_t len; }; #endif /* MOCKS_STDLIB_H */ diff --git a/tests/unit/conn/conn-new.c b/tests/unit/conn/conn-new.c index 3ac1cc515a..a72b53a89c 100644 --- a/tests/unit/conn/conn-new.c +++ b/tests/unit/conn/conn-new.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * conn-new.c -- the connection new/delete unit tests @@ -255,6 +255,38 @@ delete__flush_delete_E_PROVIDER(void **unused) assert_null(cstate->conn); } +/* + * delete__flush_delete_E_INVAL - rpma_flush_delete() + * fails with RPMA_E_INVAL + */ +static void +delete__flush_delete_E_INVAL(void **unused) +{ + /* + * Cmocka does not allow freeing an object in a test if the object was + * created in the setup step whereas even failing rpma_conn_delete() + * will deallocate the rpma_conn object. + */ + struct conn_test_state *cstate; + int ret = setup__conn_new((void **)&cstate); + assert_int_equal(ret, 0); + assert_non_null(cstate->conn); + + /* configure mocks: */ + will_return(rpma_flush_delete, RPMA_E_INVAL); + will_return_maybe(ibv_destroy_cq, EAGAIN); + will_return_maybe(ibv_destroy_comp_channel, MOCK_OK); + expect_value(rdma_destroy_id, id, MOCK_CM_ID); + will_return_maybe(rdma_destroy_id, MOCK_OK); + + /* run test */ + ret = rpma_conn_delete(&cstate->conn); + + /* verify the results */ + assert_int_equal(ret, RPMA_E_INVAL); + assert_null(cstate->conn); +} + /* * delete__destroy_cq_EAGAIN - ibv_destroy_cq() fails with EAGAIN */ @@ -439,6 +471,7 @@ static const struct CMUnitTest tests_new[] = { cmocka_unit_test(delete__conn_ptr_NULL), cmocka_unit_test(delete__conn_NULL), cmocka_unit_test(delete__flush_delete_E_PROVIDER), + cmocka_unit_test(delete__flush_delete_E_INVAL), cmocka_unit_test(delete__destroy_cq_EAGAIN), cmocka_unit_test(delete__destroy_cq_EAGAIN_subsequent_EIO), cmocka_unit_test(delete__destroy_comp_channel_EAGAIN), diff --git a/tests/unit/flush/CMakeLists.txt b/tests/unit/flush/CMakeLists.txt index e2f668266e..283cd580ab 100644 --- a/tests/unit/flush/CMakeLists.txt +++ b/tests/unit/flush/CMakeLists.txt @@ -1,6 +1,6 @@ # # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2020, Intel Corporation +# Copyright 2020-2021, Intel Corporation # include(../../cmake/ctest_helpers.cmake) @@ -22,7 +22,7 @@ function(add_test_flush name) set_target_properties(${name} PROPERTIES - LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=posix_memalign,--wrap=sysconf") + LINK_FLAGS "-Wl,--wrap=_test_malloc,--wrap=mmap,--wrap=munmap,--wrap=sysconf") add_test_generic(NAME ${name} TRACERS none) endfunction() diff --git a/tests/unit/flush/flush-common.c b/tests/unit/flush/flush-common.c index 1820284e93..6d58c26e1c 100644 --- a/tests/unit/flush/flush-common.c +++ b/tests/unit/flush/flush-common.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * flush-common.c -- common part of unit tests of the flush module @@ -18,20 +18,20 @@ int setup__flush_new(void **fstate_ptr) { + static struct flush_test_state fstate = {0}; + /* configure mocks */ will_return_always(__wrap__test_malloc, MOCK_OK); will_return(__wrap_sysconf, MOCK_OK); - will_return(__wrap_posix_memalign, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &fstate.allocated_raw); expect_value(rpma_mr_reg, peer, MOCK_PEER); expect_value(rpma_mr_reg, size, 8); expect_value(rpma_mr_reg, usage, RPMA_MR_USAGE_READ_DST); - will_return(rpma_mr_reg, &allocated_raw.ptr); + will_return(rpma_mr_reg, &fstate.allocated_raw.addr); will_return(rpma_mr_reg, MOCK_RPMA_MR_LOCAL); /* run test */ - static struct flush_test_state fstate = {0}; int ret = rpma_flush_new(MOCK_PEER, &fstate.flush); /* verify the results */ @@ -48,11 +48,15 @@ setup__flush_new(void **fstate_ptr) int teardown__flush_delete(void **fstate_ptr) { + struct flush_test_state *fstate = *fstate_ptr; + /* configure mock */ expect_value(rpma_mr_dereg, *mr_ptr, MOCK_RPMA_MR_LOCAL); + will_return(rpma_mr_dereg, MOCK_OK); + will_return(__wrap_munmap, &fstate->allocated_raw); + will_return(__wrap_munmap, MOCK_OK); /* delete the object */ - struct flush_test_state *fstate = *fstate_ptr; int ret = rpma_flush_delete(&fstate->flush); /* verify the results */ diff --git a/tests/unit/flush/flush-common.h b/tests/unit/flush/flush-common.h index 4c1b9f0274..4007dc4649 100644 --- a/tests/unit/flush/flush-common.h +++ b/tests/unit/flush/flush-common.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause */ -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * flush-common.h -- header of the common part of unit tests @@ -9,6 +9,8 @@ #ifndef FLUSH_COMMON_H #define FLUSH_COMMON_H 1 +#include "mocks-stdlib.h" + #define MOCK_RPMA_MR_REMOTE (struct rpma_mr_remote *)0xC412 #define MOCK_RPMA_MR_LOCAL (struct rpma_mr_local *)0xC411 #define MOCK_REMOTE_OFFSET (size_t)0xC414 @@ -22,6 +24,7 @@ */ struct flush_test_state { struct rpma_flush *flush; + struct mmap_args allocated_raw; }; int setup__flush_new(void **fstate_ptr); diff --git a/tests/unit/flush/flush-new.c b/tests/unit/flush/flush-new.c index 6ca6e60170..458b680a1b 100644 --- a/tests/unit/flush/flush-new.c +++ b/tests/unit/flush/flush-new.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2020, Intel Corporation */ +/* Copyright 2020-2021, Intel Corporation */ /* * flush-new.c -- unit tests of the flush module @@ -14,6 +14,7 @@ #include "flush-common.h" #include "mocks-stdlib.h" #include "test-common.h" +#include /* * new__malloc_ENOMEM -- malloc() fail with ENOMEM @@ -53,15 +54,15 @@ new__apm_sysconf_EINVAL(void **unused) } /* - * new__apm_posix_memalign_ENOMEM -- malloc() fail with ENOMEM + * new__apm_mmap_ENOMEM -- mmap() fails with ENOMEM */ static void -new__apm_posix_memalign_ENOMEM(void **unused) +new__apm_mmap_ENOMEM(void **unused) { /* configure mocks */ will_return_always(__wrap__test_malloc, MOCK_OK); will_return(__wrap_sysconf, MOCK_OK); - will_return(__wrap_posix_memalign, ENOMEM); + will_return(__wrap_mmap, MAP_FAILED); /* run test */ struct rpma_flush *flush = NULL; @@ -82,15 +83,17 @@ new__apm_mr_reg_RPMA_E_NOMEM(void **unused) will_return_always(__wrap__test_malloc, MOCK_OK); will_return(__wrap_sysconf, MOCK_OK); - will_return(__wrap_posix_memalign, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(rpma_mr_reg, peer, MOCK_PEER); expect_value(rpma_mr_reg, size, 8); expect_value(rpma_mr_reg, usage, RPMA_MR_USAGE_READ_DST); - will_return(rpma_mr_reg, &allocated_raw.ptr); + will_return(rpma_mr_reg, &allocated_raw.addr); will_return(rpma_mr_reg, NULL); will_return(rpma_mr_reg, RPMA_E_NOMEM); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, EINVAL); /* run test */ struct rpma_flush *flush = NULL; @@ -111,15 +114,18 @@ new__apm_malloc_ENOMEM(void **unused) will_return(__wrap__test_malloc, MOCK_OK); will_return(__wrap_sysconf, MOCK_OK); - will_return(__wrap_posix_memalign, MOCK_OK); - struct posix_memalign_args allocated_raw = {0}; - will_return(__wrap_posix_memalign, &allocated_raw); + struct mmap_args allocated_raw = {0}; + will_return(__wrap_mmap, MOCK_OK); + will_return(__wrap_mmap, &allocated_raw); expect_value(rpma_mr_reg, peer, MOCK_PEER); expect_value(rpma_mr_reg, size, 8); expect_value(rpma_mr_reg, usage, RPMA_MR_USAGE_READ_DST); - will_return(rpma_mr_reg, &allocated_raw.ptr); + will_return(rpma_mr_reg, &allocated_raw.addr); will_return(rpma_mr_reg, MOCK_RPMA_MR_LOCAL); will_return(__wrap__test_malloc, ENOMEM); + will_return(rpma_mr_dereg, MOCK_OK); + will_return(__wrap_munmap, &allocated_raw); + will_return(__wrap_munmap, MOCK_OK); expect_value(rpma_mr_dereg, *mr_ptr, MOCK_RPMA_MR_LOCAL); /* run test */ @@ -143,18 +149,71 @@ new__apm_success(void **unused) */ } +/* + * delete__apm_dereg_E_PROVIDER -- rpma_mr_dereg() failed with RPMA_E_PROVIDER + */ +static void +delete__apm_dereg_E_PROVIDER(void **unused) +{ + struct flush_test_state *fstate; + + setup__flush_new((void **)&fstate); + + /* configure mocks */ + expect_value(rpma_mr_dereg, *mr_ptr, MOCK_RPMA_MR_LOCAL); + will_return(__wrap_munmap, &fstate->allocated_raw); + will_return_maybe(__wrap_munmap, MOCK_OK); + will_return(rpma_mr_dereg, RPMA_E_PROVIDER); + will_return(rpma_mr_dereg, MOCK_ERRNO); + + /* delete the object */ + int ret = rpma_flush_delete(&fstate->flush); + + /* verify the results */ + assert_int_equal(ret, RPMA_E_PROVIDER); + assert_null(fstate->flush); +} + +/* + * delete__apm_munmap_E_INVAL -- munmap() failed with EINVAL + */ +static void +delete__apm_munmap_E_INVAL(void **unused) +{ + struct flush_test_state *fstate; + + setup__flush_new((void **)&fstate); + + /* configure mocks */ + expect_value(rpma_mr_dereg, *mr_ptr, MOCK_RPMA_MR_LOCAL); + will_return_maybe(rpma_mr_dereg, MOCK_OK); + will_return(__wrap_munmap, &fstate->allocated_raw); + will_return(__wrap_munmap, EINVAL); + + /* delete the object */ + int ret = rpma_flush_delete(&fstate->flush); + + /* verify the results */ + assert_int_equal(ret, RPMA_E_INVAL); + assert_null(fstate->flush); +} + int main(int argc, char *argv[]) { const struct CMUnitTest tests[] = { - /* rpma__new() unit tests */ + /* rpma_flush_new() unit tests */ cmocka_unit_test(new__malloc_ENOMEM), cmocka_unit_test(new__apm_sysconf_EINVAL), - cmocka_unit_test(new__apm_posix_memalign_ENOMEM), + cmocka_unit_test(new__apm_mmap_ENOMEM), cmocka_unit_test(new__apm_mr_reg_RPMA_E_NOMEM), cmocka_unit_test(new__apm_malloc_ENOMEM), cmocka_unit_test_setup_teardown(new__apm_success, setup__flush_new, teardown__flush_delete), + + /* rpma_flush_delete() unit tests */ + cmocka_unit_test(delete__apm_dereg_E_PROVIDER), + cmocka_unit_test(delete__apm_munmap_E_INVAL), }; return cmocka_run_group_tests(tests, NULL, NULL);