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 [ - + # # : 42 : 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 [ - + # # : 42 : DEFINE_STUB(rte_mem_event_callback_register, int,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
24 : : (const char *name, rte_mem_event_callback_t clb, void *arg), 0);
25 [ - + # # : 42 : 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 : 168 : 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 [ + + + - : 168 : SPDK_CU_ASSERT_FATAL(((uintptr_t)vaddr & MAP_PAGE_MASK) == 0);
# # ]
44 [ + + + - : 168 : SPDK_CU_ASSERT_FATAL((len & MAP_PAGE_MASK) == 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 [ + + + - : 168 : SPDK_CU_ASSERT_FATAL((uintptr_t)vaddr < (MAP_PAGE_SIZE * PAGE_ARRAY_SIZE));
# # ]
51 : :
52 [ + + ]: 168 : i = (uintptr_t)vaddr >> MAP_PAGE_SHIFT;
53 [ + + ]: 168 : end = i + (len >> MAP_PAGE_SHIFT);
54 [ + + ]: 504 : for (; i < end; i++) {
55 [ + + - ]: 336 : switch (action) {
56 : 160 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
57 : : /* This page should not already be registered */
58 [ + + # # ]: 168 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == false);
59 [ + + # # ]: 168 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_set(g_page_array, i) == 0);
60 : 168 : break;
61 : 160 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
62 [ + + # # ]: 168 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == true);
63 : 168 : spdk_bit_array_clear(g_page_array, i);
64 : 168 : break;
65 : 0 : default:
66 [ # # ]: 0 : SPDK_UNREACHABLE();
67 : : }
68 : 16 : }
69 : :
70 : 168 : return 0;
71 : : }
72 : :
73 : : static int
74 : 336 : 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 : 336 : struct spdk_mem_map *reg_map = cb_ctx;
78 : : uint64_t reg_addr;
79 : 336 : uint64_t reg_size = size;
80 : :
81 [ + + + ]: 336 : switch (action) {
82 : 200 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
83 [ + + ]: 210 : if (vaddr == g_vaddr_to_fail) {
84 : : /* Test the error handling. */
85 : 42 : return -1;
86 : : }
87 : :
88 : 168 : CU_ASSERT(spdk_mem_map_set_translation(map, (uint64_t)vaddr, (uint64_t)size, (uint64_t)vaddr) == 0);
89 : :
90 : 168 : break;
91 : 120 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
92 : : /* validate the start address */
93 : 126 : reg_addr = spdk_mem_map_translate(map, (uint64_t)vaddr, ®_size);
94 : 126 : CU_ASSERT(reg_addr == (uint64_t)vaddr);
95 : 126 : 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 : 126 : spdk_mem_map_clear_translation(reg_map, (uint64_t)vaddr, size);
102 : 126 : break;
103 : : }
104 : :
105 : 294 : return 0;
106 : 16 : }
107 : :
108 : : static int
109 : 1512 : 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 : 1512 : 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 [ + + + - : 1512 : SPDK_CU_ASSERT_FATAL((uintptr_t)vaddr < (MAP_PAGE_SIZE * PAGE_ARRAY_SIZE));
# # ]
119 : :
120 [ + + + ]: 1512 : switch (action) {
121 : 720 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
122 [ - + - + : 756 : assert(size == len_arr[(uintptr_t)vaddr / MAP_PAGE_SIZE]);
- + - + +
- # # ]
123 : 756 : break;
124 : 720 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
125 [ + + + - : 756 : CU_ASSERT(size == len_arr[(uintptr_t)vaddr / MAP_PAGE_SIZE]);
+ - + - ]
126 : 756 : break;
127 : : }
128 : :
129 : 1512 : return 0;
130 : : }
131 : :
132 : : static int
133 : 273 : test_check_regions_contiguous(uint64_t addr1, uint64_t addr2)
134 : : {
135 : 273 : 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 : 42 : test_mem_map_alloc_free(void)
160 : : {
161 : 18 : struct spdk_mem_map *map, *failed_map;
162 : 42 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
163 : : int i;
164 : :
165 : 42 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
166 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(map != NULL);
167 : 42 : spdk_mem_map_free(&map);
168 : 42 : CU_ASSERT(map == NULL);
169 : :
170 : 42 : map = spdk_mem_map_alloc(default_translation, NULL, NULL);
171 [ + + # # ]: 42 : 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 [ + + + - ]: 252 : for (i = 0; i < 5; i++) {
179 [ + - + - : 210 : spdk_mem_register((void *)(uintptr_t)(2 * i * MAP_PAGE_SIZE), MAP_PAGE_SIZE);
+ - ]
180 : 10 : }
181 : :
182 : : /* The last region */
183 [ + - ]: 42 : g_vaddr_to_fail = (void *)(8 * MAP_PAGE_SIZE);
184 : 42 : failed_map = spdk_mem_map_alloc(default_translation, &test_map_ops_notify_fail, map);
185 : 42 : CU_ASSERT(failed_map == NULL);
186 : :
187 [ + + + - ]: 210 : for (i = 0; i < 4; i++) {
188 [ + - ]: 168 : uint64_t reg, size = MAP_PAGE_SIZE;
189 : :
190 [ + - + - ]: 168 : reg = spdk_mem_map_translate(map, 2 * i * MAP_PAGE_SIZE, &size);
191 : : /* check if `failed_map` didn't leave any translations behind */
192 : 168 : CU_ASSERT(reg == default_translation);
193 : 8 : }
194 : :
195 [ + + + - ]: 252 : for (i = 0; i < 5; i++) {
196 [ + - + - : 210 : spdk_mem_unregister((void *)(uintptr_t)(2 * i * MAP_PAGE_SIZE), MAP_PAGE_SIZE);
+ - ]
197 : 10 : }
198 : :
199 : 42 : spdk_mem_map_free(&map);
200 : 42 : CU_ASSERT(map == NULL);
201 : 42 : }
202 : :
203 : : static void
204 : 42 : test_mem_map_translation(void)
205 : : {
206 : 18 : struct spdk_mem_map *map;
207 : 42 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
208 : 42 : const uint64_t first_invalid_addr = 0x1000000000000ULL;
209 [ + - ]: 42 : const uint64_t last_valid_page = first_invalid_addr - MAP_PAGE_SIZE;
210 : : uint64_t addr;
211 : 18 : uint64_t mapping_length;
212 : : int rc;
213 : :
214 : 42 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
215 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(map != NULL);
216 : :
217 : : /* Try to get translation for address with no translation */
218 : 42 : addr = spdk_mem_map_translate(map, 10, NULL);
219 : 42 : CU_ASSERT(addr == default_translation);
220 : :
221 : : /* Set translation for region of non-2MB multiple size */
222 [ + - + - ]: 42 : rc = spdk_mem_map_set_translation(map, MAP_PAGE_SIZE, 1234, MAP_PAGE_SIZE);
223 : 42 : CU_ASSERT(rc == -EINVAL);
224 : :
225 : : /* Set translation for vaddr that isn't 2MB aligned */
226 [ + - + - ]: 42 : rc = spdk_mem_map_set_translation(map, 1234, MAP_PAGE_SIZE, MAP_PAGE_SIZE);
227 : 42 : CU_ASSERT(rc == -EINVAL);
228 : :
229 : : /* Set translation for one 2MB page */
230 [ + - + - : 42 : rc = spdk_mem_map_set_translation(map, MAP_PAGE_SIZE, MAP_PAGE_SIZE, MAP_PAGE_SIZE);
+ - ]
231 : 42 : CU_ASSERT(rc == 0);
232 : :
233 : : /* Set translation for region that overlaps the previous translation */
234 [ + - ]: 42 : rc = spdk_mem_map_set_translation(map, 0, 3 * MAP_PAGE_SIZE, 0);
235 : 42 : CU_ASSERT(rc == 0);
236 : :
237 : : /* Make sure we indicate that the three regions are contiguous */
238 [ + - ]: 42 : mapping_length = MAP_PAGE_SIZE * 3;
239 : 42 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
240 : 42 : CU_ASSERT(addr == 0);
241 [ + - ]: 42 : CU_ASSERT(mapping_length == MAP_PAGE_SIZE * 3);
242 : :
243 : : /* Translate an unaligned address */
244 [ + - ]: 42 : mapping_length = MAP_PAGE_SIZE * 3;
245 [ + - ]: 42 : addr = spdk_mem_map_translate(map, VALUE_4KB, &mapping_length);
246 : 42 : CU_ASSERT(addr == 0);
247 [ + - + - ]: 42 : CU_ASSERT(mapping_length == MAP_PAGE_SIZE * 3 - VALUE_4KB);
248 : :
249 : : /* Clear translation for the middle page of the larger region. */
250 [ + - + - ]: 42 : rc = spdk_mem_map_clear_translation(map, MAP_PAGE_SIZE, MAP_PAGE_SIZE);
251 : 42 : CU_ASSERT(rc == 0);
252 : :
253 : : /* Get translation for first page */
254 : 42 : addr = spdk_mem_map_translate(map, 0, NULL);
255 : 42 : CU_ASSERT(addr == 0);
256 : :
257 : : /* Make sure we indicate that the three regions are no longer contiguous */
258 [ + - ]: 42 : mapping_length = MAP_PAGE_SIZE * 3;
259 : 42 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
260 : 42 : CU_ASSERT(addr == 0);
261 [ + - ]: 42 : CU_ASSERT(mapping_length == MAP_PAGE_SIZE);
262 : :
263 : : /* Get translation for an unallocated block. Make sure size is 0 */
264 [ + - ]: 42 : mapping_length = MAP_PAGE_SIZE * 3;
265 [ + - ]: 42 : addr = spdk_mem_map_translate(map, MAP_PAGE_SIZE, &mapping_length);
266 : 42 : CU_ASSERT(addr == default_translation);
267 [ + - ]: 42 : CU_ASSERT(mapping_length == MAP_PAGE_SIZE);
268 : :
269 : : /* Verify translation for 2nd page is the default */
270 [ + - ]: 42 : addr = spdk_mem_map_translate(map, MAP_PAGE_SIZE, NULL);
271 : 42 : CU_ASSERT(addr == default_translation);
272 : :
273 : : /* Get translation for third page */
274 [ + - ]: 42 : addr = spdk_mem_map_translate(map, 2 * MAP_PAGE_SIZE, NULL);
275 : : /*
276 : : * Note that addr should be 0, not 4MB. When we set the
277 : : * translation above, we said the whole 6MB region
278 : : * should translate to 0.
279 : : */
280 : 42 : CU_ASSERT(addr == 0);
281 : :
282 : : /* Translate only a subset of a 2MB page */
283 : 42 : mapping_length = 543;
284 : 42 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
285 : 42 : CU_ASSERT(addr == 0);
286 : 42 : CU_ASSERT(mapping_length == 543);
287 : :
288 : : /* Translate another subset of a 2MB page */
289 : 42 : mapping_length = 543;
290 [ + - + - ]: 42 : addr = spdk_mem_map_translate(map, MAP_PAGE_SIZE >> 1, &mapping_length);
291 : 42 : CU_ASSERT(addr == 0);
292 : 42 : CU_ASSERT(mapping_length == 543);
293 : :
294 : : /* Try to translate an unaligned region that is only partially registered */
295 : 42 : mapping_length = 543;
296 [ + - ]: 42 : addr = spdk_mem_map_translate(map, 3 * MAP_PAGE_SIZE - 196, &mapping_length);
297 : 42 : CU_ASSERT(addr == 0);
298 : 42 : CU_ASSERT(mapping_length == 196);
299 : :
300 : : /* Clear translation for the first page */
301 [ + - ]: 42 : rc = spdk_mem_map_clear_translation(map, 0, MAP_PAGE_SIZE);
302 : 42 : CU_ASSERT(rc == 0);
303 : :
304 : : /* Get translation for the first page */
305 : 42 : addr = spdk_mem_map_translate(map, 0, NULL);
306 : 42 : CU_ASSERT(addr == default_translation);
307 : :
308 : : /* Clear translation for the third page */
309 [ + - + - ]: 42 : rc = spdk_mem_map_clear_translation(map, 2 * MAP_PAGE_SIZE, MAP_PAGE_SIZE);
310 : 42 : CU_ASSERT(rc == 0);
311 : :
312 : : /* Get translation for the third page */
313 [ + - ]: 42 : addr = spdk_mem_map_translate(map, 2 * MAP_PAGE_SIZE, NULL);
314 : 42 : CU_ASSERT(addr == default_translation);
315 : :
316 : : /* Set translation for the last valid 2MB region */
317 [ + - ]: 42 : rc = spdk_mem_map_set_translation(map, last_valid_page, MAP_PAGE_SIZE, 0x1234);
318 : 42 : CU_ASSERT(rc == 0);
319 : :
320 : : /* Verify translation for last valid 2MB region */
321 : 42 : addr = spdk_mem_map_translate(map, last_valid_page, NULL);
322 : 42 : CU_ASSERT(addr == 0x1234);
323 : :
324 : : /* Attempt to set translation for the first invalid address */
325 [ + - ]: 42 : rc = spdk_mem_map_set_translation(map, first_invalid_addr, MAP_PAGE_SIZE, 0x5678);
326 : 42 : CU_ASSERT(rc == -EINVAL);
327 : :
328 : : /* Attempt to set translation starting at a valid address but exceeding the valid range */
329 [ + - ]: 42 : rc = spdk_mem_map_set_translation(map, last_valid_page, MAP_PAGE_SIZE * 2, 0x123123);
330 : 42 : CU_ASSERT(rc != 0);
331 : :
332 : 42 : spdk_mem_map_free(&map);
333 : 42 : CU_ASSERT(map == NULL);
334 : :
335 : : /* Allocate a map without a contiguous region checker */
336 : 42 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops_no_contig, NULL);
337 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(map != NULL);
338 : :
339 : : /* map three contiguous regions */
340 [ + - ]: 42 : rc = spdk_mem_map_set_translation(map, 0, 3 * MAP_PAGE_SIZE, 0);
341 : 42 : CU_ASSERT(rc == 0);
342 : :
343 : : /* Since we can't check their contiguity, make sure we only return the size of one page */
344 [ + - ]: 42 : mapping_length = MAP_PAGE_SIZE * 3;
345 : 42 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
346 : 42 : CU_ASSERT(addr == 0);
347 [ + - ]: 42 : CU_ASSERT(mapping_length == MAP_PAGE_SIZE);
348 : :
349 : : /* Translate only a subset of a 2MB page */
350 : 42 : mapping_length = 543;
351 : 42 : addr = spdk_mem_map_translate(map, 0, &mapping_length);
352 : 42 : CU_ASSERT(addr == 0);
353 : 42 : CU_ASSERT(mapping_length == 543);
354 : :
355 : : /* Clear the translation */
356 [ + - ]: 42 : rc = spdk_mem_map_clear_translation(map, 0, MAP_PAGE_SIZE * 3);
357 : 42 : CU_ASSERT(rc == 0);
358 : :
359 : 42 : spdk_mem_map_free(&map);
360 : 42 : CU_ASSERT(map == NULL);
361 : 42 : }
362 : :
363 : : static void
364 : 42 : test_mem_map_registration(void)
365 : : {
366 : : int rc;
367 : 18 : struct spdk_mem_map *map;
368 : 42 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
369 : :
370 : 42 : map = spdk_mem_map_alloc(default_translation, &test_mem_map_ops, NULL);
371 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(map != NULL);
372 : :
373 : : /* Unregister memory region that wasn't previously registered */
374 [ + - + - ]: 42 : rc = spdk_mem_unregister((void *)MAP_PAGE_SIZE, MAP_PAGE_SIZE);
375 : 42 : CU_ASSERT(rc == -EINVAL);
376 : :
377 : : /* Register non-2MB multiple size */
378 [ + - ]: 42 : rc = spdk_mem_register((void *)MAP_PAGE_SIZE, 1234);
379 : 42 : CU_ASSERT(rc == -EINVAL);
380 : :
381 : : /* Register region that isn't 2MB aligned */
382 [ + - ]: 42 : rc = spdk_mem_register((void *)1234, MAP_PAGE_SIZE);
383 : 42 : CU_ASSERT(rc == -EINVAL);
384 : :
385 : : /* Register one 2MB page */
386 [ + - + - ]: 42 : rc = spdk_mem_register((void *)MAP_PAGE_SIZE, MAP_PAGE_SIZE);
387 : 42 : CU_ASSERT(rc == 0);
388 : :
389 : : /* Register an overlapping address range */
390 [ + - ]: 42 : rc = spdk_mem_register((void *)0, 3 * MAP_PAGE_SIZE);
391 : 42 : CU_ASSERT(rc == -EBUSY);
392 : :
393 : : /* Unregister a 2MB page */
394 [ + - + - ]: 42 : rc = spdk_mem_unregister((void *)MAP_PAGE_SIZE, MAP_PAGE_SIZE);
395 : 42 : CU_ASSERT(rc == 0);
396 : :
397 : : /* Register non overlapping address range */
398 [ + - ]: 42 : rc = spdk_mem_register((void *)0, 3 * MAP_PAGE_SIZE);
399 : 42 : CU_ASSERT(rc == 0);
400 : :
401 : : /* Unregister the middle page of the larger region. */
402 [ + - + - ]: 42 : rc = spdk_mem_unregister((void *)MAP_PAGE_SIZE, MAP_PAGE_SIZE);
403 : 42 : CU_ASSERT(rc == -ERANGE);
404 : :
405 : : /* Unregister the first page */
406 [ + - ]: 42 : rc = spdk_mem_unregister((void *)0, MAP_PAGE_SIZE);
407 : 42 : CU_ASSERT(rc == -ERANGE);
408 : :
409 : : /* Unregister the third page */
410 [ + - + - ]: 42 : rc = spdk_mem_unregister((void *)(2 * MAP_PAGE_SIZE), MAP_PAGE_SIZE);
411 : 42 : CU_ASSERT(rc == -ERANGE);
412 : :
413 : : /* Unregister the entire address range */
414 [ + - ]: 42 : rc = spdk_mem_unregister((void *)0, 3 * MAP_PAGE_SIZE);
415 : 42 : CU_ASSERT(rc == 0);
416 : :
417 : 42 : spdk_mem_map_free(&map);
418 : 42 : CU_ASSERT(map == NULL);
419 : 42 : }
420 : :
421 : : static void
422 : 42 : test_mem_map_registration_adjacent(void)
423 : : {
424 : 18 : struct spdk_mem_map *map, *newmap;
425 : 42 : uint64_t default_translation = 0xDEADBEEF0BADF00D;
426 : : uintptr_t vaddr;
427 : : unsigned i;
428 : 42 : size_t notify_len[PAGE_ARRAY_SIZE] = {0};
429 : 42 : size_t chunk_len[] = { 2, 1, 3, 2, 1, 1 };
430 : :
431 : 44 : map = spdk_mem_map_alloc(default_translation,
432 : 2 : &test_map_ops_notify_checklen, notify_len);
433 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(map != NULL);
434 : :
435 : 42 : vaddr = 0;
436 [ + + ]: 294 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
437 [ + + + - : 252 : notify_len[vaddr / MAP_PAGE_SIZE] = chunk_len[i] * MAP_PAGE_SIZE;
+ - + - +
- + - + -
+ - + - ]
438 [ + + + - : 252 : spdk_mem_register((void *)vaddr, notify_len[vaddr / MAP_PAGE_SIZE]);
+ - + - +
- ]
439 [ + + + - : 252 : vaddr += notify_len[vaddr / MAP_PAGE_SIZE];
+ - + - +
- ]
440 : 12 : }
441 : :
442 : : /* Verify the memory is translated in the same chunks it was registered */
443 : 44 : newmap = spdk_mem_map_alloc(default_translation,
444 : 2 : &test_map_ops_notify_checklen, notify_len);
445 [ + + # # ]: 42 : SPDK_CU_ASSERT_FATAL(newmap != NULL);
446 : 42 : spdk_mem_map_free(&newmap);
447 : 42 : CU_ASSERT(newmap == NULL);
448 : :
449 : 42 : vaddr = 0;
450 [ + + ]: 294 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
451 [ + + + - : 252 : notify_len[vaddr / MAP_PAGE_SIZE] = chunk_len[i] * MAP_PAGE_SIZE;
+ - + - +
- + - + -
+ - + - ]
452 [ + + + - : 252 : spdk_mem_unregister((void *)vaddr, notify_len[vaddr / MAP_PAGE_SIZE]);
+ - + - +
- ]
453 [ + + + - : 252 : vaddr += notify_len[vaddr / MAP_PAGE_SIZE];
+ - + - +
- ]
454 : 12 : }
455 : :
456 : : /* Register all chunks again just to unregister them again, but this
457 : : * time with only a single unregister() call.
458 : : */
459 : 42 : vaddr = 0;
460 [ + + ]: 294 : for (i = 0; i < SPDK_COUNTOF(chunk_len); i++) {
461 [ + + + - : 252 : notify_len[vaddr / MAP_PAGE_SIZE] = chunk_len[i] * MAP_PAGE_SIZE;
+ - + - +
- + - + -
+ - + - ]
462 [ + + + - : 252 : spdk_mem_register((void *)vaddr, notify_len[vaddr / MAP_PAGE_SIZE]);
+ - + - +
- ]
463 [ + + + - : 252 : vaddr += notify_len[vaddr / MAP_PAGE_SIZE];
+ - + - +
- ]
464 : 12 : }
465 : 42 : spdk_mem_unregister(0, vaddr);
466 : :
467 : 42 : spdk_mem_map_free(&map);
468 : 42 : CU_ASSERT(map == NULL);
469 : 42 : }
470 : :
471 : : static int
472 : 21 : init_2mb_map(void)
473 : : {
474 : 21 : mem_map_use_page_shift(SHIFT_2MB);
475 : 21 : return mem_map_init(false);
476 : : }
477 : :
478 : : static int
479 : 21 : cleanup_2mb_map(void)
480 : : {
481 : 21 : mem_map_fini();
482 : 21 : return 0;
483 : : }
484 : :
485 : : static int
486 : 21 : init_4kb_map(void)
487 : : {
488 : 21 : mem_map_use_page_shift(SHIFT_4KB);
489 : 21 : return mem_map_init(false);
490 : : }
491 : :
492 : : static int
493 : 21 : cleanup_4kb_map(void)
494 : : {
495 : 21 : mem_map_fini();
496 : 21 : return 0;
497 : : }
498 : :
499 : : int
500 : 21 : main(int argc, char **argv)
501 : : {
502 : 21 : CU_pSuite suite = NULL;
503 : : unsigned int num_failures;
504 : :
505 : : /*
506 : : * These tests can use PAGE_ARRAY_SIZE 2MB pages of memory.
507 : : * Note that the tests just verify addresses - this memory
508 : : * is not actually allocated.
509 : : */
510 : 21 : g_page_array = spdk_bit_array_create(PAGE_ARRAY_SIZE);
511 : :
512 [ - + ]: 21 : if (CU_initialize_registry() != CUE_SUCCESS) {
513 : 0 : return CU_get_error();
514 : : }
515 : :
516 : : /* Test suite for 2MB page size mapping. */
517 : 21 : suite = CU_add_suite("mem_map_2mb", init_2mb_map, cleanup_2mb_map);
518 [ + + ]: 21 : if (suite == NULL) {
519 : 0 : CU_cleanup_registry();
520 : 0 : return CU_get_error();
521 : : }
522 : :
523 [ + - ]: 20 : if (
524 [ + - - + ]: 42 : CU_add_test(suite, "alloc and free memory map", test_mem_map_alloc_free) == NULL ||
525 [ + - ]: 41 : CU_add_test(suite, "mem map translation", test_mem_map_translation) == NULL ||
526 [ + + ]: 41 : CU_add_test(suite, "mem map registration", test_mem_map_registration) == NULL ||
527 : 21 : CU_add_test(suite, "mem map adjacent registrations", test_mem_map_registration_adjacent) == NULL
528 : : ) {
529 : 0 : CU_cleanup_registry();
530 : 0 : return CU_get_error();
531 : : }
532 : :
533 : : /* Test suite for 4KB page size mapping. */
534 : 21 : suite = CU_add_suite("mem_map_4kb", init_4kb_map, cleanup_4kb_map);
535 [ + + ]: 21 : if (suite == NULL) {
536 : 0 : CU_cleanup_registry();
537 : 0 : return CU_get_error();
538 : : }
539 : :
540 [ + - ]: 20 : if (
541 [ + - + - ]: 42 : CU_add_test(suite, "alloc and free memory map", test_mem_map_alloc_free) == NULL ||
542 [ + - ]: 41 : CU_add_test(suite, "mem map translation", test_mem_map_translation) == NULL ||
543 [ + + ]: 41 : CU_add_test(suite, "mem map registration", test_mem_map_registration) == NULL ||
544 : 21 : CU_add_test(suite, "mem map adjacent registrations", test_mem_map_registration_adjacent) == NULL
545 : : ) {
546 : 0 : CU_cleanup_registry();
547 : 0 : return CU_get_error();
548 : : }
549 : :
550 : 21 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
551 : 21 : CU_cleanup_registry();
552 : :
553 : 21 : spdk_bit_array_free(&g_page_array);
554 : :
555 : 21 : return num_failures;
556 : 1 : }
|