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