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