Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "env_dpdk/memory.c"
7 : :
8 : : #define UNIT_TEST_NO_VTOPHYS
9 : : #include "common/lib/test_env.c"
10 : : #include "spdk_internal/cunit.h"
11 : :
12 : : #include "spdk/bit_array.h"
13 : :
14 : : #define PAGE_ARRAY_SIZE (100)
15 : : static struct spdk_bit_array *g_page_array;
16 : : static void *g_vaddr_to_fail = (void *)UINT64_MAX;
17 : :
18 [ - + # # : 22 : DEFINE_STUB(rte_memseg_contig_walk, int, (rte_memseg_contig_walk_t func, void *arg), 0);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
19 [ # # # # : 0 : DEFINE_STUB(rte_mem_virt2memseg, struct rte_memseg *,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
20 : : (const void *virt, const struct rte_memseg_list *msl), NULL);
21 [ # # # # : 0 : DEFINE_STUB(spdk_env_dpdk_external_init, bool, (void), true);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
22 [ - + # # : 22 : DEFINE_STUB(rte_mem_event_callback_register, int,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
23 : : (const char *name, rte_mem_event_callback_t clb, void *arg), 0);
24 [ # # # # : 0 : DEFINE_STUB(rte_mem_virt2iova, rte_iova_t, (const void *virtaddr), 0);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
25 [ # # # # : 0 : DEFINE_STUB(rte_eal_iova_mode, enum rte_iova_mode, (void), RTE_IOVA_VA);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
26 [ # # # # : 0 : DEFINE_STUB(rte_vfio_is_enabled, int, (const char *modname), 0);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
27 [ # # # # : 0 : DEFINE_STUB(rte_vfio_noiommu_is_enabled, int, (void), 0);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
28 [ # # # # : 0 : DEFINE_STUB(rte_memseg_get_fd_thread_unsafe, int, (const struct rte_memseg *ms), 0);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
29 [ # # # # : 0 : DEFINE_STUB(rte_memseg_get_fd_offset_thread_unsafe, int,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
30 : : (const struct rte_memseg *ms, size_t *offset), 0);
31 [ # # # # : 0 : DEFINE_STUB(dpdk_pci_device_get_mem_resource, struct rte_mem_resource *,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
32 : : (struct rte_pci_device *dev, uint32_t bar), 0);
33 : :
34 : : static int
35 : 88 : test_mem_map_notify(void *cb_ctx, struct spdk_mem_map *map,
36 : : enum spdk_mem_map_notify_action action,
37 : : void *vaddr, size_t len)
38 : : {
39 : : uint32_t i, end;
40 : :
41 [ + + + - : 88 : SPDK_CU_ASSERT_FATAL(((uintptr_t)vaddr & MASK_2MB) == 0);
# # ]
42 [ + + + - : 88 : SPDK_CU_ASSERT_FATAL((len & MASK_2MB) == 0);
# # ]
43 : :
44 : : /*
45 : : * This is a test requirement - the bit array we use to verify
46 : : * pages are valid is only so large.
47 : : */
48 [ + + + - : 88 : SPDK_CU_ASSERT_FATAL((uintptr_t)vaddr < (VALUE_2MB * PAGE_ARRAY_SIZE));
# # ]
49 : :
50 [ + - ]: 88 : i = (uintptr_t)vaddr >> SHIFT_2MB;
51 [ + - ]: 88 : end = i + (len >> SHIFT_2MB);
52 [ + + ]: 264 : for (; i < end; i++) {
53 [ + + - ]: 176 : switch (action) {
54 : 84 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
55 : : /* This page should not already be registered */
56 [ + + # # ]: 88 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == false);
57 [ + + # # ]: 88 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_set(g_page_array, i) == 0);
58 : 88 : break;
59 : 84 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
60 [ + + # # ]: 88 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == true);
61 : 88 : spdk_bit_array_clear(g_page_array, i);
62 : 88 : break;
63 : 0 : default:
64 [ # # ]: 0 : SPDK_UNREACHABLE();
65 : : }
66 : 8 : }
67 : :
68 : 88 : return 0;
69 : : }
70 : :
71 : : static int
72 : 176 : test_mem_map_notify_fail(void *cb_ctx, struct spdk_mem_map *map,
73 : : enum spdk_mem_map_notify_action action, void *vaddr, size_t size)
74 : : {
75 : 176 : struct spdk_mem_map *reg_map = cb_ctx;
76 : : uint64_t reg_addr;
77 : 176 : uint64_t reg_size = size;
78 : :
79 [ + + + ]: 176 : switch (action) {
80 : 105 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
81 [ + + ]: 110 : if (vaddr == g_vaddr_to_fail) {
82 : : /* Test the error handling. */
83 : 22 : return -1;
84 : : }
85 : :
86 : 88 : CU_ASSERT(spdk_mem_map_set_translation(map, (uint64_t)vaddr, (uint64_t)size, (uint64_t)vaddr) == 0);
87 : :
88 : 88 : break;
89 : 63 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
90 : : /* validate the start address */
91 : 66 : reg_addr = spdk_mem_map_translate(map, (uint64_t)vaddr, ®_size);
92 : 66 : CU_ASSERT(reg_addr == (uint64_t)vaddr);
93 : 66 : spdk_mem_map_clear_translation(map, (uint64_t)vaddr, size);
94 : :
95 : : /* Clear the same region in the other mem_map to be able to
96 : : * verify that there was no memory left still registered after
97 : : * the mem_map creation failure.
98 : : */
99 : 66 : spdk_mem_map_clear_translation(reg_map, (uint64_t)vaddr, size);
100 : 66 : break;
101 : : }
102 : :
103 : 154 : return 0;
104 : 8 : }
105 : :
106 : : static int
107 : 792 : test_mem_map_notify_checklen(void *cb_ctx, struct spdk_mem_map *map,
108 : : enum spdk_mem_map_notify_action action, void *vaddr, size_t size)
109 : : {
110 : 792 : size_t *len_arr = cb_ctx;
111 : :
112 : : /*
113 : : * This is a test requirement - the len array we use to verify
114 : : * pages are valid is only so large.
115 : : */
116 [ + + + - : 792 : SPDK_CU_ASSERT_FATAL((uintptr_t)vaddr < (VALUE_2MB * PAGE_ARRAY_SIZE));
# # ]
117 : :
118 [ + + + ]: 792 : switch (action) {
119 : 378 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
120 [ - + - + : 396 : assert(size == len_arr[(uintptr_t)vaddr / VALUE_2MB]);
- + - + +
- # # ]
121 : 396 : break;
122 : 378 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
123 [ + - + - : 396 : CU_ASSERT(size == len_arr[(uintptr_t)vaddr / VALUE_2MB]);
+ - + - ]
124 : 396 : break;
125 : : }
126 : :
127 : 792 : return 0;
128 : : }
129 : :
130 : : static int
131 : 154 : test_check_regions_contiguous(uint64_t addr1, uint64_t addr2)
132 : : {
133 : 154 : return addr1 == addr2;
134 : : }
135 : :
136 : : const struct spdk_mem_map_ops test_mem_map_ops = {
137 : : .notify_cb = test_mem_map_notify,
138 : : .are_contiguous = test_check_regions_contiguous
139 : : };
140 : :
141 : : const struct spdk_mem_map_ops test_mem_map_ops_no_contig = {
142 : : .notify_cb = test_mem_map_notify,
143 : : .are_contiguous = NULL
144 : : };
145 : :
146 : : struct spdk_mem_map_ops test_map_ops_notify_fail = {
147 : : .notify_cb = test_mem_map_notify_fail,
148 : : .are_contiguous = NULL
149 : : };
150 : :
151 : : struct spdk_mem_map_ops test_map_ops_notify_checklen = {
152 : : .notify_cb = test_mem_map_notify_checklen,
153 : : .are_contiguous = NULL
154 : : };
155 : :
156 : : static void
157 : 22 : test_mem_map_alloc_free(void)
158 : : {
159 : 10 : struct spdk_mem_map *map, *failed_map;
160 : 22 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
161 : : int i;
162 : :
163 : 22 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
164 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
165 : 22 : spdk_mem_map_free(&map);
166 : 22 : CU_ASSERT(map == NULL);
167 : :
168 : 22 : map = spdk_mem_map_alloc(default_translation, NULL, NULL);
169 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
170 : :
171 : : /* Register some memory for the initial memory walk in
172 : : * spdk_mem_map_alloc(). We'll fail registering the last region
173 : : * and will check if the mem_map cleaned up all its previously
174 : : * initialized translations.
175 : : */
176 [ + + + - ]: 132 : for (i = 0; i < 5; i++) {
177 [ + - + - : 110 : spdk_mem_register((void *)(uintptr_t)(2 * i * VALUE_2MB), VALUE_2MB);
+ - ]
178 : 5 : }
179 : :
180 : : /* The last region */
181 [ + - ]: 22 : g_vaddr_to_fail = (void *)(8 * VALUE_2MB);
182 : 22 : failed_map = spdk_mem_map_alloc(default_translation, &test_map_ops_notify_fail, map);
183 : 22 : CU_ASSERT(failed_map == NULL);
184 : :
185 [ + + + - ]: 110 : for (i = 0; i < 4; i++) {
186 [ + - ]: 88 : uint64_t reg, size = VALUE_2MB;
187 : :
188 [ + - + - ]: 88 : reg = spdk_mem_map_translate(map, 2 * i * VALUE_2MB, &size);
189 : : /* check if `failed_map` didn't leave any translations behind */
190 : 88 : CU_ASSERT(reg == default_translation);
191 : 4 : }
192 : :
193 [ + + + - ]: 132 : for (i = 0; i < 5; i++) {
194 [ + - + - : 110 : spdk_mem_unregister((void *)(uintptr_t)(2 * i * VALUE_2MB), VALUE_2MB);
+ - ]
195 : 5 : }
196 : :
197 : 22 : spdk_mem_map_free(&map);
198 : 22 : CU_ASSERT(map == NULL);
199 : 22 : }
200 : :
201 : : static void
202 : 22 : test_mem_map_translation(void)
203 : : {
204 : 10 : struct spdk_mem_map *map;
205 : 22 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
206 : : uint64_t addr;
207 : 10 : uint64_t mapping_length;
208 : : int rc;
209 : :
210 : 22 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
211 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
212 : :
213 : : /* Try to get translation for address with no translation */
214 : 22 : addr = spdk_mem_map_translate(map, 10, NULL);
215 : 22 : CU_ASSERT(addr == default_translation);
216 : :
217 : : /* Set translation for region of non-2MB multiple size */
218 [ + - + - ]: 22 : rc = spdk_mem_map_set_translation(map, VALUE_2MB, 1234, VALUE_2MB);
219 : 22 : CU_ASSERT(rc == -EINVAL);
220 : :
221 : : /* Set translation for vaddr that isn't 2MB aligned */
222 [ + - + - ]: 22 : rc = spdk_mem_map_set_translation(map, 1234, VALUE_2MB, VALUE_2MB);
223 : 22 : CU_ASSERT(rc == -EINVAL);
224 : :
225 : : /* Set translation for one 2MB page */
226 [ + - + - : 22 : rc = spdk_mem_map_set_translation(map, VALUE_2MB, VALUE_2MB, VALUE_2MB);
+ - ]
227 : 22 : CU_ASSERT(rc == 0);
228 : :
229 : : /* Set translation for region that overlaps the previous translation */
230 [ + - ]: 22 : rc = spdk_mem_map_set_translation(map, 0, 3 * VALUE_2MB, 0);
231 : 22 : CU_ASSERT(rc == 0);
232 : :
233 : : /* Make sure we indicate that the three regions are contiguous */
234 [ + - ]: 22 : mapping_length = VALUE_2MB * 3;
235 : 22 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
236 : 22 : CU_ASSERT(addr == 0);
237 [ + - ]: 22 : CU_ASSERT(mapping_length == VALUE_2MB * 3);
238 : :
239 : : /* Translate an unaligned address */
240 [ + - ]: 22 : mapping_length = VALUE_2MB * 3;
241 [ + - ]: 22 : addr = spdk_mem_map_translate(map, VALUE_4KB, &mapping_length);
242 : 22 : CU_ASSERT(addr == 0);
243 [ + - + - ]: 22 : CU_ASSERT(mapping_length == VALUE_2MB * 3 - VALUE_4KB);
244 : :
245 : : /* Clear translation for the middle page of the larger region. */
246 [ + - + - ]: 22 : rc = spdk_mem_map_clear_translation(map, VALUE_2MB, VALUE_2MB);
247 : 22 : CU_ASSERT(rc == 0);
248 : :
249 : : /* Get translation for first page */
250 : 22 : addr = spdk_mem_map_translate(map, 0, NULL);
251 : 22 : CU_ASSERT(addr == 0);
252 : :
253 : : /* Make sure we indicate that the three regions are no longer contiguous */
254 [ + - ]: 22 : mapping_length = VALUE_2MB * 3;
255 : 22 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
256 : 22 : CU_ASSERT(addr == 0);
257 [ + - ]: 22 : CU_ASSERT(mapping_length == VALUE_2MB);
258 : :
259 : : /* Get translation for an unallocated block. Make sure size is 0 */
260 [ + - ]: 22 : mapping_length = VALUE_2MB * 3;
261 [ + - ]: 22 : addr = spdk_mem_map_translate(map, VALUE_2MB, &mapping_length);
262 : 22 : CU_ASSERT(addr == default_translation);
263 [ + - ]: 22 : CU_ASSERT(mapping_length == VALUE_2MB);
264 : :
265 : : /* Verify translation for 2nd page is the default */
266 [ + - ]: 22 : addr = spdk_mem_map_translate(map, VALUE_2MB, NULL);
267 : 22 : CU_ASSERT(addr == default_translation);
268 : :
269 : : /* Get translation for third page */
270 [ + - ]: 22 : addr = spdk_mem_map_translate(map, 2 * VALUE_2MB, NULL);
271 : : /*
272 : : * Note that addr should be 0, not 4MB. When we set the
273 : : * translation above, we said the whole 6MB region
274 : : * should translate to 0.
275 : : */
276 : 22 : CU_ASSERT(addr == 0);
277 : :
278 : : /* Translate only a subset of a 2MB page */
279 : 22 : mapping_length = 543;
280 : 22 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
281 : 22 : CU_ASSERT(addr == 0);
282 : 22 : CU_ASSERT(mapping_length == 543);
283 : :
284 : : /* Translate another subset of a 2MB page */
285 : 22 : mapping_length = 543;
286 [ + - ]: 22 : addr = spdk_mem_map_translate(map, VALUE_4KB, &mapping_length);
287 : 22 : CU_ASSERT(addr == 0);
288 : 22 : CU_ASSERT(mapping_length == 543);
289 : :
290 : : /* Try to translate an unaligned region that is only partially registered */
291 : 22 : mapping_length = 543;
292 [ + - ]: 22 : addr = spdk_mem_map_translate(map, 3 * VALUE_2MB - 196, &mapping_length);
293 : 22 : CU_ASSERT(addr == 0);
294 : 22 : CU_ASSERT(mapping_length == 196);
295 : :
296 : : /* Clear translation for the first page */
297 [ + - ]: 22 : rc = spdk_mem_map_clear_translation(map, 0, VALUE_2MB);
298 : 22 : CU_ASSERT(rc == 0);
299 : :
300 : : /* Get translation for the first page */
301 : 22 : addr = spdk_mem_map_translate(map, 0, NULL);
302 : 22 : CU_ASSERT(addr == default_translation);
303 : :
304 : : /* Clear translation for the third page */
305 [ + - + - ]: 22 : rc = spdk_mem_map_clear_translation(map, 2 * VALUE_2MB, VALUE_2MB);
306 : 22 : CU_ASSERT(rc == 0);
307 : :
308 : : /* Get translation for the third page */
309 [ + - ]: 22 : addr = spdk_mem_map_translate(map, 2 * VALUE_2MB, NULL);
310 : 22 : CU_ASSERT(addr == default_translation);
311 : :
312 : : /* Set translation for the last valid 2MB region */
313 [ + - ]: 22 : rc = spdk_mem_map_set_translation(map, 0xffffffe00000ULL, VALUE_2MB, 0x1234);
314 : 22 : CU_ASSERT(rc == 0);
315 : :
316 : : /* Verify translation for last valid 2MB region */
317 : 22 : addr = spdk_mem_map_translate(map, 0xffffffe00000ULL, NULL);
318 : 22 : CU_ASSERT(addr == 0x1234);
319 : :
320 : : /* Attempt to set translation for the first invalid address */
321 [ + - ]: 22 : rc = spdk_mem_map_set_translation(map, 0x1000000000000ULL, VALUE_2MB, 0x5678);
322 : 22 : CU_ASSERT(rc == -EINVAL);
323 : :
324 : : /* Attempt to set translation starting at a valid address but exceeding the valid range */
325 [ + - ]: 22 : rc = spdk_mem_map_set_translation(map, 0xffffffe00000ULL, VALUE_2MB * 2, 0x123123);
326 : 22 : CU_ASSERT(rc != 0);
327 : :
328 : 22 : spdk_mem_map_free(&map);
329 : 22 : CU_ASSERT(map == NULL);
330 : :
331 : : /* Allocate a map without a contiguous region checker */
332 : 22 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops_no_contig, NULL);
333 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
334 : :
335 : : /* map three contiguous regions */
336 [ + - ]: 22 : rc = spdk_mem_map_set_translation(map, 0, 3 * VALUE_2MB, 0);
337 : 22 : CU_ASSERT(rc == 0);
338 : :
339 : : /* Since we can't check their contiguity, make sure we only return the size of one page */
340 [ + - ]: 22 : mapping_length = VALUE_2MB * 3;
341 : 22 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
342 : 22 : CU_ASSERT(addr == 0);
343 [ + - ]: 22 : CU_ASSERT(mapping_length == VALUE_2MB);
344 : :
345 : : /* Translate only a subset of a 2MB page */
346 : 22 : mapping_length = 543;
347 : 22 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
348 : 22 : CU_ASSERT(addr == 0);
349 : 22 : CU_ASSERT(mapping_length == 543);
350 : :
351 : : /* Clear the translation */
352 [ + - ]: 22 : rc = spdk_mem_map_clear_translation(map, 0, VALUE_2MB * 3);
353 : 22 : CU_ASSERT(rc == 0);
354 : :
355 : 22 : spdk_mem_map_free(&map);
356 : 22 : CU_ASSERT(map == NULL);
357 : 22 : }
358 : :
359 : : static void
360 : 22 : test_mem_map_registration(void)
361 : : {
362 : : int rc;
363 : 10 : struct spdk_mem_map *map;
364 : 22 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
365 : :
366 : 22 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
367 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
368 : :
369 : : /* Unregister memory region that wasn't previously registered */
370 [ + - + - ]: 22 : rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
371 : 22 : CU_ASSERT(rc == -EINVAL);
372 : :
373 : : /* Register non-2MB multiple size */
374 [ + - ]: 22 : rc = spdk_mem_register((void *)VALUE_2MB, 1234);
375 : 22 : CU_ASSERT(rc == -EINVAL);
376 : :
377 : : /* Register region that isn't 2MB aligned */
378 [ + - ]: 22 : rc = spdk_mem_register((void *)1234, VALUE_2MB);
379 : 22 : CU_ASSERT(rc == -EINVAL);
380 : :
381 : : /* Register one 2MB page */
382 [ + - + - ]: 22 : rc = spdk_mem_register((void *)VALUE_2MB, VALUE_2MB);
383 : 22 : CU_ASSERT(rc == 0);
384 : :
385 : : /* Register an overlapping address range */
386 [ + - ]: 22 : rc = spdk_mem_register((void *)0, 3 * VALUE_2MB);
387 : 22 : CU_ASSERT(rc == -EBUSY);
388 : :
389 : : /* Unregister a 2MB page */
390 [ + - + - ]: 22 : rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
391 : 22 : CU_ASSERT(rc == 0);
392 : :
393 : : /* Register non overlapping address range */
394 [ + - ]: 22 : rc = spdk_mem_register((void *)0, 3 * VALUE_2MB);
395 : 22 : CU_ASSERT(rc == 0);
396 : :
397 : : /* Unregister the middle page of the larger region. */
398 [ + - + - ]: 22 : rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
399 : 22 : CU_ASSERT(rc == -ERANGE);
400 : :
401 : : /* Unregister the first page */
402 [ + - ]: 22 : rc = spdk_mem_unregister((void *)0, VALUE_2MB);
403 : 22 : CU_ASSERT(rc == -ERANGE);
404 : :
405 : : /* Unregister the third page */
406 [ + - + - ]: 22 : rc = spdk_mem_unregister((void *)(2 * VALUE_2MB), VALUE_2MB);
407 : 22 : CU_ASSERT(rc == -ERANGE);
408 : :
409 : : /* Unregister the entire address range */
410 [ + - ]: 22 : rc = spdk_mem_unregister((void *)0, 3 * VALUE_2MB);
411 : 22 : CU_ASSERT(rc == 0);
412 : :
413 : 22 : spdk_mem_map_free(&map);
414 : 22 : CU_ASSERT(map == NULL);
415 : 22 : }
416 : :
417 : : static void
418 : 22 : test_mem_map_registration_adjacent(void)
419 : : {
420 : 10 : struct spdk_mem_map *map, *newmap;
421 : 22 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
422 : : uintptr_t vaddr;
423 : : unsigned i;
424 : 22 : size_t notify_len[PAGE_ARRAY_SIZE] = {0};
425 : 22 : size_t chunk_len[] = { 2, 1, 3, 2, 1, 1 };
426 : :
427 : 23 : map = spdk_mem_map_alloc(default_translation,
428 : 1 : &test_map_ops_notify_checklen, notify_len);
429 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(map != NULL);
430 : :
431 : 22 : vaddr = 0;
432 [ + + ]: 154 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
433 [ + - + - : 132 : notify_len[vaddr / VALUE_2MB] = chunk_len[i] * VALUE_2MB;
+ - + - +
- + - + -
+ - + - ]
434 [ + - + - : 132 : spdk_mem_register((void *)vaddr, notify_len[vaddr / VALUE_2MB]);
+ - + - +
- ]
435 [ + - + - : 132 : vaddr += notify_len[vaddr / VALUE_2MB];
+ - + - +
- ]
436 : 6 : }
437 : :
438 : : /* Verify the memory is translated in the same chunks it was registered */
439 : 23 : newmap = spdk_mem_map_alloc(default_translation,
440 : 1 : &test_map_ops_notify_checklen, notify_len);
441 [ + + # # ]: 22 : SPDK_CU_ASSERT_FATAL(newmap != NULL);
442 : 22 : spdk_mem_map_free(&newmap);
443 : 22 : CU_ASSERT(newmap == NULL);
444 : :
445 : 22 : vaddr = 0;
446 [ + + ]: 154 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
447 [ + - + - : 132 : notify_len[vaddr / VALUE_2MB] = chunk_len[i] * VALUE_2MB;
+ - + - +
- + - + -
+ - + - ]
448 [ + - + - : 132 : spdk_mem_unregister((void *)vaddr, notify_len[vaddr / VALUE_2MB]);
+ - + - +
- ]
449 [ + - + - : 132 : vaddr += notify_len[vaddr / VALUE_2MB];
+ - + - +
- ]
450 : 6 : }
451 : :
452 : : /* Register all chunks again just to unregister them again, but this
453 : : * time with only a single unregister() call.
454 : : */
455 : 22 : vaddr = 0;
456 [ + + ]: 154 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
457 [ + - + - : 132 : notify_len[vaddr / VALUE_2MB] = chunk_len[i] * VALUE_2MB;
+ - + - +
- + - + -
+ - + - ]
458 [ + - + - : 132 : spdk_mem_register((void *)vaddr, notify_len[vaddr / VALUE_2MB]);
+ - + - +
- ]
459 [ + - + - : 132 : vaddr += notify_len[vaddr / VALUE_2MB];
+ - + - +
- ]
460 : 6 : }
461 : 22 : spdk_mem_unregister(0, vaddr);
462 : :
463 : 22 : spdk_mem_map_free(&map);
464 : 22 : CU_ASSERT(map == NULL);
465 : 22 : }
466 : :
467 : : int
468 : 22 : main(int argc, char **argv)
469 : : {
470 : 22 : CU_pSuite suite = NULL;
471 : : unsigned int num_failures;
472 : :
473 : : /*
474 : : * These tests can use PAGE_ARRAY_SIZE 2MB pages of memory.
475 : : * Note that the tests just verify addresses - this memory
476 : : * is not actually allocated.
477 : : */
478 : 22 : g_page_array = spdk_bit_array_create(PAGE_ARRAY_SIZE);
479 : :
480 : : /* Initialize the memory map */
481 [ - + ]: 22 : if (mem_map_init(false) < 0) {
482 : 0 : return CUE_NOMEMORY;
483 : : }
484 : :
485 [ - + ]: 22 : if (CU_initialize_registry() != CUE_SUCCESS) {
486 : 0 : return CU_get_error();
487 : : }
488 : :
489 : 22 : suite = CU_add_suite("memory", NULL, NULL);
490 [ + + ]: 22 : if (suite == NULL) {
491 : 0 : CU_cleanup_registry();
492 : 0 : return CU_get_error();
493 : : }
494 : :
495 [ + - ]: 21 : if (
496 [ + - + - ]: 44 : CU_add_test(suite, "alloc and free memory map", test_mem_map_alloc_free) == NULL ||
497 [ + - ]: 43 : CU_add_test(suite, "mem map translation", test_mem_map_translation) == NULL ||
498 [ + + ]: 43 : CU_add_test(suite, "mem map registration", test_mem_map_registration) == NULL ||
499 : 22 : CU_add_test(suite, "mem map adjacent registrations", test_mem_map_registration_adjacent) == NULL
500 : : ) {
501 : 0 : CU_cleanup_registry();
502 : 0 : return CU_get_error();
503 : : }
504 : :
505 : 22 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
506 : 22 : CU_cleanup_registry();
507 : :
508 : 22 : spdk_bit_array_free(&g_page_array);
509 : :
510 : 22 : return num_failures;
511 : 1 : }
|