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