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