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