diff options
Diffstat (limited to 'src/spdk/test/common/lib')
-rw-r--r-- | src/spdk/test/common/lib/nvme/common_stubs.h | 117 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_env.c | 637 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_rdma.c | 49 | ||||
-rw-r--r-- | src/spdk/test/common/lib/test_sock.c | 70 | ||||
-rw-r--r-- | src/spdk/test/common/lib/ut_multithread.c | 214 |
5 files changed, 1087 insertions, 0 deletions
diff --git a/src/spdk/test/common/lib/nvme/common_stubs.h b/src/spdk/test/common/lib/nvme/common_stubs.h new file mode 100644 index 000000000..1dc22a162 --- /dev/null +++ b/src/spdk/test/common/lib/nvme/common_stubs.h @@ -0,0 +1,117 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "common/lib/test_env.c" + +const char * +spdk_nvme_transport_id_trtype_str(enum spdk_nvme_transport_type trtype) +{ + switch (trtype) { + case SPDK_NVME_TRANSPORT_PCIE: + return "PCIe"; + case SPDK_NVME_TRANSPORT_RDMA: + return "RDMA"; + case SPDK_NVME_TRANSPORT_FC: + return "FC"; + default: + return NULL; + } +} + +int +spdk_nvme_transport_id_populate_trstring(struct spdk_nvme_transport_id *trid, const char *trstring) +{ + int len, i; + + if (trstring == NULL) { + return -EINVAL; + } + + len = strnlen(trstring, SPDK_NVMF_TRSTRING_MAX_LEN); + if (len == SPDK_NVMF_TRSTRING_MAX_LEN) { + return -EINVAL; + } + + /* cast official trstring to uppercase version of input. */ + for (i = 0; i < len; i++) { + trid->trstring[i] = toupper(trstring[i]); + } + return 0; +} + +DEFINE_STUB(nvme_request_check_timeout, int, (struct nvme_request *req, uint16_t cid, + struct spdk_nvme_ctrlr_process *active_proc, uint64_t now_tick), 0); +DEFINE_STUB_V(nvme_ctrlr_destruct_finish, (struct spdk_nvme_ctrlr *ctrlr)); +DEFINE_STUB(nvme_ctrlr_construct, int, (struct spdk_nvme_ctrlr *ctrlr), 0); +DEFINE_STUB_V(nvme_ctrlr_destruct, (struct spdk_nvme_ctrlr *ctrlr)); +DEFINE_STUB_V(nvme_ctrlr_init_cap, (struct spdk_nvme_ctrlr *ctrlr, + const union spdk_nvme_cap_register *cap, + const union spdk_nvme_vs_register *vs)); +DEFINE_STUB(nvme_ctrlr_get_vs, int, (struct spdk_nvme_ctrlr *ctrlr, + union spdk_nvme_vs_register *vs), 0); +DEFINE_STUB(nvme_ctrlr_get_cap, int, (struct spdk_nvme_ctrlr *ctrlr, + union spdk_nvme_cap_register *cap), 0); +DEFINE_STUB(nvme_qpair_init, int, (struct spdk_nvme_qpair *qpair, uint16_t id, + struct spdk_nvme_ctrlr *ctrlr, + enum spdk_nvme_qprio qprio, + uint32_t num_requests), 0); +DEFINE_STUB_V(nvme_qpair_deinit, (struct spdk_nvme_qpair *qpair)); +DEFINE_STUB_V(spdk_nvme_transport_register, (const struct spdk_nvme_transport_ops *ops)); +DEFINE_STUB(nvme_transport_ctrlr_connect_qpair, int, (struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair), 0); +DEFINE_STUB(nvme_ctrlr_get_current_process, struct spdk_nvme_ctrlr_process *, + (struct spdk_nvme_ctrlr *ctrlr), (struct spdk_nvme_ctrlr_process *)(uintptr_t)0x1); +DEFINE_STUB(nvme_ctrlr_add_process, int, (struct spdk_nvme_ctrlr *ctrlr, void *devhandle), 0); +DEFINE_STUB_V(spdk_nvme_trid_populate_transport, (struct spdk_nvme_transport_id *trid, + enum spdk_nvme_transport_type trtype)); +DEFINE_STUB(nvme_get_transport, const struct spdk_nvme_transport *, (const char *transport_name), + NULL); +DEFINE_STUB(spdk_nvme_qpair_process_completions, int32_t, (struct spdk_nvme_qpair *qpair, + uint32_t max_completions), 0); + +/* Fabric transports only */ +DEFINE_STUB_V(nvme_ctrlr_disconnect_qpair, (struct spdk_nvme_qpair *qpair)); +DEFINE_STUB(nvme_fabric_ctrlr_set_reg_4, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint32_t value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_set_reg_8, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint64_t value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_get_reg_4, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint32_t *value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_get_reg_8, int, (struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, + uint64_t *value), 0); +DEFINE_STUB(nvme_fabric_ctrlr_scan, int, (struct spdk_nvme_probe_ctx *probe_ctx, + bool direct_connect), 0); +DEFINE_STUB(nvme_fabric_qpair_connect, int, (struct spdk_nvme_qpair *qpair, uint32_t num_entries), + 0); +DEFINE_STUB_V(nvme_transport_ctrlr_disconnect_qpair, (struct spdk_nvme_ctrlr *ctrlr, + struct spdk_nvme_qpair *qpair)); +DEFINE_STUB(nvme_poll_group_disconnect_qpair, int, (struct spdk_nvme_qpair *qpair), 0); diff --git a/src/spdk/test/common/lib/test_env.c b/src/spdk/test/common/lib/test_env.c new file mode 100644 index 000000000..5e2912b5c --- /dev/null +++ b/src/spdk/test/common/lib/test_env.c @@ -0,0 +1,637 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/mock.h" + +#include "spdk/env.h" +#include "spdk/queue.h" +#include "spdk/util.h" + +static uint32_t g_ut_num_cores; +static bool *g_ut_cores; + +void allocate_cores(uint32_t num_cores); +void free_cores(void); + +DEFINE_STUB(spdk_process_is_primary, bool, (void), true) +DEFINE_STUB(spdk_memzone_lookup, void *, (const char *name), NULL) +DEFINE_STUB_V(spdk_pci_driver_register, (const char *name, struct spdk_pci_id *id_table, + uint32_t flags)); +DEFINE_STUB(spdk_pci_nvme_get_driver, struct spdk_pci_driver *, (void), NULL) +DEFINE_STUB(spdk_pci_ioat_get_driver, struct spdk_pci_driver *, (void), NULL) +DEFINE_STUB(spdk_pci_virtio_get_driver, struct spdk_pci_driver *, (void), NULL) + +void +allocate_cores(uint32_t num_cores) +{ + uint32_t i; + + g_ut_num_cores = num_cores; + + g_ut_cores = calloc(num_cores, sizeof(bool)); + assert(g_ut_cores != NULL); + + for (i = 0; i < num_cores; i++) { + g_ut_cores[i] = true; + } +} + +void +free_cores(void) +{ + free(g_ut_cores); + g_ut_cores = NULL; + g_ut_num_cores = 0; +} + +static uint32_t +ut_get_next_core(uint32_t i) +{ + i++; + + while (i < g_ut_num_cores) { + if (!g_ut_cores[i]) { + i++; + continue; + } + break; + } + + if (i < g_ut_num_cores) { + return i; + } else { + return UINT32_MAX; + } +} + +uint32_t +spdk_env_get_first_core(void) +{ + return ut_get_next_core(-1); +} + +uint32_t +spdk_env_get_next_core(uint32_t prev_core) +{ + return ut_get_next_core(prev_core); +} + +uint32_t +spdk_env_get_core_count(void) +{ + return g_ut_num_cores; +} + +uint32_t +spdk_env_get_last_core(void) +{ + uint32_t i; + uint32_t last_core = UINT32_MAX; + + SPDK_ENV_FOREACH_CORE(i) { + last_core = i; + } + + return last_core; +} + +DEFINE_RETURN_MOCK(spdk_env_get_current_core, uint32_t); +uint32_t +spdk_env_get_current_core(void) +{ + HANDLE_RETURN_MOCK(spdk_env_get_current_core); + + return UINT32_MAX; +} + +DEFINE_RETURN_MOCK(spdk_env_get_socket_id, uint32_t); +uint32_t +spdk_env_get_socket_id(uint32_t core) +{ + HANDLE_RETURN_MOCK(spdk_env_get_socket_id); + + return SPDK_ENV_SOCKET_ID_ANY; +} + +/* + * These mocks don't use the DEFINE_STUB macros because + * their default implementation is more complex. + */ + +DEFINE_RETURN_MOCK(spdk_memzone_reserve, void *); +void * +spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) +{ + HANDLE_RETURN_MOCK(spdk_memzone_reserve); + + return malloc(len); +} + +DEFINE_RETURN_MOCK(spdk_memzone_reserve_aligned, void *); +void * +spdk_memzone_reserve_aligned(const char *name, size_t len, int socket_id, + unsigned flags, unsigned align) +{ + HANDLE_RETURN_MOCK(spdk_memzone_reserve_aligned); + + return malloc(len); +} + +DEFINE_RETURN_MOCK(spdk_malloc, void *); +void * +spdk_malloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) +{ + HANDLE_RETURN_MOCK(spdk_malloc); + + void *buf = NULL; + + if (align == 0) { + align = 8; + } + + if (posix_memalign(&buf, align, size)) { + return NULL; + } + if (phys_addr) { + *phys_addr = (uint64_t)buf; + } + + return buf; +} + +DEFINE_RETURN_MOCK(spdk_zmalloc, void *); +void * +spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) +{ + HANDLE_RETURN_MOCK(spdk_zmalloc); + + void *buf = spdk_malloc(size, align, phys_addr, -1, 1); + + if (buf != NULL) { + memset(buf, 0, size); + } + return buf; +} + +DEFINE_RETURN_MOCK(spdk_dma_malloc, void *); +void * +spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_malloc); + + return spdk_malloc(size, align, phys_addr, -1, 1); +} + +DEFINE_RETURN_MOCK(spdk_realloc, void *); +void * +spdk_realloc(void *buf, size_t size, size_t align) +{ + HANDLE_RETURN_MOCK(spdk_realloc); + + return realloc(buf, size); +} + +DEFINE_RETURN_MOCK(spdk_dma_zmalloc, void *); +void * +spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_zmalloc); + + return spdk_zmalloc(size, align, phys_addr, -1, 1); +} + +DEFINE_RETURN_MOCK(spdk_dma_malloc_socket, void *); +void * +spdk_dma_malloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) +{ + HANDLE_RETURN_MOCK(spdk_dma_malloc_socket); + + return spdk_dma_malloc(size, align, phys_addr); +} + +DEFINE_RETURN_MOCK(spdk_dma_zmalloc_socket, void *); +void * +spdk_dma_zmalloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) +{ + HANDLE_RETURN_MOCK(spdk_dma_zmalloc_socket); + + return spdk_dma_zmalloc(size, align, phys_addr); +} + +DEFINE_RETURN_MOCK(spdk_dma_realloc, void *); +void * +spdk_dma_realloc(void *buf, size_t size, size_t align, uint64_t *phys_addr) +{ + HANDLE_RETURN_MOCK(spdk_dma_realloc); + + return realloc(buf, size); +} + +void +spdk_free(void *buf) +{ + /* fix for false-positives in *certain* static analysis tools. */ + assert((uintptr_t)buf != UINTPTR_MAX); + free(buf); +} + +void +spdk_dma_free(void *buf) +{ + return spdk_free(buf); +} + +#ifndef UNIT_TEST_NO_VTOPHYS +DEFINE_RETURN_MOCK(spdk_vtophys, uint64_t); +uint64_t +spdk_vtophys(void *buf, uint64_t *size) +{ + HANDLE_RETURN_MOCK(spdk_vtophys); + + return (uintptr_t)buf; +} +#endif + +void +spdk_memzone_dump(FILE *f) +{ + return; +} + +DEFINE_RETURN_MOCK(spdk_memzone_free, int); +int +spdk_memzone_free(const char *name) +{ + HANDLE_RETURN_MOCK(spdk_memzone_free); + + return 0; +} + +struct test_mempool { + size_t count; + size_t ele_size; +}; + +DEFINE_RETURN_MOCK(spdk_mempool_create, struct spdk_mempool *); +struct spdk_mempool * +spdk_mempool_create(const char *name, size_t count, + size_t ele_size, size_t cache_size, int socket_id) +{ + struct test_mempool *mp; + + HANDLE_RETURN_MOCK(spdk_mempool_create); + + mp = calloc(1, sizeof(*mp)); + if (mp == NULL) { + return NULL; + } + + mp->count = count; + mp->ele_size = ele_size; + + return (struct spdk_mempool *)mp; +} + +void +spdk_mempool_free(struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + free(mp); +} + +DEFINE_RETURN_MOCK(spdk_mempool_get, void *); +void * +spdk_mempool_get(struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + size_t ele_size = 0x10000; + void *buf; + + HANDLE_RETURN_MOCK(spdk_mempool_get); + + if (mp && mp->count == 0) { + return NULL; + } + + if (mp) { + ele_size = mp->ele_size; + } + + if (posix_memalign(&buf, 64, spdk_align32pow2(ele_size))) { + return NULL; + } else { + if (mp) { + mp->count--; + } + return buf; + } +} + +int +spdk_mempool_get_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) +{ + for (size_t i = 0; i < count; i++) { + ele_arr[i] = spdk_mempool_get(mp); + if (ele_arr[i] == NULL) { + return -1; + } + } + return 0; +} + +void +spdk_mempool_put(struct spdk_mempool *_mp, void *ele) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + if (mp) { + mp->count++; + } + free(ele); +} + +void +spdk_mempool_put_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) +{ + for (size_t i = 0; i < count; i++) { + spdk_mempool_put(mp, ele_arr[i]); + } +} + +DEFINE_RETURN_MOCK(spdk_mempool_count, size_t); +size_t +spdk_mempool_count(const struct spdk_mempool *_mp) +{ + struct test_mempool *mp = (struct test_mempool *)_mp; + + HANDLE_RETURN_MOCK(spdk_mempool_count); + + if (mp) { + return mp->count; + } else { + return 1024; + } +} + +struct spdk_ring_ele { + void *ele; + TAILQ_ENTRY(spdk_ring_ele) link; +}; + +struct spdk_ring { + TAILQ_HEAD(, spdk_ring_ele) elements; + pthread_mutex_t lock; + size_t count; +}; + +DEFINE_RETURN_MOCK(spdk_ring_create, struct spdk_ring *); +struct spdk_ring * +spdk_ring_create(enum spdk_ring_type type, size_t count, int socket_id) +{ + struct spdk_ring *ring; + + HANDLE_RETURN_MOCK(spdk_ring_create); + + ring = calloc(1, sizeof(*ring)); + if (!ring) { + return NULL; + } + + if (pthread_mutex_init(&ring->lock, NULL)) { + free(ring); + return NULL; + } + + TAILQ_INIT(&ring->elements); + return ring; +} + +void +spdk_ring_free(struct spdk_ring *ring) +{ + struct spdk_ring_ele *ele, *tmp; + + if (!ring) { + return; + } + + TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { + free(ele); + } + + pthread_mutex_destroy(&ring->lock); + free(ring); +} + +DEFINE_RETURN_MOCK(spdk_ring_enqueue, size_t); +size_t +spdk_ring_enqueue(struct spdk_ring *ring, void **objs, size_t count, + size_t *free_space) +{ + struct spdk_ring_ele *ele; + size_t i; + + HANDLE_RETURN_MOCK(spdk_ring_enqueue); + + pthread_mutex_lock(&ring->lock); + + for (i = 0; i < count; i++) { + ele = calloc(1, sizeof(*ele)); + if (!ele) { + break; + } + + ele->ele = objs[i]; + TAILQ_INSERT_TAIL(&ring->elements, ele, link); + ring->count++; + } + + pthread_mutex_unlock(&ring->lock); + return i; +} + +DEFINE_RETURN_MOCK(spdk_ring_dequeue, size_t); +size_t +spdk_ring_dequeue(struct spdk_ring *ring, void **objs, size_t count) +{ + struct spdk_ring_ele *ele, *tmp; + size_t i = 0; + + HANDLE_RETURN_MOCK(spdk_ring_dequeue); + + if (count == 0) { + return 0; + } + + pthread_mutex_lock(&ring->lock); + + TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { + TAILQ_REMOVE(&ring->elements, ele, link); + ring->count--; + objs[i] = ele->ele; + free(ele); + i++; + if (i >= count) { + break; + } + } + + pthread_mutex_unlock(&ring->lock); + return i; + +} + + +DEFINE_RETURN_MOCK(spdk_ring_count, size_t); +size_t +spdk_ring_count(struct spdk_ring *ring) +{ + HANDLE_RETURN_MOCK(spdk_ring_count); + return ring->count; +} + +DEFINE_RETURN_MOCK(spdk_get_ticks, uint64_t); +uint64_t +spdk_get_ticks(void) +{ + HANDLE_RETURN_MOCK(spdk_get_ticks); + + return ut_spdk_get_ticks; +} + +DEFINE_RETURN_MOCK(spdk_get_ticks_hz, uint64_t); +uint64_t +spdk_get_ticks_hz(void) +{ + HANDLE_RETURN_MOCK(spdk_get_ticks_hz); + + return 1000000; +} + +void +spdk_delay_us(unsigned int us) +{ + /* spdk_get_ticks_hz is 1000000, meaning 1 tick per us. */ + ut_spdk_get_ticks += us; +} + +#ifndef UNIT_TEST_NO_PCI_ADDR +DEFINE_RETURN_MOCK(spdk_pci_addr_parse, int); +int +spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf) +{ + unsigned domain, bus, dev, func; + + HANDLE_RETURN_MOCK(spdk_pci_addr_parse); + + if (addr == NULL || bdf == NULL) { + return -EINVAL; + } + + if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) || + (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) { + /* Matched a full address - all variables are initialized */ + } else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) { + func = 0; + } else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) || + (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) { + domain = 0; + } else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) || + (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) { + domain = 0; + func = 0; + } else { + return -EINVAL; + } + + if (bus > 0xFF || dev > 0x1F || func > 7) { + return -EINVAL; + } + + addr->domain = domain; + addr->bus = bus; + addr->dev = dev; + addr->func = func; + + return 0; +} + +DEFINE_RETURN_MOCK(spdk_pci_addr_fmt, int); +int +spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr) +{ + int rc; + + HANDLE_RETURN_MOCK(spdk_pci_addr_fmt); + + rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x", + addr->domain, addr->bus, + addr->dev, addr->func); + + if (rc > 0 && (size_t)rc < sz) { + return 0; + } + + return -1; +} + +DEFINE_RETURN_MOCK(spdk_pci_addr_compare, int); +int +spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2) +{ + HANDLE_RETURN_MOCK(spdk_pci_addr_compare); + + if (a1->domain > a2->domain) { + return 1; + } else if (a1->domain < a2->domain) { + return -1; + } else if (a1->bus > a2->bus) { + return 1; + } else if (a1->bus < a2->bus) { + return -1; + } else if (a1->dev > a2->dev) { + return 1; + } else if (a1->dev < a2->dev) { + return -1; + } else if (a1->func > a2->func) { + return 1; + } else if (a1->func < a2->func) { + return -1; + } + + return 0; +} +#endif diff --git a/src/spdk/test/common/lib/test_rdma.c b/src/spdk/test/common/lib/test_rdma.c new file mode 100644 index 000000000..109862fe6 --- /dev/null +++ b/src/spdk/test/common/lib/test_rdma.c @@ -0,0 +1,49 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/rdma.h" +#include "spdk_internal/mock.h" + +DEFINE_STUB(spdk_rdma_qp_create, struct spdk_rdma_qp *, (struct rdma_cm_id *cm_id, + struct spdk_rdma_qp_init_attr *qp_attr), NULL); +DEFINE_STUB(spdk_rdma_qp_accept, int, (struct spdk_rdma_qp *spdk_rdma_qp, + struct rdma_conn_param *conn_param), 0); +DEFINE_STUB(spdk_rdma_qp_complete_connect, int, (struct spdk_rdma_qp *spdk_rdma_qp), 0); +DEFINE_STUB_V(spdk_rdma_qp_destroy, (struct spdk_rdma_qp *spdk_rdma_qp)); +DEFINE_STUB(spdk_rdma_qp_disconnect, int, (struct spdk_rdma_qp *spdk_rdma_qp), 0); +DEFINE_STUB(spdk_rdma_qp_queue_send_wrs, bool, (struct spdk_rdma_qp *spdk_rdma_qp, + struct ibv_send_wr *first), true); +DEFINE_STUB(spdk_rdma_qp_flush_send_wrs, int, (struct spdk_rdma_qp *spdk_rdma_qp, + struct ibv_send_wr **bad_wr), 0); diff --git a/src/spdk/test/common/lib/test_sock.c b/src/spdk/test/common/lib/test_sock.c new file mode 100644 index 000000000..d2c83b732 --- /dev/null +++ b/src/spdk/test/common/lib/test_sock.c @@ -0,0 +1,70 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_internal/sock.h" +#include "spdk_internal/mock.h" + +DEFINE_STUB(spdk_sock_getaddr, int, (struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, + char *caddr, int clen, uint16_t *cport), 0); +DEFINE_STUB(spdk_sock_connect, struct spdk_sock *, (const char *ip, int port, char *impl_name), + NULL); +DEFINE_STUB(spdk_sock_connect_ext, struct spdk_sock *, (const char *ip, int port, char *impl_name, + struct spdk_sock_opts *opts), NULL); +DEFINE_STUB(spdk_sock_listen, struct spdk_sock *, (const char *ip, int port, char *impl_name), + NULL); +DEFINE_STUB(spdk_sock_listen_ext, struct spdk_sock *, (const char *ip, int port, char *impl_name, + struct spdk_sock_opts *opts), NULL); +DEFINE_STUB_V(spdk_sock_get_default_opts, (struct spdk_sock_opts *opts)); +DEFINE_STUB(spdk_sock_accept, struct spdk_sock *, (struct spdk_sock *sock), NULL); +DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **sock), 0); +DEFINE_STUB(spdk_sock_recv, ssize_t, (struct spdk_sock *sock, void *buf, size_t len), 0); +DEFINE_STUB(spdk_sock_writev, ssize_t, (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); +DEFINE_STUB(spdk_sock_readv, ssize_t, (struct spdk_sock *sock, struct iovec *iov, int iovcnt), 0); +DEFINE_STUB(spdk_sock_set_recvlowat, int, (struct spdk_sock *sock, int nbytes), 0); +DEFINE_STUB(spdk_sock_set_recvbuf, int, (struct spdk_sock *sock, int sz), 0); +DEFINE_STUB(spdk_sock_set_sendbuf, int, (struct spdk_sock *sock, int sz), 0); +DEFINE_STUB_V(spdk_sock_writev_async, (struct spdk_sock *sock, struct spdk_sock_request *req)); +DEFINE_STUB(spdk_sock_flush, int, (struct spdk_sock *sock), 0); +DEFINE_STUB(spdk_sock_is_ipv6, bool, (struct spdk_sock *sock), false); +DEFINE_STUB(spdk_sock_is_ipv4, bool, (struct spdk_sock *sock), true); +DEFINE_STUB(spdk_sock_is_connected, bool, (struct spdk_sock *sock), true); +DEFINE_STUB(spdk_sock_group_create, struct spdk_sock_group *, (void *ctx), NULL); +DEFINE_STUB(spdk_sock_group_add_sock, int, (struct spdk_sock_group *group, struct spdk_sock *sock, + spdk_sock_cb cb_fn, void *cb_arg), 0); +DEFINE_STUB(spdk_sock_group_remove_sock, int, (struct spdk_sock_group *group, + struct spdk_sock *sock), 0); +DEFINE_STUB(spdk_sock_group_poll, int, (struct spdk_sock_group *group), 0); +DEFINE_STUB(spdk_sock_group_poll_count, int, (struct spdk_sock_group *group, int max_events), 0); +DEFINE_STUB(spdk_sock_group_close, int, (struct spdk_sock_group **group), 0); diff --git a/src/spdk/test/common/lib/ut_multithread.c b/src/spdk/test/common/lib/ut_multithread.c new file mode 100644 index 000000000..30b78f74d --- /dev/null +++ b/src/spdk/test/common/lib/ut_multithread.c @@ -0,0 +1,214 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk_cunit.h" +#include "spdk/thread.h" +#include "spdk_internal/mock.h" +#include "spdk_internal/thread.h" + +#include "common/lib/test_env.c" + +static uint32_t g_ut_num_threads; + +int allocate_threads(int num_threads); +void free_threads(void); +void poll_threads(void); +bool poll_thread(uintptr_t thread_id); +bool poll_thread_times(uintptr_t thread_id, uint32_t max_polls); + +struct ut_msg { + spdk_msg_fn fn; + void *ctx; + TAILQ_ENTRY(ut_msg) link; +}; + +struct ut_thread { + struct spdk_thread *thread; + struct spdk_io_channel *ch; +}; + +struct ut_thread *g_ut_threads; + +#define INVALID_THREAD 0x1000 + +static uint64_t g_ut_thread_id = INVALID_THREAD; + +static void +set_thread(uintptr_t thread_id) +{ + g_ut_thread_id = thread_id; + if (thread_id == INVALID_THREAD) { + spdk_set_thread(NULL); + } else { + spdk_set_thread(g_ut_threads[thread_id].thread); + } + +} + +int +allocate_threads(int num_threads) +{ + struct spdk_thread *thread; + uint32_t i; + + spdk_thread_lib_init(NULL, 0); + + g_ut_num_threads = num_threads; + + g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads)); + assert(g_ut_threads != NULL); + + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = spdk_thread_create(NULL, NULL); + assert(thread != NULL); + g_ut_threads[i].thread = thread; + } + + set_thread(INVALID_THREAD); + return 0; +} + +void +free_threads(void) +{ + uint32_t i, num_threads; + struct spdk_thread *thread; + + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = g_ut_threads[i].thread; + spdk_thread_exit(thread); + } + + num_threads = g_ut_num_threads; + + while (num_threads != 0) { + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = g_ut_threads[i].thread; + if (thread == NULL) { + continue; + } + + if (spdk_thread_is_exited(thread)) { + g_ut_threads[i].thread = NULL; + num_threads--; + spdk_thread_destroy(thread); + } else { + spdk_thread_poll(thread, 0, 0); + } + } + } + + g_ut_num_threads = 0; + free(g_ut_threads); + g_ut_threads = NULL; + + spdk_thread_lib_fini(); +} + +bool +poll_thread_times(uintptr_t thread_id, uint32_t max_polls) +{ + bool busy = false; + struct ut_thread *thread = &g_ut_threads[thread_id]; + uintptr_t original_thread_id; + uint32_t polls_executed = 0; + uint64_t now; + + if (max_polls == 0) { + /* If max_polls is set to 0, + * poll until no operation is pending. */ + return poll_thread(thread_id); + } + assert(thread_id != (uintptr_t)INVALID_THREAD); + assert(thread_id < g_ut_num_threads); + + original_thread_id = g_ut_thread_id; + set_thread(INVALID_THREAD); + + now = spdk_get_ticks(); + while (polls_executed < max_polls) { + if (spdk_thread_poll(thread->thread, 1, now) > 0) { + busy = true; + } + now = spdk_thread_get_last_tsc(thread->thread); + polls_executed++; + } + + set_thread(original_thread_id); + + return busy; +} + +bool +poll_thread(uintptr_t thread_id) +{ + bool busy = false; + struct ut_thread *thread = &g_ut_threads[thread_id]; + uintptr_t original_thread_id; + uint64_t now; + + assert(thread_id != (uintptr_t)INVALID_THREAD); + assert(thread_id < g_ut_num_threads); + + original_thread_id = g_ut_thread_id; + set_thread(INVALID_THREAD); + + now = spdk_get_ticks(); + while (spdk_thread_poll(thread->thread, 0, now) > 0) { + now = spdk_thread_get_last_tsc(thread->thread); + busy = true; + } + + set_thread(original_thread_id); + + return busy; +} + +void +poll_threads(void) +{ + while (true) { + bool busy = false; + + for (uint32_t i = 0; i < g_ut_num_threads; i++) { + busy = busy || poll_thread(i); + } + + if (!busy) { + break; + } + } +} |