1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 */ 4 5 #include "spdk/stdinc.h" 6 #include "spdk_internal/cunit.h" 7 #include "spdk_internal/mock.h" 8 #include "common/lib/test_env.c" 9 #include "rdma/common.c" 10 11 DEFINE_STUB(spdk_mem_map_alloc, struct spdk_mem_map *, (uint64_t default_translation, 12 const struct spdk_mem_map_ops *ops, void *cb_ctx), NULL); 13 DEFINE_STUB_V(spdk_mem_map_free, (struct spdk_mem_map **pmap)); 14 DEFINE_STUB(spdk_mem_map_set_translation, int, (struct spdk_mem_map *map, uint64_t vaddr, 15 uint64_t size, uint64_t translation), 0); 16 DEFINE_STUB(spdk_mem_map_clear_translation, int, (struct spdk_mem_map *map, uint64_t vaddr, 17 uint64_t size), 0); 18 DEFINE_STUB(spdk_mem_map_translate, uint64_t, (const struct spdk_mem_map *map, uint64_t vaddr, 19 uint64_t *size), 0); 20 21 struct ut_rdma_device { 22 struct ibv_context *context; 23 bool removed; 24 TAILQ_ENTRY(ut_rdma_device) tailq; 25 }; 26 27 static TAILQ_HEAD(, ut_rdma_device) g_ut_dev_list = TAILQ_HEAD_INITIALIZER(g_ut_dev_list); 28 29 struct ibv_context ** 30 rdma_get_devices(int *num_devices) 31 { 32 struct ibv_context **ctx_list; 33 struct ut_rdma_device *ut_dev; 34 int num_ut_devs = 0; 35 int i = 0; 36 37 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 38 if (!ut_dev->removed) { 39 num_ut_devs++; 40 } 41 } 42 43 ctx_list = malloc(sizeof(*ctx_list) * (num_ut_devs + 1)); 44 SPDK_CU_ASSERT_FATAL(ctx_list); 45 46 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 47 if (!ut_dev->removed) { 48 ctx_list[i++] = ut_dev->context; 49 } 50 } 51 ctx_list[i] = NULL; 52 53 if (num_devices) { 54 *num_devices = num_ut_devs; 55 } 56 57 return ctx_list; 58 } 59 60 void 61 rdma_free_devices(struct ibv_context **list) 62 { 63 free(list); 64 } 65 66 struct ibv_pd * 67 ibv_alloc_pd(struct ibv_context *context) 68 { 69 struct ibv_pd *pd; 70 struct ut_rdma_device *ut_dev; 71 72 TAILQ_FOREACH(ut_dev, &g_ut_dev_list, tailq) { 73 if (ut_dev->context == context && !ut_dev->removed) { 74 break; 75 } 76 } 77 78 if (!ut_dev) { 79 return NULL; 80 } 81 82 pd = calloc(1, sizeof(*pd)); 83 SPDK_CU_ASSERT_FATAL(pd); 84 85 pd->context = context; 86 87 return pd; 88 } 89 90 int 91 ibv_dealloc_pd(struct ibv_pd *pd) 92 { 93 free(pd); 94 95 return 0; 96 } 97 98 static struct ut_rdma_device * 99 ut_rdma_add_dev(struct ibv_context *context) 100 { 101 struct ut_rdma_device *ut_dev; 102 103 ut_dev = calloc(1, sizeof(*ut_dev)); 104 if (!ut_dev) { 105 return NULL; 106 } 107 108 ut_dev->context = context; 109 TAILQ_INSERT_TAIL(&g_ut_dev_list, ut_dev, tailq); 110 111 return ut_dev; 112 } 113 114 static void 115 ut_rdma_remove_dev(struct ut_rdma_device *ut_dev) 116 { 117 TAILQ_REMOVE(&g_ut_dev_list, ut_dev, tailq); 118 free(ut_dev); 119 } 120 121 static struct spdk_rdma_device * 122 _rdma_get_dev(struct ibv_context *context) 123 { 124 struct spdk_rdma_device *dev; 125 126 TAILQ_FOREACH(dev, &g_dev_list, tailq) { 127 if (dev->context == context) { 128 break; 129 } 130 } 131 132 return dev; 133 } 134 135 static void 136 test_spdk_rdma_pd(void) 137 { 138 struct ut_rdma_device *ut_dev0, *ut_dev1, *ut_dev2; 139 struct ibv_pd *pd1, *pd1_1, *pd2; 140 141 ut_dev0 = ut_rdma_add_dev((struct ibv_context *)0xface); 142 SPDK_CU_ASSERT_FATAL(ut_dev0 != NULL); 143 144 ut_dev1 = ut_rdma_add_dev((struct ibv_context *)0xc0ffee); 145 SPDK_CU_ASSERT_FATAL(ut_dev1 != NULL); 146 147 ut_dev2 = ut_rdma_add_dev((struct ibv_context *)0xf00d); 148 SPDK_CU_ASSERT_FATAL(ut_dev2 != NULL); 149 150 /* There are ut_dev0 and ut_dev1. */ 151 ut_dev2->removed = true; 152 153 /* Call spdk_rdma_get_pd() to non-existent ut_dev2. */ 154 pd2 = spdk_rdma_get_pd(ut_dev2->context); 155 156 /* Then, spdk_rdma_get_pd() should return NULL and g_dev_list should have dev0 and dev1. */ 157 CU_ASSERT(pd2 == NULL); 158 CU_ASSERT(_rdma_get_dev(ut_dev0->context) != NULL); 159 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 160 CU_ASSERT(_rdma_get_dev(ut_dev2->context) == NULL); 161 162 /* Remove ut_dev0 and add ut_dev2. */ 163 ut_dev0->removed = true; 164 ut_dev2->removed = false; 165 166 /* Call spdk_rdma_get_pd() to ut_dev1. */ 167 pd1 = spdk_rdma_get_pd(ut_dev1->context); 168 169 /* Then, spdk_rdma_get_pd() should return pd1 and g_dev_list should have dev1 and dev2. */ 170 CU_ASSERT(pd1 != NULL); 171 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 172 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 173 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 174 175 /* Remove ut_dev1. */ 176 ut_dev1->removed = true; 177 178 /* Call spdk_rdma_get_pd() again to ut_dev1 which does not exist anymore. */ 179 pd1_1 = spdk_rdma_get_pd(ut_dev1->context); 180 181 /* Then, spdk_rdma_get_pd() should return NULL and g_dev_list should still have dev1. */ 182 CU_ASSERT(pd1_1 == NULL); 183 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 184 CU_ASSERT(_rdma_get_dev(ut_dev1->context) != NULL); 185 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 186 187 /* Call spdk_rdma_put_pd() to pd1. */ 188 spdk_rdma_put_pd(pd1); 189 190 /* Then, dev1 should be removed from g_dev_list. */ 191 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 192 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL); 193 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 194 195 /* Call spdk_rdma_get_pd() to ut_dev2. */ 196 pd2 = spdk_rdma_get_pd(ut_dev2->context); 197 198 /* spdk_rdma_get_pd() should succeed and g_dev_list should still have dev2 199 * even after spdk_rdma_put_pd() is called to pd2. 200 */ 201 CU_ASSERT(pd2 != NULL); 202 203 spdk_rdma_put_pd(pd2); 204 205 CU_ASSERT(_rdma_get_dev(ut_dev0->context) == NULL); 206 CU_ASSERT(_rdma_get_dev(ut_dev1->context) == NULL); 207 CU_ASSERT(_rdma_get_dev(ut_dev2->context) != NULL); 208 209 _rdma_fini(); 210 211 ut_rdma_remove_dev(ut_dev0); 212 ut_rdma_remove_dev(ut_dev1); 213 ut_rdma_remove_dev(ut_dev2); 214 } 215 216 int 217 main(int argc, char **argv) 218 { 219 CU_pSuite suite = NULL; 220 unsigned int num_failures; 221 222 CU_initialize_registry(); 223 224 suite = CU_add_suite("rdma_common", NULL, NULL); 225 CU_ADD_TEST(suite, test_spdk_rdma_pd); 226 227 num_failures = spdk_ut_run_tests(argc, argv, NULL); 228 CU_cleanup_registry(); 229 return num_failures; 230 } 231