Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2019 Intel Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <stddef.h>
7 : : #include <stdio.h>
8 : : #include <string.h>
9 : : #include <sys/queue.h>
10 : :
11 : : #include <rte_errno.h>
12 : : #include <rte_memcpy.h>
13 : : #include <rte_memory.h>
14 : : #include <rte_eal.h>
15 : : #include <rte_eal_memconfig.h>
16 : : #include <rte_common.h>
17 : : #include <rte_spinlock.h>
18 : :
19 : : #include <eal_export.h>
20 : : #include <eal_trace_internal.h>
21 : :
22 : : #include <rte_malloc.h>
23 : : #include "malloc_elem.h"
24 : : #include "malloc_heap.h"
25 : : #include "eal_memalloc.h"
26 : : #include "eal_memcfg.h"
27 : : #include "eal_private.h"
28 : :
29 : :
30 : : /* Free the memory space back to heap */
31 : : static inline void
32 : 108424 : mem_free(void *addr, const bool trace_ena, bool zero)
33 : : {
34 : : struct malloc_elem *elem;
35 : :
36 [ + + ]: 108424 : if (trace_ena)
37 : 108421 : rte_eal_trace_mem_free(addr);
38 : :
39 [ + + ]: 108424 : if (addr == NULL)
40 : : return;
41 : :
42 : : elem = malloc_elem_from_data(addr);
43 [ + + ]: 107813 : if (zero) {
44 : 1 : size_t data_len = elem->size - MALLOC_ELEM_OVERHEAD;
45 : 1 : rte_memzero_explicit(addr, data_len);
46 : : }
47 : :
48 [ - + ]: 107813 : if (malloc_heap_free(elem) < 0)
49 : 0 : EAL_LOG(ERR, "Error: Invalid memory");
50 : : }
51 : :
52 : : RTE_EXPORT_SYMBOL(rte_free)
53 : : void
54 : 108420 : rte_free(void *addr)
55 : : {
56 : 108420 : mem_free(addr, true, false);
57 : 108420 : }
58 : :
59 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_free_sensitive, 25.07)
60 : : void
61 : 1 : rte_free_sensitive(void *addr)
62 : : {
63 : 1 : mem_free(addr, true, true);
64 : 1 : }
65 : :
66 : : void
67 : 3 : eal_free_no_trace(void *addr)
68 : : {
69 : 3 : mem_free(addr, false, false);
70 : 3 : }
71 : :
72 : : static void *
73 : 110276 : malloc_socket(const char *type, size_t size, unsigned int align,
74 : : int socket_arg, const bool trace_ena)
75 : : {
76 : : void *ptr;
77 : :
78 : : /* return NULL if size is 0 or alignment is not power-of-2 */
79 [ + + + + ]: 110276 : if (size == 0 || (align && !rte_is_power_of_2(align)))
80 : : return NULL;
81 : :
82 : : /* if there are no hugepages and if we are not allocating from an
83 : : * external heap, use memory from any socket available. checking for
84 : : * socket being external may return -1 in case of invalid socket, but
85 : : * that's OK - if there are no hugepages, it doesn't matter.
86 : : */
87 [ + + + + ]: 220530 : if (rte_malloc_heap_socket_is_external(socket_arg) != 1 &&
88 : 110258 : !rte_eal_has_hugepages())
89 : : socket_arg = SOCKET_ID_ANY;
90 : :
91 : 110272 : ptr = malloc_heap_alloc(size, socket_arg, 0,
92 : : align == 0 ? 1 : align, 0, false);
93 : :
94 [ + + ]: 110272 : if (trace_ena)
95 : 110267 : rte_eal_trace_mem_malloc(type, size, align, socket_arg, ptr);
96 : : return ptr;
97 : : }
98 : :
99 : : /*
100 : : * Allocate memory on specified heap.
101 : : */
102 : : RTE_EXPORT_SYMBOL(rte_malloc_socket)
103 : : void *
104 : 110271 : rte_malloc_socket(const char *type, size_t size, unsigned int align,
105 : : int socket_arg)
106 : : {
107 : 110271 : return malloc_socket(type, size, align, socket_arg, true);
108 : : }
109 : :
110 : : void *
111 : 5 : eal_malloc_no_trace(const char *type, size_t size, unsigned int align)
112 : : {
113 : 5 : return malloc_socket(type, size, align, SOCKET_ID_ANY, false);
114 : : }
115 : :
116 : : /*
117 : : * Allocate memory on default heap.
118 : : */
119 : : RTE_EXPORT_SYMBOL(rte_malloc)
120 : : void *
121 : 70339 : rte_malloc(const char *type, size_t size, unsigned align)
122 : : {
123 : 70339 : return rte_malloc_socket(type, size, align, SOCKET_ID_ANY);
124 : : }
125 : :
126 : : /*
127 : : * Allocate zero'd memory on specified heap.
128 : : */
129 : : RTE_EXPORT_SYMBOL(rte_zmalloc_socket)
130 : : void *
131 : 39771 : rte_zmalloc_socket(const char *type, size_t size, unsigned align, int socket)
132 : : {
133 : 39771 : void *ptr = rte_malloc_socket(type, size, align, socket);
134 : :
135 [ + + ]: 39771 : if (ptr != NULL) {
136 : : struct malloc_elem *elem = malloc_elem_from_data(ptr);
137 : :
138 [ - + ]: 39741 : if (elem->dirty) {
139 : : memset(ptr, 0, size);
140 : : } else {
141 : : #ifdef RTE_MALLOC_DEBUG
142 : : /*
143 : : * If DEBUG is enabled, then freed memory is marked
144 : : * with a poison value and set to zero on allocation.
145 : : * If DEBUG is disabled then memory is already zeroed.
146 : : */
147 : : memset(ptr, 0, size);
148 : : #endif
149 : : }
150 : : }
151 : :
152 : 39771 : rte_eal_trace_mem_zmalloc(type, size, align, socket, ptr);
153 : 39771 : return ptr;
154 : : }
155 : :
156 : : /*
157 : : * Allocate zero'd memory on default heap.
158 : : */
159 : : RTE_EXPORT_SYMBOL(rte_zmalloc)
160 : : void *
161 : 34148 : rte_zmalloc(const char *type, size_t size, unsigned align)
162 : : {
163 : 34148 : return rte_zmalloc_socket(type, size, align, SOCKET_ID_ANY);
164 : : }
165 : :
166 : : /*
167 : : * Allocate zero'd memory on specified heap.
168 : : */
169 : : RTE_EXPORT_SYMBOL(rte_calloc_socket)
170 : : void *
171 : 59 : rte_calloc_socket(const char *type, size_t num, size_t size, unsigned align, int socket)
172 : : {
173 : 59 : return rte_zmalloc_socket(type, num * size, align, socket);
174 : : }
175 : :
176 : : /*
177 : : * Allocate zero'd memory on default heap.
178 : : */
179 : : RTE_EXPORT_SYMBOL(rte_calloc)
180 : : void *
181 : 219 : rte_calloc(const char *type, size_t num, size_t size, unsigned align)
182 : : {
183 : 219 : return rte_zmalloc(type, num * size, align);
184 : : }
185 : :
186 : : /*
187 : : * Resize allocated memory on specified heap.
188 : : */
189 : : RTE_EXPORT_SYMBOL(rte_realloc_socket)
190 : : void *
191 : 110 : rte_realloc_socket(void *ptr, size_t size, unsigned int align, int socket)
192 : : {
193 : : size_t user_size;
194 : :
195 [ + + ]: 110 : if (ptr == NULL)
196 : 88 : return rte_malloc_socket(NULL, size, align, socket);
197 : :
198 : : struct malloc_elem *elem = malloc_elem_from_data(ptr);
199 [ - + ]: 22 : if (elem == NULL) {
200 : 0 : EAL_LOG(ERR, "Error: memory corruption detected");
201 : 0 : return NULL;
202 : : }
203 : :
204 : : user_size = size;
205 : :
206 : 22 : size = RTE_CACHE_LINE_ROUNDUP(size), align = RTE_CACHE_LINE_ROUNDUP(align);
207 : :
208 : : /* check requested socket id and alignment matches first, and if ok,
209 : : * see if we can resize block
210 : : */
211 [ + + ]: 22 : if ((socket == SOCKET_ID_ANY ||
212 [ + + ]: 9 : (unsigned int)socket == elem->heap->socket_id) &&
213 [ + + + + ]: 41 : RTE_PTR_ALIGN(ptr, align) == ptr &&
214 : 20 : malloc_heap_resize(elem, size) == 0) {
215 : 3 : rte_eal_trace_mem_realloc(size, align, socket, ptr);
216 : :
217 : : asan_set_redzone(elem, user_size);
218 : :
219 : 3 : return ptr;
220 : : }
221 : :
222 : : /* either requested socket id doesn't match, alignment is off
223 : : * or we have no room to expand,
224 : : * so move the data.
225 : : */
226 : 19 : void *new_ptr = rte_malloc_socket(NULL, size, align, socket);
227 [ + - ]: 19 : if (new_ptr == NULL)
228 : : return NULL;
229 : : /* elem: |pad|data_elem|data|trailer| */
230 : : const size_t old_size = old_malloc_size(elem);
231 [ + - ]: 19 : rte_memcpy(new_ptr, ptr, old_size < size ? old_size : size);
232 : 19 : rte_free(ptr);
233 : :
234 : 19 : rte_eal_trace_mem_realloc(size, align, socket, new_ptr);
235 : 19 : return new_ptr;
236 : : }
237 : :
238 : : /*
239 : : * Resize allocated memory.
240 : : */
241 : : RTE_EXPORT_SYMBOL(rte_realloc)
242 : : void *
243 : 3 : rte_realloc(void *ptr, size_t size, unsigned int align)
244 : : {
245 : 3 : return rte_realloc_socket(ptr, size, align, SOCKET_ID_ANY);
246 : : }
247 : :
248 : : RTE_EXPORT_SYMBOL(rte_malloc_validate)
249 : : int
250 [ + + ]: 100306 : rte_malloc_validate(const void *ptr, size_t *size)
251 : : {
252 : : const struct malloc_elem *elem = malloc_elem_from_data(ptr);
253 [ + - ]: 100305 : if (!malloc_elem_cookies_ok(elem))
254 : : return -1;
255 [ + + ]: 100305 : if (size != NULL)
256 : 50154 : *size = elem->size - elem->pad - MALLOC_ELEM_OVERHEAD;
257 : : return 0;
258 : : }
259 : :
260 : : /*
261 : : * Function to retrieve data for heap on given socket
262 : : */
263 : : RTE_EXPORT_SYMBOL(rte_malloc_get_socket_stats)
264 : : int
265 : 14 : rte_malloc_get_socket_stats(int socket,
266 : : struct rte_malloc_socket_stats *socket_stats)
267 : : {
268 : 14 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
269 : : int heap_idx;
270 : :
271 : 14 : heap_idx = malloc_socket_to_heap_id(socket);
272 [ + - ]: 14 : if (heap_idx < 0)
273 : : return -1;
274 : :
275 : 14 : return malloc_heap_get_stats(&mcfg->malloc_heaps[heap_idx],
276 : : socket_stats);
277 : : }
278 : :
279 : : /*
280 : : * Function to dump contents of all heaps
281 : : */
282 : : RTE_EXPORT_SYMBOL(rte_malloc_dump_heaps)
283 : : void
284 : 0 : rte_malloc_dump_heaps(FILE *f)
285 : : {
286 : 0 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
287 : : unsigned int idx;
288 : :
289 [ # # ]: 0 : for (idx = 0; idx < RTE_MAX_HEAPS; idx++) {
290 : : fprintf(f, "Heap id: %u\n", idx);
291 : 0 : malloc_heap_dump(&mcfg->malloc_heaps[idx], f);
292 : : }
293 : 0 : }
294 : :
295 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_get_socket)
296 : : int
297 : 2 : rte_malloc_heap_get_socket(const char *name)
298 : : {
299 : 2 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
300 : : struct malloc_heap *heap = NULL;
301 : : unsigned int idx;
302 : : int ret;
303 : :
304 [ + - ]: 2 : if (name == NULL ||
305 [ + - - + ]: 2 : strnlen(name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
306 : : strnlen(name, RTE_HEAP_NAME_MAX_LEN) ==
307 : : RTE_HEAP_NAME_MAX_LEN) {
308 : 0 : rte_errno = EINVAL;
309 : 0 : return -1;
310 : : }
311 : 2 : rte_mcfg_mem_read_lock();
312 [ + - ]: 6 : for (idx = 0; idx < RTE_MAX_HEAPS; idx++) {
313 : 6 : struct malloc_heap *tmp = &mcfg->malloc_heaps[idx];
314 : :
315 [ + + ]: 6 : if (!strncmp(name, tmp->name, RTE_HEAP_NAME_MAX_LEN)) {
316 : : heap = tmp;
317 : : break;
318 : : }
319 : : }
320 : :
321 [ + - ]: 2 : if (heap != NULL) {
322 : 2 : ret = heap->socket_id;
323 : : } else {
324 : 0 : rte_errno = ENOENT;
325 : : ret = -1;
326 : : }
327 : 2 : rte_mcfg_mem_read_unlock();
328 : :
329 : 2 : return ret;
330 : : }
331 : :
332 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_socket_is_external)
333 : : int
334 : 110860 : rte_malloc_heap_socket_is_external(int socket_id)
335 : : {
336 : 110860 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
337 : : unsigned int idx;
338 : : int ret = -1;
339 : :
340 [ + + ]: 110860 : if (socket_id == SOCKET_ID_ANY)
341 : : return 0;
342 : :
343 : 4956 : rte_mcfg_mem_read_lock();
344 [ + + ]: 5949 : for (idx = 0; idx < RTE_MAX_HEAPS; idx++) {
345 : : struct malloc_heap *tmp = &mcfg->malloc_heaps[idx];
346 : :
347 [ + + ]: 5919 : if ((int)tmp->socket_id == socket_id) {
348 : : /* external memory always has large socket ID's */
349 : 4926 : ret = tmp->socket_id >= RTE_MAX_NUMA_NODES;
350 : 4926 : break;
351 : : }
352 : : }
353 : 4956 : rte_mcfg_mem_read_unlock();
354 : :
355 : 4956 : return ret;
356 : : }
357 : :
358 : : /*
359 : : * Print stats on memory type. If type is NULL, info on all types is printed
360 : : */
361 : : RTE_EXPORT_SYMBOL(rte_malloc_dump_stats)
362 : : void
363 : 3 : rte_malloc_dump_stats(FILE *f, __rte_unused const char *type)
364 : : {
365 : 3 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
366 : : unsigned int heap_id;
367 : : struct rte_malloc_socket_stats sock_stats;
368 : :
369 : : /* Iterate through all initialised heaps */
370 [ + + ]: 99 : for (heap_id = 0; heap_id < RTE_MAX_HEAPS; heap_id++) {
371 : 96 : struct malloc_heap *heap = &mcfg->malloc_heaps[heap_id];
372 : :
373 : 96 : malloc_heap_get_stats(heap, &sock_stats);
374 : :
375 : : fprintf(f, "Heap id:%u\n", heap_id);
376 : 96 : fprintf(f, "\tHeap name:%s\n", heap->name);
377 : 96 : fprintf(f, "\tHeap_size:%zu,\n", sock_stats.heap_totalsz_bytes);
378 : 96 : fprintf(f, "\tFree_size:%zu,\n", sock_stats.heap_freesz_bytes);
379 : 96 : fprintf(f, "\tAlloc_size:%zu,\n", sock_stats.heap_allocsz_bytes);
380 : 96 : fprintf(f, "\tGreatest_free_size:%zu,\n",
381 : : sock_stats.greatest_free_size);
382 : 96 : fprintf(f, "\tAlloc_count:%u,\n",sock_stats.alloc_count);
383 : 96 : fprintf(f, "\tFree_count:%u,\n", sock_stats.free_count);
384 : : }
385 : 3 : return;
386 : : }
387 : :
388 : : /*
389 : : * Return the IO address of a virtual address obtained through rte_malloc
390 : : */
391 : : RTE_EXPORT_SYMBOL(rte_malloc_virt2iova)
392 : : rte_iova_t
393 [ + - ]: 6083 : rte_malloc_virt2iova(const void *addr)
394 : : {
395 : : const struct rte_memseg *ms;
396 : : struct malloc_elem *elem = malloc_elem_from_data(addr);
397 : :
398 [ + - ]: 6083 : if (elem == NULL)
399 : : return RTE_BAD_IOVA;
400 : :
401 [ + - + + ]: 6083 : if (!elem->msl->external && rte_eal_iova_mode() == RTE_IOVA_VA)
402 : : return (uintptr_t) addr;
403 : :
404 : 5137 : ms = rte_mem_virt2memseg(addr, elem->msl);
405 [ + - ]: 5137 : if (ms == NULL)
406 : : return RTE_BAD_IOVA;
407 : :
408 [ + - ]: 5137 : if (ms->iova == RTE_BAD_IOVA)
409 : : return RTE_BAD_IOVA;
410 : :
411 : 5137 : return ms->iova + RTE_PTR_DIFF(addr, ms->addr);
412 : : }
413 : :
414 : : static struct malloc_heap *
415 : 6 : find_named_heap(const char *name)
416 : : {
417 : 6 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
418 : : unsigned int i;
419 : :
420 [ + - ]: 18 : for (i = 0; i < RTE_MAX_HEAPS; i++) {
421 : 18 : struct malloc_heap *heap = &mcfg->malloc_heaps[i];
422 : :
423 [ + + ]: 18 : if (!strncmp(name, heap->name, RTE_HEAP_NAME_MAX_LEN))
424 : 6 : return heap;
425 : : }
426 : : return NULL;
427 : : }
428 : :
429 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_memory_add)
430 : : int
431 : 2 : rte_malloc_heap_memory_add(const char *heap_name, void *va_addr, size_t len,
432 : : rte_iova_t iova_addrs[], unsigned int n_pages, size_t page_sz)
433 : : {
434 : : struct malloc_heap *heap = NULL;
435 : : struct rte_memseg_list *msl;
436 : : unsigned int n;
437 : : int ret;
438 : :
439 [ + - + - ]: 2 : if (heap_name == NULL || va_addr == NULL ||
440 [ + - ]: 2 : page_sz == 0 || !rte_is_power_of_2(page_sz) ||
441 [ + - + - ]: 2 : RTE_ALIGN(len, page_sz) != len ||
442 : 2 : !rte_is_aligned(va_addr, page_sz) ||
443 [ + + + - ]: 2 : ((len / page_sz) != n_pages && iova_addrs != NULL) ||
444 [ + - - + ]: 2 : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
445 : : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) ==
446 : : RTE_HEAP_NAME_MAX_LEN) {
447 : 0 : rte_errno = EINVAL;
448 : 0 : return -1;
449 : : }
450 : 2 : rte_mcfg_mem_write_lock();
451 : :
452 : : /* find our heap */
453 : 2 : heap = find_named_heap(heap_name);
454 [ - + ]: 2 : if (heap == NULL) {
455 : 0 : rte_errno = ENOENT;
456 : : ret = -1;
457 : 0 : goto unlock;
458 : : }
459 [ - + ]: 2 : if (heap->socket_id < RTE_MAX_NUMA_NODES) {
460 : : /* cannot add memory to internal heaps */
461 : 0 : rte_errno = EPERM;
462 : : ret = -1;
463 : 0 : goto unlock;
464 : : }
465 : 2 : n = len / page_sz;
466 : :
467 : 2 : msl = malloc_heap_create_external_seg(va_addr, iova_addrs, n, page_sz,
468 : : heap_name, heap->socket_id);
469 [ - + ]: 2 : if (msl == NULL) {
470 : : ret = -1;
471 : 0 : goto unlock;
472 : : }
473 : :
474 : 2 : rte_spinlock_lock(&heap->lock);
475 : 2 : ret = malloc_heap_add_external_memory(heap, msl);
476 : 2 : msl->heap = 1; /* mark it as heap segment */
477 : : rte_spinlock_unlock(&heap->lock);
478 : :
479 : 2 : unlock:
480 : 2 : rte_mcfg_mem_write_unlock();
481 : :
482 : 2 : return ret;
483 : : }
484 : :
485 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_memory_remove)
486 : : int
487 : 2 : rte_malloc_heap_memory_remove(const char *heap_name, void *va_addr, size_t len)
488 : : {
489 : : struct malloc_heap *heap = NULL;
490 : : struct rte_memseg_list *msl;
491 : : int ret;
492 : :
493 [ + - + - ]: 2 : if (heap_name == NULL || va_addr == NULL || len == 0 ||
494 [ + - - + ]: 2 : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
495 : : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) ==
496 : : RTE_HEAP_NAME_MAX_LEN) {
497 : 0 : rte_errno = EINVAL;
498 : 0 : return -1;
499 : : }
500 : 2 : rte_mcfg_mem_write_lock();
501 : : /* find our heap */
502 : 2 : heap = find_named_heap(heap_name);
503 [ - + ]: 2 : if (heap == NULL) {
504 : 0 : rte_errno = ENOENT;
505 : : ret = -1;
506 : 0 : goto unlock;
507 : : }
508 [ - + ]: 2 : if (heap->socket_id < RTE_MAX_NUMA_NODES) {
509 : : /* cannot remove memory from internal heaps */
510 : 0 : rte_errno = EPERM;
511 : : ret = -1;
512 : 0 : goto unlock;
513 : : }
514 : :
515 : 2 : msl = malloc_heap_find_external_seg(va_addr, len);
516 [ - + ]: 2 : if (msl == NULL) {
517 : : ret = -1;
518 : 0 : goto unlock;
519 : : }
520 : :
521 : 2 : rte_spinlock_lock(&heap->lock);
522 : 2 : ret = malloc_heap_remove_external_memory(heap, va_addr, len);
523 : : rte_spinlock_unlock(&heap->lock);
524 [ - + ]: 2 : if (ret != 0)
525 : 0 : goto unlock;
526 : :
527 : 2 : ret = malloc_heap_destroy_external_seg(msl);
528 : :
529 : 2 : unlock:
530 : 2 : rte_mcfg_mem_write_unlock();
531 : :
532 : 2 : return ret;
533 : : }
534 : :
535 : : static int
536 : 0 : sync_memory(const char *heap_name, void *va_addr, size_t len, bool attach)
537 : : {
538 : : struct malloc_heap *heap = NULL;
539 : : struct rte_memseg_list *msl;
540 : : int ret;
541 : :
542 [ # # # # ]: 0 : if (heap_name == NULL || va_addr == NULL || len == 0 ||
543 [ # # # # ]: 0 : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
544 : : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) ==
545 : : RTE_HEAP_NAME_MAX_LEN) {
546 : 0 : rte_errno = EINVAL;
547 : 0 : return -1;
548 : : }
549 : 0 : rte_mcfg_mem_read_lock();
550 : :
551 : : /* find our heap */
552 : 0 : heap = find_named_heap(heap_name);
553 [ # # ]: 0 : if (heap == NULL) {
554 : 0 : rte_errno = ENOENT;
555 : : ret = -1;
556 : 0 : goto unlock;
557 : : }
558 : : /* we shouldn't be able to sync to internal heaps */
559 [ # # ]: 0 : if (heap->socket_id < RTE_MAX_NUMA_NODES) {
560 : 0 : rte_errno = EPERM;
561 : : ret = -1;
562 : 0 : goto unlock;
563 : : }
564 : :
565 : : /* find corresponding memseg list to sync to */
566 : 0 : msl = malloc_heap_find_external_seg(va_addr, len);
567 [ # # ]: 0 : if (msl == NULL) {
568 : : ret = -1;
569 : 0 : goto unlock;
570 : : }
571 : :
572 [ # # ]: 0 : if (attach) {
573 : 0 : ret = rte_fbarray_attach(&msl->memseg_arr);
574 [ # # ]: 0 : if (ret == 0) {
575 : : /* notify all subscribers that a new memory area was
576 : : * added.
577 : : */
578 : 0 : eal_memalloc_mem_event_notify(RTE_MEM_EVENT_ALLOC,
579 : : va_addr, len);
580 : : } else {
581 : : ret = -1;
582 : 0 : goto unlock;
583 : : }
584 : : } else {
585 : : /* notify all subscribers that a memory area is about to
586 : : * be removed.
587 : : */
588 : 0 : eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE,
589 : 0 : msl->base_va, msl->len);
590 : 0 : ret = rte_fbarray_detach(&msl->memseg_arr);
591 : : if (ret < 0) {
592 : : ret = -1;
593 : : goto unlock;
594 : : }
595 : : }
596 : 0 : unlock:
597 : 0 : rte_mcfg_mem_read_unlock();
598 : 0 : return ret;
599 : : }
600 : :
601 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_memory_attach)
602 : : int
603 : 0 : rte_malloc_heap_memory_attach(const char *heap_name, void *va_addr, size_t len)
604 : : {
605 : 0 : return sync_memory(heap_name, va_addr, len, true);
606 : : }
607 : :
608 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_memory_detach)
609 : : int
610 : 0 : rte_malloc_heap_memory_detach(const char *heap_name, void *va_addr, size_t len)
611 : : {
612 : 0 : return sync_memory(heap_name, va_addr, len, false);
613 : : }
614 : :
615 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_create)
616 : : int
617 : 2 : rte_malloc_heap_create(const char *heap_name)
618 : : {
619 : 2 : struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
620 : : struct malloc_heap *heap = NULL;
621 : : int i, ret;
622 : :
623 [ + - ]: 2 : if (heap_name == NULL ||
624 [ + - - + ]: 2 : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
625 : : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) ==
626 : : RTE_HEAP_NAME_MAX_LEN) {
627 : 0 : rte_errno = EINVAL;
628 : 0 : return -1;
629 : : }
630 : : /* check if there is space in the heap list, or if heap with this name
631 : : * already exists.
632 : : */
633 : 2 : rte_mcfg_mem_write_lock();
634 : :
635 [ + - ]: 6 : for (i = 0; i < RTE_MAX_HEAPS; i++) {
636 : 6 : struct malloc_heap *tmp = &mcfg->malloc_heaps[i];
637 : : /* existing heap */
638 [ - + ]: 6 : if (strncmp(heap_name, tmp->name,
639 : : RTE_HEAP_NAME_MAX_LEN) == 0) {
640 : 0 : EAL_LOG(ERR, "Heap %s already exists",
641 : : heap_name);
642 : 0 : rte_errno = EEXIST;
643 : : ret = -1;
644 : 0 : goto unlock;
645 : : }
646 : : /* empty heap */
647 [ + + ]: 6 : if (strnlen(tmp->name, RTE_HEAP_NAME_MAX_LEN) == 0) {
648 : : heap = tmp;
649 : : break;
650 : : }
651 : : }
652 [ - + ]: 2 : if (heap == NULL) {
653 : 0 : EAL_LOG(ERR, "Cannot create new heap: no space");
654 : 0 : rte_errno = ENOSPC;
655 : : ret = -1;
656 : 0 : goto unlock;
657 : : }
658 : :
659 : : /* we're sure that we can create a new heap, so do it */
660 : 2 : ret = malloc_heap_create(heap, heap_name);
661 : 2 : unlock:
662 : 2 : rte_mcfg_mem_write_unlock();
663 : :
664 : 2 : return ret;
665 : : }
666 : :
667 : : RTE_EXPORT_SYMBOL(rte_malloc_heap_destroy)
668 : : int
669 : 2 : rte_malloc_heap_destroy(const char *heap_name)
670 : : {
671 : : struct malloc_heap *heap = NULL;
672 : : int ret;
673 : :
674 [ + - ]: 2 : if (heap_name == NULL ||
675 [ + - - + ]: 2 : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) == 0 ||
676 : : strnlen(heap_name, RTE_HEAP_NAME_MAX_LEN) ==
677 : : RTE_HEAP_NAME_MAX_LEN) {
678 : 0 : rte_errno = EINVAL;
679 : 0 : return -1;
680 : : }
681 : 2 : rte_mcfg_mem_write_lock();
682 : :
683 : : /* start from non-socket heaps */
684 : 2 : heap = find_named_heap(heap_name);
685 [ - + ]: 2 : if (heap == NULL) {
686 : 0 : EAL_LOG(ERR, "Heap %s not found", heap_name);
687 : 0 : rte_errno = ENOENT;
688 : : ret = -1;
689 : 0 : goto unlock;
690 : : }
691 : : /* we shouldn't be able to destroy internal heaps */
692 [ - + ]: 2 : if (heap->socket_id < RTE_MAX_NUMA_NODES) {
693 : 0 : rte_errno = EPERM;
694 : : ret = -1;
695 : 0 : goto unlock;
696 : : }
697 : : /* sanity checks done, now we can destroy the heap */
698 : 2 : rte_spinlock_lock(&heap->lock);
699 : 2 : ret = malloc_heap_destroy(heap);
700 : : rte_spinlock_unlock(&heap->lock);
701 : 2 : unlock:
702 : 2 : rte_mcfg_mem_write_unlock();
703 : :
704 : 2 : return ret;
705 : : }
|