1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 #include <stdint.h> 5 #include <stddef.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 #include <stdarg.h> 9 #include <errno.h> 10 #include <sys/queue.h> 11 12 #include <rte_memory.h> 13 #include <rte_errno.h> 14 #include <rte_eal.h> 15 #include <rte_eal_memconfig.h> 16 #include <rte_launch.h> 17 #include <rte_per_lcore.h> 18 #include <rte_lcore.h> 19 #include <rte_common.h> 20 #include <rte_string_fns.h> 21 #include <rte_spinlock.h> 22 #include <rte_memcpy.h> 23 #include <rte_memzone.h> 24 #include <rte_atomic.h> 25 #include <rte_fbarray.h> 26 27 #include "eal_internal_cfg.h" 28 #include "eal_memalloc.h" 29 #include "eal_memcfg.h" 30 #include "eal_private.h" 31 #include "malloc_elem.h" 32 #include "malloc_heap.h" 33 #include "malloc_mp.h" 34 35 /* start external socket ID's at a very high number */ 36 #define CONST_MAX(a, b) (a > b ? a : b) /* RTE_MAX is not a constant */ 37 #define EXTERNAL_HEAP_MIN_SOCKET_ID (CONST_MAX((1 << 8), RTE_MAX_NUMA_NODES)) 38 39 static unsigned 40 check_hugepage_sz(unsigned flags, uint64_t hugepage_sz) 41 { 42 unsigned check_flag = 0; 43 44 if (!(flags & ~RTE_MEMZONE_SIZE_HINT_ONLY)) 45 return 1; 46 47 switch (hugepage_sz) { 48 case RTE_PGSIZE_256K: 49 check_flag = RTE_MEMZONE_256KB; 50 break; 51 case RTE_PGSIZE_2M: 52 check_flag = RTE_MEMZONE_2MB; 53 break; 54 case RTE_PGSIZE_16M: 55 check_flag = RTE_MEMZONE_16MB; 56 break; 57 case RTE_PGSIZE_256M: 58 check_flag = RTE_MEMZONE_256MB; 59 break; 60 case RTE_PGSIZE_512M: 61 check_flag = RTE_MEMZONE_512MB; 62 break; 63 case RTE_PGSIZE_1G: 64 check_flag = RTE_MEMZONE_1GB; 65 break; 66 case RTE_PGSIZE_4G: 67 check_flag = RTE_MEMZONE_4GB; 68 break; 69 case RTE_PGSIZE_16G: 70 check_flag = RTE_MEMZONE_16GB; 71 } 72 73 return check_flag & flags; 74 } 75 76 int 77 malloc_socket_to_heap_id(unsigned int socket_id) 78 { 79 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 80 int i; 81 82 for (i = 0; i < RTE_MAX_HEAPS; i++) { 83 struct malloc_heap *heap = &mcfg->malloc_heaps[i]; 84 85 if (heap->socket_id == socket_id) 86 return i; 87 } 88 return -1; 89 } 90 91 /* 92 * Expand the heap with a memory area. 93 */ 94 static struct malloc_elem * 95 malloc_heap_add_memory(struct malloc_heap *heap, struct rte_memseg_list *msl, 96 void *start, size_t len) 97 { 98 struct malloc_elem *elem = start; 99 100 malloc_elem_init(elem, heap, msl, len, elem, len); 101 102 malloc_elem_insert(elem); 103 104 elem = malloc_elem_join_adjacent_free(elem); 105 106 malloc_elem_free_list_insert(elem); 107 108 return elem; 109 } 110 111 static int 112 malloc_add_seg(const struct rte_memseg_list *msl, 113 const struct rte_memseg *ms, size_t len, void *arg __rte_unused) 114 { 115 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 116 struct rte_memseg_list *found_msl; 117 struct malloc_heap *heap; 118 int msl_idx, heap_idx; 119 120 if (msl->external) 121 return 0; 122 123 heap_idx = malloc_socket_to_heap_id(msl->socket_id); 124 if (heap_idx < 0) { 125 RTE_LOG(ERR, EAL, "Memseg list has invalid socket id\n"); 126 return -1; 127 } 128 heap = &mcfg->malloc_heaps[heap_idx]; 129 130 /* msl is const, so find it */ 131 msl_idx = msl - mcfg->memsegs; 132 133 if (msl_idx < 0 || msl_idx >= RTE_MAX_MEMSEG_LISTS) 134 return -1; 135 136 found_msl = &mcfg->memsegs[msl_idx]; 137 138 malloc_heap_add_memory(heap, found_msl, ms->addr, len); 139 140 heap->total_size += len; 141 142 RTE_LOG(DEBUG, EAL, "Added %zuM to heap on socket %i\n", len >> 20, 143 msl->socket_id); 144 return 0; 145 } 146 147 /* 148 * Iterates through the freelist for a heap to find a free element 149 * which can store data of the required size and with the requested alignment. 150 * If size is 0, find the biggest available elem. 151 * Returns null on failure, or pointer to element on success. 152 */ 153 static struct malloc_elem * 154 find_suitable_element(struct malloc_heap *heap, size_t size, 155 unsigned int flags, size_t align, size_t bound, bool contig) 156 { 157 size_t idx; 158 struct malloc_elem *elem, *alt_elem = NULL; 159 160 for (idx = malloc_elem_free_list_index(size); 161 idx < RTE_HEAP_NUM_FREELISTS; idx++) { 162 for (elem = LIST_FIRST(&heap->free_head[idx]); 163 !!elem; elem = LIST_NEXT(elem, free_list)) { 164 if (malloc_elem_can_hold(elem, size, align, bound, 165 contig)) { 166 if (check_hugepage_sz(flags, 167 elem->msl->page_sz)) 168 return elem; 169 if (alt_elem == NULL) 170 alt_elem = elem; 171 } 172 } 173 } 174 175 if ((alt_elem != NULL) && (flags & RTE_MEMZONE_SIZE_HINT_ONLY)) 176 return alt_elem; 177 178 return NULL; 179 } 180 181 /* 182 * Iterates through the freelist for a heap to find a free element with the 183 * biggest size and requested alignment. Will also set size to whatever element 184 * size that was found. 185 * Returns null on failure, or pointer to element on success. 186 */ 187 static struct malloc_elem * 188 find_biggest_element(struct malloc_heap *heap, size_t *size, 189 unsigned int flags, size_t align, bool contig) 190 { 191 struct malloc_elem *elem, *max_elem = NULL; 192 size_t idx, max_size = 0; 193 194 for (idx = 0; idx < RTE_HEAP_NUM_FREELISTS; idx++) { 195 for (elem = LIST_FIRST(&heap->free_head[idx]); 196 !!elem; elem = LIST_NEXT(elem, free_list)) { 197 size_t cur_size; 198 if ((flags & RTE_MEMZONE_SIZE_HINT_ONLY) == 0 && 199 !check_hugepage_sz(flags, 200 elem->msl->page_sz)) 201 continue; 202 if (contig) { 203 cur_size = 204 malloc_elem_find_max_iova_contig(elem, 205 align); 206 } else { 207 void *data_start = RTE_PTR_ADD(elem, 208 MALLOC_ELEM_HEADER_LEN); 209 void *data_end = RTE_PTR_ADD(elem, elem->size - 210 MALLOC_ELEM_TRAILER_LEN); 211 void *aligned = RTE_PTR_ALIGN_CEIL(data_start, 212 align); 213 /* check if aligned data start is beyond end */ 214 if (aligned >= data_end) 215 continue; 216 cur_size = RTE_PTR_DIFF(data_end, aligned); 217 } 218 if (cur_size > max_size) { 219 max_size = cur_size; 220 max_elem = elem; 221 } 222 } 223 } 224 225 *size = max_size; 226 return max_elem; 227 } 228 229 /* 230 * Main function to allocate a block of memory from the heap. 231 * It locks the free list, scans it, and adds a new memseg if the 232 * scan fails. Once the new memseg is added, it re-scans and should return 233 * the new element after releasing the lock. 234 */ 235 static void * 236 heap_alloc(struct malloc_heap *heap, const char *type __rte_unused, size_t size, 237 unsigned int flags, size_t align, size_t bound, bool contig) 238 { 239 struct malloc_elem *elem; 240 size_t user_size = size; 241 242 size = RTE_CACHE_LINE_ROUNDUP(size); 243 align = RTE_CACHE_LINE_ROUNDUP(align); 244 245 /* roundup might cause an overflow */ 246 if (size == 0) 247 return NULL; 248 elem = find_suitable_element(heap, size, flags, align, bound, contig); 249 if (elem != NULL) { 250 elem = malloc_elem_alloc(elem, size, align, bound, contig); 251 252 /* increase heap's count of allocated elements */ 253 heap->alloc_count++; 254 255 asan_set_redzone(elem, user_size); 256 } 257 258 return elem == NULL ? NULL : (void *)(&elem[1]); 259 } 260 261 static void * 262 heap_alloc_biggest(struct malloc_heap *heap, const char *type __rte_unused, 263 unsigned int flags, size_t align, bool contig) 264 { 265 struct malloc_elem *elem; 266 size_t size; 267 268 align = RTE_CACHE_LINE_ROUNDUP(align); 269 270 elem = find_biggest_element(heap, &size, flags, align, contig); 271 if (elem != NULL) { 272 elem = malloc_elem_alloc(elem, size, align, 0, contig); 273 274 /* increase heap's count of allocated elements */ 275 heap->alloc_count++; 276 277 asan_set_redzone(elem, size); 278 } 279 280 return elem == NULL ? NULL : (void *)(&elem[1]); 281 } 282 283 /* this function is exposed in malloc_mp.h */ 284 void 285 rollback_expand_heap(struct rte_memseg **ms, int n_segs, 286 struct malloc_elem *elem, void *map_addr, size_t map_len) 287 { 288 if (elem != NULL) { 289 malloc_elem_free_list_remove(elem); 290 malloc_elem_hide_region(elem, map_addr, map_len); 291 } 292 293 eal_memalloc_free_seg_bulk(ms, n_segs); 294 } 295 296 /* this function is exposed in malloc_mp.h */ 297 struct malloc_elem * 298 alloc_pages_on_heap(struct malloc_heap *heap, uint64_t pg_sz, size_t elt_size, 299 int socket, unsigned int flags, size_t align, size_t bound, 300 bool contig, struct rte_memseg **ms, int n_segs) 301 { 302 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 303 struct rte_memseg_list *msl; 304 struct malloc_elem *elem = NULL; 305 size_t alloc_sz; 306 int allocd_pages; 307 void *ret, *map_addr; 308 309 alloc_sz = (size_t)pg_sz * n_segs; 310 311 /* first, check if we're allowed to allocate this memory */ 312 if (eal_memalloc_mem_alloc_validate(socket, 313 heap->total_size + alloc_sz) < 0) { 314 RTE_LOG(DEBUG, EAL, "User has disallowed allocation\n"); 315 return NULL; 316 } 317 318 allocd_pages = eal_memalloc_alloc_seg_bulk(ms, n_segs, pg_sz, 319 socket, true); 320 321 /* make sure we've allocated our pages... */ 322 if (allocd_pages < 0) 323 return NULL; 324 325 map_addr = ms[0]->addr; 326 msl = rte_mem_virt2memseg_list(map_addr); 327 328 /* check if we wanted contiguous memory but didn't get it */ 329 if (contig && !eal_memalloc_is_contig(msl, map_addr, alloc_sz)) { 330 RTE_LOG(DEBUG, EAL, "%s(): couldn't allocate physically contiguous space\n", 331 __func__); 332 goto fail; 333 } 334 335 /* 336 * Once we have all the memseg lists configured, if there is a dma mask 337 * set, check iova addresses are not out of range. Otherwise the device 338 * setting the dma mask could have problems with the mapped memory. 339 * 340 * There are two situations when this can happen: 341 * 1) memory initialization 342 * 2) dynamic memory allocation 343 * 344 * For 1), an error when checking dma mask implies app can not be 345 * executed. For 2) implies the new memory can not be added. 346 */ 347 if (mcfg->dma_maskbits && 348 rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) { 349 /* 350 * Currently this can only happen if IOMMU is enabled 351 * and the address width supported by the IOMMU hw is 352 * not enough for using the memory mapped IOVAs. 353 * 354 * If IOVA is VA, advice to try with '--iova-mode pa' 355 * which could solve some situations when IOVA VA is not 356 * really needed. 357 */ 358 RTE_LOG(ERR, EAL, 359 "%s(): couldn't allocate memory due to IOVA exceeding limits of current DMA mask\n", 360 __func__); 361 362 /* 363 * If IOVA is VA and it is possible to run with IOVA PA, 364 * because user is root, give and advice for solving the 365 * problem. 366 */ 367 if ((rte_eal_iova_mode() == RTE_IOVA_VA) && 368 rte_eal_using_phys_addrs()) 369 RTE_LOG(ERR, EAL, 370 "%s(): Please try initializing EAL with --iova-mode=pa parameter\n", 371 __func__); 372 goto fail; 373 } 374 375 /* add newly minted memsegs to malloc heap */ 376 elem = malloc_heap_add_memory(heap, msl, map_addr, alloc_sz); 377 378 /* try once more, as now we have allocated new memory */ 379 ret = find_suitable_element(heap, elt_size, flags, align, bound, 380 contig); 381 382 if (ret == NULL) 383 goto fail; 384 385 return elem; 386 387 fail: 388 rollback_expand_heap(ms, n_segs, elem, map_addr, alloc_sz); 389 return NULL; 390 } 391 392 static int 393 try_expand_heap_primary(struct malloc_heap *heap, uint64_t pg_sz, 394 size_t elt_size, int socket, unsigned int flags, size_t align, 395 size_t bound, bool contig) 396 { 397 struct malloc_elem *elem; 398 struct rte_memseg **ms; 399 void *map_addr; 400 size_t alloc_sz; 401 int n_segs; 402 bool callback_triggered = false; 403 404 alloc_sz = RTE_ALIGN_CEIL(align + elt_size + 405 MALLOC_ELEM_TRAILER_LEN, pg_sz); 406 n_segs = alloc_sz / pg_sz; 407 408 /* we can't know in advance how many pages we'll need, so we malloc */ 409 ms = malloc(sizeof(*ms) * n_segs); 410 if (ms == NULL) 411 return -1; 412 memset(ms, 0, sizeof(*ms) * n_segs); 413 414 elem = alloc_pages_on_heap(heap, pg_sz, elt_size, socket, flags, align, 415 bound, contig, ms, n_segs); 416 417 if (elem == NULL) 418 goto free_ms; 419 420 map_addr = ms[0]->addr; 421 422 /* notify user about changes in memory map */ 423 eal_memalloc_mem_event_notify(RTE_MEM_EVENT_ALLOC, map_addr, alloc_sz); 424 425 /* notify other processes that this has happened */ 426 if (request_sync()) { 427 /* we couldn't ensure all processes have mapped memory, 428 * so free it back and notify everyone that it's been 429 * freed back. 430 * 431 * technically, we could've avoided adding memory addresses to 432 * the map, but that would've led to inconsistent behavior 433 * between primary and secondary processes, as those get 434 * callbacks during sync. therefore, force primary process to 435 * do alloc-and-rollback syncs as well. 436 */ 437 callback_triggered = true; 438 goto free_elem; 439 } 440 heap->total_size += alloc_sz; 441 442 RTE_LOG(DEBUG, EAL, "Heap on socket %d was expanded by %zdMB\n", 443 socket, alloc_sz >> 20ULL); 444 445 free(ms); 446 447 return 0; 448 449 free_elem: 450 if (callback_triggered) 451 eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, 452 map_addr, alloc_sz); 453 454 rollback_expand_heap(ms, n_segs, elem, map_addr, alloc_sz); 455 456 request_sync(); 457 free_ms: 458 free(ms); 459 460 return -1; 461 } 462 463 static int 464 try_expand_heap_secondary(struct malloc_heap *heap, uint64_t pg_sz, 465 size_t elt_size, int socket, unsigned int flags, size_t align, 466 size_t bound, bool contig) 467 { 468 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 469 struct malloc_mp_req req; 470 int req_result; 471 472 memset(&req, 0, sizeof(req)); 473 474 req.t = REQ_TYPE_ALLOC; 475 req.alloc_req.align = align; 476 req.alloc_req.bound = bound; 477 req.alloc_req.contig = contig; 478 req.alloc_req.flags = flags; 479 req.alloc_req.elt_size = elt_size; 480 req.alloc_req.page_sz = pg_sz; 481 req.alloc_req.socket = socket; 482 req.alloc_req.malloc_heap_idx = heap - mcfg->malloc_heaps; 483 484 req_result = request_to_primary(&req); 485 486 if (req_result != 0) 487 return -1; 488 489 if (req.result != REQ_RESULT_SUCCESS) 490 return -1; 491 492 return 0; 493 } 494 495 static int 496 try_expand_heap(struct malloc_heap *heap, uint64_t pg_sz, size_t elt_size, 497 int socket, unsigned int flags, size_t align, size_t bound, 498 bool contig) 499 { 500 int ret; 501 502 rte_mcfg_mem_write_lock(); 503 504 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 505 ret = try_expand_heap_primary(heap, pg_sz, elt_size, socket, 506 flags, align, bound, contig); 507 } else { 508 ret = try_expand_heap_secondary(heap, pg_sz, elt_size, socket, 509 flags, align, bound, contig); 510 } 511 512 rte_mcfg_mem_write_unlock(); 513 return ret; 514 } 515 516 static int 517 compare_pagesz(const void *a, const void *b) 518 { 519 const struct rte_memseg_list * const*mpa = a; 520 const struct rte_memseg_list * const*mpb = b; 521 const struct rte_memseg_list *msla = *mpa; 522 const struct rte_memseg_list *mslb = *mpb; 523 uint64_t pg_sz_a = msla->page_sz; 524 uint64_t pg_sz_b = mslb->page_sz; 525 526 if (pg_sz_a < pg_sz_b) 527 return -1; 528 if (pg_sz_a > pg_sz_b) 529 return 1; 530 return 0; 531 } 532 533 static int 534 alloc_more_mem_on_socket(struct malloc_heap *heap, size_t size, int socket, 535 unsigned int flags, size_t align, size_t bound, bool contig) 536 { 537 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 538 struct rte_memseg_list *requested_msls[RTE_MAX_MEMSEG_LISTS]; 539 struct rte_memseg_list *other_msls[RTE_MAX_MEMSEG_LISTS]; 540 uint64_t requested_pg_sz[RTE_MAX_MEMSEG_LISTS]; 541 uint64_t other_pg_sz[RTE_MAX_MEMSEG_LISTS]; 542 uint64_t prev_pg_sz; 543 int i, n_other_msls, n_other_pg_sz, n_requested_msls, n_requested_pg_sz; 544 bool size_hint = (flags & RTE_MEMZONE_SIZE_HINT_ONLY) > 0; 545 unsigned int size_flags = flags & ~RTE_MEMZONE_SIZE_HINT_ONLY; 546 void *ret; 547 548 memset(requested_msls, 0, sizeof(requested_msls)); 549 memset(other_msls, 0, sizeof(other_msls)); 550 memset(requested_pg_sz, 0, sizeof(requested_pg_sz)); 551 memset(other_pg_sz, 0, sizeof(other_pg_sz)); 552 553 /* 554 * go through memseg list and take note of all the page sizes available, 555 * and if any of them were specifically requested by the user. 556 */ 557 n_requested_msls = 0; 558 n_other_msls = 0; 559 for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) { 560 struct rte_memseg_list *msl = &mcfg->memsegs[i]; 561 562 if (msl->socket_id != socket) 563 continue; 564 565 if (msl->base_va == NULL) 566 continue; 567 568 /* if pages of specific size were requested */ 569 if (size_flags != 0 && check_hugepage_sz(size_flags, 570 msl->page_sz)) 571 requested_msls[n_requested_msls++] = msl; 572 else if (size_flags == 0 || size_hint) 573 other_msls[n_other_msls++] = msl; 574 } 575 576 /* sort the lists, smallest first */ 577 qsort(requested_msls, n_requested_msls, sizeof(requested_msls[0]), 578 compare_pagesz); 579 qsort(other_msls, n_other_msls, sizeof(other_msls[0]), 580 compare_pagesz); 581 582 /* now, extract page sizes we are supposed to try */ 583 prev_pg_sz = 0; 584 n_requested_pg_sz = 0; 585 for (i = 0; i < n_requested_msls; i++) { 586 uint64_t pg_sz = requested_msls[i]->page_sz; 587 588 if (prev_pg_sz != pg_sz) { 589 requested_pg_sz[n_requested_pg_sz++] = pg_sz; 590 prev_pg_sz = pg_sz; 591 } 592 } 593 prev_pg_sz = 0; 594 n_other_pg_sz = 0; 595 for (i = 0; i < n_other_msls; i++) { 596 uint64_t pg_sz = other_msls[i]->page_sz; 597 598 if (prev_pg_sz != pg_sz) { 599 other_pg_sz[n_other_pg_sz++] = pg_sz; 600 prev_pg_sz = pg_sz; 601 } 602 } 603 604 /* finally, try allocating memory of specified page sizes, starting from 605 * the smallest sizes 606 */ 607 for (i = 0; i < n_requested_pg_sz; i++) { 608 uint64_t pg_sz = requested_pg_sz[i]; 609 610 /* 611 * do not pass the size hint here, as user expects other page 612 * sizes first, before resorting to best effort allocation. 613 */ 614 if (!try_expand_heap(heap, pg_sz, size, socket, size_flags, 615 align, bound, contig)) 616 return 0; 617 } 618 if (n_other_pg_sz == 0) 619 return -1; 620 621 /* now, check if we can reserve anything with size hint */ 622 ret = find_suitable_element(heap, size, flags, align, bound, contig); 623 if (ret != NULL) 624 return 0; 625 626 /* 627 * we still couldn't reserve memory, so try expanding heap with other 628 * page sizes, if there are any 629 */ 630 for (i = 0; i < n_other_pg_sz; i++) { 631 uint64_t pg_sz = other_pg_sz[i]; 632 633 if (!try_expand_heap(heap, pg_sz, size, socket, flags, 634 align, bound, contig)) 635 return 0; 636 } 637 return -1; 638 } 639 640 /* this will try lower page sizes first */ 641 static void * 642 malloc_heap_alloc_on_heap_id(const char *type, size_t size, 643 unsigned int heap_id, unsigned int flags, size_t align, 644 size_t bound, bool contig) 645 { 646 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 647 struct malloc_heap *heap = &mcfg->malloc_heaps[heap_id]; 648 unsigned int size_flags = flags & ~RTE_MEMZONE_SIZE_HINT_ONLY; 649 int socket_id; 650 void *ret; 651 const struct internal_config *internal_conf = 652 eal_get_internal_configuration(); 653 654 rte_spinlock_lock(&(heap->lock)); 655 656 align = align == 0 ? 1 : align; 657 658 /* for legacy mode, try once and with all flags */ 659 if (internal_conf->legacy_mem) { 660 ret = heap_alloc(heap, type, size, flags, align, bound, contig); 661 goto alloc_unlock; 662 } 663 664 /* 665 * we do not pass the size hint here, because even if allocation fails, 666 * we may still be able to allocate memory from appropriate page sizes, 667 * we just need to request more memory first. 668 */ 669 670 socket_id = rte_socket_id_by_idx(heap_id); 671 /* 672 * if socket ID is negative, we cannot find a socket ID for this heap - 673 * which means it's an external heap. those can have unexpected page 674 * sizes, so if the user asked to allocate from there - assume user 675 * knows what they're doing, and allow allocating from there with any 676 * page size flags. 677 */ 678 if (socket_id < 0) 679 size_flags |= RTE_MEMZONE_SIZE_HINT_ONLY; 680 681 ret = heap_alloc(heap, type, size, size_flags, align, bound, contig); 682 if (ret != NULL) 683 goto alloc_unlock; 684 685 /* if socket ID is invalid, this is an external heap */ 686 if (socket_id < 0) 687 goto alloc_unlock; 688 689 if (!alloc_more_mem_on_socket(heap, size, socket_id, flags, align, 690 bound, contig)) { 691 ret = heap_alloc(heap, type, size, flags, align, bound, contig); 692 693 /* this should have succeeded */ 694 if (ret == NULL) 695 RTE_LOG(ERR, EAL, "Error allocating from heap\n"); 696 } 697 alloc_unlock: 698 rte_spinlock_unlock(&(heap->lock)); 699 return ret; 700 } 701 702 static unsigned int 703 malloc_get_numa_socket(void) 704 { 705 const struct internal_config *conf = eal_get_internal_configuration(); 706 unsigned int socket_id = rte_socket_id(); 707 unsigned int idx; 708 709 if (socket_id != (unsigned int)SOCKET_ID_ANY) 710 return socket_id; 711 712 /* for control threads, return first socket where memory is available */ 713 for (idx = 0; idx < rte_socket_count(); idx++) { 714 socket_id = rte_socket_id_by_idx(idx); 715 if (conf->socket_mem[socket_id] != 0) 716 return socket_id; 717 } 718 719 return rte_socket_id_by_idx(0); 720 } 721 722 void * 723 malloc_heap_alloc(const char *type, size_t size, int socket_arg, 724 unsigned int flags, size_t align, size_t bound, bool contig) 725 { 726 int socket, heap_id, i; 727 void *ret; 728 729 /* return NULL if size is 0 or alignment is not power-of-2 */ 730 if (size == 0 || (align && !rte_is_power_of_2(align))) 731 return NULL; 732 733 if (!rte_eal_has_hugepages() && socket_arg < RTE_MAX_NUMA_NODES) 734 socket_arg = SOCKET_ID_ANY; 735 736 if (socket_arg == SOCKET_ID_ANY) 737 socket = malloc_get_numa_socket(); 738 else 739 socket = socket_arg; 740 741 /* turn socket ID into heap ID */ 742 heap_id = malloc_socket_to_heap_id(socket); 743 /* if heap id is negative, socket ID was invalid */ 744 if (heap_id < 0) 745 return NULL; 746 747 ret = malloc_heap_alloc_on_heap_id(type, size, heap_id, flags, align, 748 bound, contig); 749 if (ret != NULL || socket_arg != SOCKET_ID_ANY) 750 return ret; 751 752 /* try other heaps. we are only iterating through native DPDK sockets, 753 * so external heaps won't be included. 754 */ 755 for (i = 0; i < (int) rte_socket_count(); i++) { 756 if (i == heap_id) 757 continue; 758 ret = malloc_heap_alloc_on_heap_id(type, size, i, flags, align, 759 bound, contig); 760 if (ret != NULL) 761 return ret; 762 } 763 return NULL; 764 } 765 766 static void * 767 heap_alloc_biggest_on_heap_id(const char *type, unsigned int heap_id, 768 unsigned int flags, size_t align, bool contig) 769 { 770 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 771 struct malloc_heap *heap = &mcfg->malloc_heaps[heap_id]; 772 void *ret; 773 774 rte_spinlock_lock(&(heap->lock)); 775 776 align = align == 0 ? 1 : align; 777 778 ret = heap_alloc_biggest(heap, type, flags, align, contig); 779 780 rte_spinlock_unlock(&(heap->lock)); 781 782 return ret; 783 } 784 785 void * 786 malloc_heap_alloc_biggest(const char *type, int socket_arg, unsigned int flags, 787 size_t align, bool contig) 788 { 789 int socket, i, cur_socket, heap_id; 790 void *ret; 791 792 /* return NULL if align is not power-of-2 */ 793 if ((align && !rte_is_power_of_2(align))) 794 return NULL; 795 796 if (!rte_eal_has_hugepages()) 797 socket_arg = SOCKET_ID_ANY; 798 799 if (socket_arg == SOCKET_ID_ANY) 800 socket = malloc_get_numa_socket(); 801 else 802 socket = socket_arg; 803 804 /* turn socket ID into heap ID */ 805 heap_id = malloc_socket_to_heap_id(socket); 806 /* if heap id is negative, socket ID was invalid */ 807 if (heap_id < 0) 808 return NULL; 809 810 ret = heap_alloc_biggest_on_heap_id(type, heap_id, flags, align, 811 contig); 812 if (ret != NULL || socket_arg != SOCKET_ID_ANY) 813 return ret; 814 815 /* try other heaps */ 816 for (i = 0; i < (int) rte_socket_count(); i++) { 817 cur_socket = rte_socket_id_by_idx(i); 818 if (cur_socket == socket) 819 continue; 820 ret = heap_alloc_biggest_on_heap_id(type, i, flags, align, 821 contig); 822 if (ret != NULL) 823 return ret; 824 } 825 return NULL; 826 } 827 828 /* this function is exposed in malloc_mp.h */ 829 int 830 malloc_heap_free_pages(void *aligned_start, size_t aligned_len) 831 { 832 int n_segs, seg_idx, max_seg_idx; 833 struct rte_memseg_list *msl; 834 size_t page_sz; 835 836 msl = rte_mem_virt2memseg_list(aligned_start); 837 if (msl == NULL) 838 return -1; 839 840 page_sz = (size_t)msl->page_sz; 841 n_segs = aligned_len / page_sz; 842 seg_idx = RTE_PTR_DIFF(aligned_start, msl->base_va) / page_sz; 843 max_seg_idx = seg_idx + n_segs; 844 845 for (; seg_idx < max_seg_idx; seg_idx++) { 846 struct rte_memseg *ms; 847 848 ms = rte_fbarray_get(&msl->memseg_arr, seg_idx); 849 eal_memalloc_free_seg(ms); 850 } 851 return 0; 852 } 853 854 int 855 malloc_heap_free(struct malloc_elem *elem) 856 { 857 struct malloc_heap *heap; 858 void *start, *aligned_start, *end, *aligned_end; 859 size_t len, aligned_len, page_sz; 860 struct rte_memseg_list *msl; 861 unsigned int i, n_segs, before_space, after_space; 862 int ret; 863 const struct internal_config *internal_conf = 864 eal_get_internal_configuration(); 865 866 if (!malloc_elem_cookies_ok(elem) || elem->state != ELEM_BUSY) 867 return -1; 868 869 asan_clear_redzone(elem); 870 871 /* elem may be merged with previous element, so keep heap address */ 872 heap = elem->heap; 873 msl = elem->msl; 874 page_sz = (size_t)msl->page_sz; 875 876 rte_spinlock_lock(&(heap->lock)); 877 878 void *asan_ptr = RTE_PTR_ADD(elem, MALLOC_ELEM_HEADER_LEN + elem->pad); 879 size_t asan_data_len = elem->size - MALLOC_ELEM_OVERHEAD - elem->pad; 880 881 /* mark element as free */ 882 elem->state = ELEM_FREE; 883 884 elem = malloc_elem_free(elem); 885 886 /* anything after this is a bonus */ 887 ret = 0; 888 889 /* ...of which we can't avail if we are in legacy mode, or if this is an 890 * externally allocated segment. 891 */ 892 if (internal_conf->legacy_mem || (msl->external > 0)) 893 goto free_unlock; 894 895 /* check if we can free any memory back to the system */ 896 if (elem->size < page_sz) 897 goto free_unlock; 898 899 /* if user requested to match allocations, the sizes must match - if not, 900 * we will defer freeing these hugepages until the entire original allocation 901 * can be freed 902 */ 903 if (internal_conf->match_allocations && elem->size != elem->orig_size) 904 goto free_unlock; 905 906 /* probably, but let's make sure, as we may not be using up full page */ 907 start = elem; 908 len = elem->size; 909 aligned_start = RTE_PTR_ALIGN_CEIL(start, page_sz); 910 end = RTE_PTR_ADD(elem, len); 911 aligned_end = RTE_PTR_ALIGN_FLOOR(end, page_sz); 912 913 aligned_len = RTE_PTR_DIFF(aligned_end, aligned_start); 914 915 /* can't free anything */ 916 if (aligned_len < page_sz) 917 goto free_unlock; 918 919 /* we can free something. however, some of these pages may be marked as 920 * unfreeable, so also check that as well 921 */ 922 n_segs = aligned_len / page_sz; 923 for (i = 0; i < n_segs; i++) { 924 const struct rte_memseg *tmp = 925 rte_mem_virt2memseg(aligned_start, msl); 926 927 if (tmp->flags & RTE_MEMSEG_FLAG_DO_NOT_FREE) { 928 /* this is an unfreeable segment, so move start */ 929 aligned_start = RTE_PTR_ADD(tmp->addr, tmp->len); 930 } 931 } 932 933 /* recalculate length and number of segments */ 934 aligned_len = RTE_PTR_DIFF(aligned_end, aligned_start); 935 n_segs = aligned_len / page_sz; 936 937 /* check if we can still free some pages */ 938 if (n_segs == 0) 939 goto free_unlock; 940 941 /* We're not done yet. We also have to check if by freeing space we will 942 * be leaving free elements that are too small to store new elements. 943 * Check if we have enough space in the beginning and at the end, or if 944 * start/end are exactly page aligned. 945 */ 946 before_space = RTE_PTR_DIFF(aligned_start, elem); 947 after_space = RTE_PTR_DIFF(end, aligned_end); 948 if (before_space != 0 && 949 before_space < MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { 950 /* There is not enough space before start, but we may be able to 951 * move the start forward by one page. 952 */ 953 if (n_segs == 1) 954 goto free_unlock; 955 956 /* move start */ 957 aligned_start = RTE_PTR_ADD(aligned_start, page_sz); 958 aligned_len -= page_sz; 959 n_segs--; 960 } 961 if (after_space != 0 && after_space < 962 MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE) { 963 /* There is not enough space after end, but we may be able to 964 * move the end backwards by one page. 965 */ 966 if (n_segs == 1) 967 goto free_unlock; 968 969 /* move end */ 970 aligned_end = RTE_PTR_SUB(aligned_end, page_sz); 971 aligned_len -= page_sz; 972 n_segs--; 973 } 974 975 /* now we can finally free us some pages */ 976 977 rte_mcfg_mem_write_lock(); 978 979 /* 980 * we allow secondary processes to clear the heap of this allocated 981 * memory because it is safe to do so, as even if notifications about 982 * unmapped pages don't make it to other processes, heap is shared 983 * across all processes, and will become empty of this memory anyway, 984 * and nothing can allocate it back unless primary process will be able 985 * to deliver allocation message to every single running process. 986 */ 987 988 malloc_elem_free_list_remove(elem); 989 990 malloc_elem_hide_region(elem, (void *) aligned_start, aligned_len); 991 992 heap->total_size -= aligned_len; 993 994 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 995 /* notify user about changes in memory map */ 996 eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, 997 aligned_start, aligned_len); 998 999 /* don't care if any of this fails */ 1000 malloc_heap_free_pages(aligned_start, aligned_len); 1001 1002 request_sync(); 1003 } else { 1004 struct malloc_mp_req req; 1005 1006 memset(&req, 0, sizeof(req)); 1007 1008 req.t = REQ_TYPE_FREE; 1009 req.free_req.addr = aligned_start; 1010 req.free_req.len = aligned_len; 1011 1012 /* 1013 * we request primary to deallocate pages, but we don't do it 1014 * in this thread. instead, we notify primary that we would like 1015 * to deallocate pages, and this process will receive another 1016 * request (in parallel) that will do it for us on another 1017 * thread. 1018 * 1019 * we also don't really care if this succeeds - the data is 1020 * already removed from the heap, so it is, for all intents and 1021 * purposes, hidden from the rest of DPDK even if some other 1022 * process (including this one) may have these pages mapped. 1023 * 1024 * notifications about deallocated memory happen during sync. 1025 */ 1026 request_to_primary(&req); 1027 } 1028 1029 RTE_LOG(DEBUG, EAL, "Heap on socket %d was shrunk by %zdMB\n", 1030 msl->socket_id, aligned_len >> 20ULL); 1031 1032 rte_mcfg_mem_write_unlock(); 1033 free_unlock: 1034 asan_set_freezone(asan_ptr, asan_data_len); 1035 1036 rte_spinlock_unlock(&(heap->lock)); 1037 return ret; 1038 } 1039 1040 int 1041 malloc_heap_resize(struct malloc_elem *elem, size_t size) 1042 { 1043 int ret; 1044 1045 if (!malloc_elem_cookies_ok(elem) || elem->state != ELEM_BUSY) 1046 return -1; 1047 1048 rte_spinlock_lock(&(elem->heap->lock)); 1049 1050 ret = malloc_elem_resize(elem, size); 1051 1052 rte_spinlock_unlock(&(elem->heap->lock)); 1053 1054 return ret; 1055 } 1056 1057 /* 1058 * Function to retrieve data for a given heap 1059 */ 1060 int 1061 malloc_heap_get_stats(struct malloc_heap *heap, 1062 struct rte_malloc_socket_stats *socket_stats) 1063 { 1064 size_t idx; 1065 struct malloc_elem *elem; 1066 1067 rte_spinlock_lock(&heap->lock); 1068 1069 /* Initialise variables for heap */ 1070 socket_stats->free_count = 0; 1071 socket_stats->heap_freesz_bytes = 0; 1072 socket_stats->greatest_free_size = 0; 1073 1074 /* Iterate through free list */ 1075 for (idx = 0; idx < RTE_HEAP_NUM_FREELISTS; idx++) { 1076 for (elem = LIST_FIRST(&heap->free_head[idx]); 1077 !!elem; elem = LIST_NEXT(elem, free_list)) 1078 { 1079 socket_stats->free_count++; 1080 socket_stats->heap_freesz_bytes += elem->size; 1081 if (elem->size > socket_stats->greatest_free_size) 1082 socket_stats->greatest_free_size = elem->size; 1083 } 1084 } 1085 /* Get stats on overall heap and allocated memory on this heap */ 1086 socket_stats->heap_totalsz_bytes = heap->total_size; 1087 socket_stats->heap_allocsz_bytes = (socket_stats->heap_totalsz_bytes - 1088 socket_stats->heap_freesz_bytes); 1089 socket_stats->alloc_count = heap->alloc_count; 1090 1091 rte_spinlock_unlock(&heap->lock); 1092 return 0; 1093 } 1094 1095 /* 1096 * Function to retrieve data for a given heap 1097 */ 1098 void 1099 malloc_heap_dump(struct malloc_heap *heap, FILE *f) 1100 { 1101 struct malloc_elem *elem; 1102 1103 rte_spinlock_lock(&heap->lock); 1104 1105 fprintf(f, "Heap size: 0x%zx\n", heap->total_size); 1106 fprintf(f, "Heap alloc count: %u\n", heap->alloc_count); 1107 1108 elem = heap->first; 1109 while (elem) { 1110 malloc_elem_dump(elem, f); 1111 elem = elem->next; 1112 } 1113 1114 rte_spinlock_unlock(&heap->lock); 1115 } 1116 1117 static int 1118 destroy_elem(struct malloc_elem *elem, size_t len) 1119 { 1120 struct malloc_heap *heap = elem->heap; 1121 1122 /* notify all subscribers that a memory area is going to be removed */ 1123 eal_memalloc_mem_event_notify(RTE_MEM_EVENT_FREE, elem, len); 1124 1125 /* this element can be removed */ 1126 malloc_elem_free_list_remove(elem); 1127 malloc_elem_hide_region(elem, elem, len); 1128 1129 heap->total_size -= len; 1130 1131 memset(elem, 0, sizeof(*elem)); 1132 1133 return 0; 1134 } 1135 1136 struct rte_memseg_list * 1137 malloc_heap_create_external_seg(void *va_addr, rte_iova_t iova_addrs[], 1138 unsigned int n_pages, size_t page_sz, const char *seg_name, 1139 unsigned int socket_id) 1140 { 1141 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 1142 char fbarray_name[RTE_FBARRAY_NAME_LEN]; 1143 struct rte_memseg_list *msl = NULL; 1144 struct rte_fbarray *arr; 1145 size_t seg_len = n_pages * page_sz; 1146 unsigned int i; 1147 1148 /* first, find a free memseg list */ 1149 for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) { 1150 struct rte_memseg_list *tmp = &mcfg->memsegs[i]; 1151 if (tmp->base_va == NULL) { 1152 msl = tmp; 1153 break; 1154 } 1155 } 1156 if (msl == NULL) { 1157 RTE_LOG(ERR, EAL, "Couldn't find empty memseg list\n"); 1158 rte_errno = ENOSPC; 1159 return NULL; 1160 } 1161 1162 snprintf(fbarray_name, sizeof(fbarray_name), "%s_%p", 1163 seg_name, va_addr); 1164 1165 /* create the backing fbarray */ 1166 if (rte_fbarray_init(&msl->memseg_arr, fbarray_name, n_pages, 1167 sizeof(struct rte_memseg)) < 0) { 1168 RTE_LOG(ERR, EAL, "Couldn't create fbarray backing the memseg list\n"); 1169 return NULL; 1170 } 1171 arr = &msl->memseg_arr; 1172 1173 /* fbarray created, fill it up */ 1174 for (i = 0; i < n_pages; i++) { 1175 struct rte_memseg *ms; 1176 1177 rte_fbarray_set_used(arr, i); 1178 ms = rte_fbarray_get(arr, i); 1179 ms->addr = RTE_PTR_ADD(va_addr, i * page_sz); 1180 ms->iova = iova_addrs == NULL ? RTE_BAD_IOVA : iova_addrs[i]; 1181 ms->hugepage_sz = page_sz; 1182 ms->len = page_sz; 1183 ms->nchannel = rte_memory_get_nchannel(); 1184 ms->nrank = rte_memory_get_nrank(); 1185 ms->socket_id = socket_id; 1186 } 1187 1188 /* set up the memseg list */ 1189 msl->base_va = va_addr; 1190 msl->page_sz = page_sz; 1191 msl->socket_id = socket_id; 1192 msl->len = seg_len; 1193 msl->version = 0; 1194 msl->external = 1; 1195 1196 return msl; 1197 } 1198 1199 struct extseg_walk_arg { 1200 void *va_addr; 1201 size_t len; 1202 struct rte_memseg_list *msl; 1203 }; 1204 1205 static int 1206 extseg_walk(const struct rte_memseg_list *msl, void *arg) 1207 { 1208 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 1209 struct extseg_walk_arg *wa = arg; 1210 1211 if (msl->base_va == wa->va_addr && msl->len == wa->len) { 1212 unsigned int found_idx; 1213 1214 /* msl is const */ 1215 found_idx = msl - mcfg->memsegs; 1216 wa->msl = &mcfg->memsegs[found_idx]; 1217 return 1; 1218 } 1219 return 0; 1220 } 1221 1222 struct rte_memseg_list * 1223 malloc_heap_find_external_seg(void *va_addr, size_t len) 1224 { 1225 struct extseg_walk_arg wa; 1226 int res; 1227 1228 wa.va_addr = va_addr; 1229 wa.len = len; 1230 1231 res = rte_memseg_list_walk_thread_unsafe(extseg_walk, &wa); 1232 1233 if (res != 1) { 1234 /* 0 means nothing was found, -1 shouldn't happen */ 1235 if (res == 0) 1236 rte_errno = ENOENT; 1237 return NULL; 1238 } 1239 return wa.msl; 1240 } 1241 1242 int 1243 malloc_heap_destroy_external_seg(struct rte_memseg_list *msl) 1244 { 1245 /* destroy the fbarray backing this memory */ 1246 if (rte_fbarray_destroy(&msl->memseg_arr) < 0) 1247 return -1; 1248 1249 /* reset the memseg list */ 1250 memset(msl, 0, sizeof(*msl)); 1251 1252 return 0; 1253 } 1254 1255 int 1256 malloc_heap_add_external_memory(struct malloc_heap *heap, 1257 struct rte_memseg_list *msl) 1258 { 1259 /* erase contents of new memory */ 1260 memset(msl->base_va, 0, msl->len); 1261 1262 /* now, add newly minted memory to the malloc heap */ 1263 malloc_heap_add_memory(heap, msl, msl->base_va, msl->len); 1264 1265 heap->total_size += msl->len; 1266 1267 /* all done! */ 1268 RTE_LOG(DEBUG, EAL, "Added segment for heap %s starting at %p\n", 1269 heap->name, msl->base_va); 1270 1271 /* notify all subscribers that a new memory area has been added */ 1272 eal_memalloc_mem_event_notify(RTE_MEM_EVENT_ALLOC, 1273 msl->base_va, msl->len); 1274 1275 return 0; 1276 } 1277 1278 int 1279 malloc_heap_remove_external_memory(struct malloc_heap *heap, void *va_addr, 1280 size_t len) 1281 { 1282 struct malloc_elem *elem = heap->first; 1283 1284 /* find element with specified va address */ 1285 while (elem != NULL && elem != va_addr) { 1286 elem = elem->next; 1287 /* stop if we've blown past our VA */ 1288 if (elem > (struct malloc_elem *)va_addr) { 1289 rte_errno = ENOENT; 1290 return -1; 1291 } 1292 } 1293 /* check if element was found */ 1294 if (elem == NULL || elem->msl->len != len) { 1295 rte_errno = ENOENT; 1296 return -1; 1297 } 1298 /* if element's size is not equal to segment len, segment is busy */ 1299 if (elem->state == ELEM_BUSY || elem->size != len) { 1300 rte_errno = EBUSY; 1301 return -1; 1302 } 1303 return destroy_elem(elem, len); 1304 } 1305 1306 int 1307 malloc_heap_create(struct malloc_heap *heap, const char *heap_name) 1308 { 1309 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 1310 uint32_t next_socket_id = mcfg->next_socket_id; 1311 1312 /* prevent overflow. did you really create 2 billion heaps??? */ 1313 if (next_socket_id > INT32_MAX) { 1314 RTE_LOG(ERR, EAL, "Cannot assign new socket ID's\n"); 1315 rte_errno = ENOSPC; 1316 return -1; 1317 } 1318 1319 /* initialize empty heap */ 1320 heap->alloc_count = 0; 1321 heap->first = NULL; 1322 heap->last = NULL; 1323 LIST_INIT(heap->free_head); 1324 rte_spinlock_init(&heap->lock); 1325 heap->total_size = 0; 1326 heap->socket_id = next_socket_id; 1327 1328 /* we hold a global mem hotplug writelock, so it's safe to increment */ 1329 mcfg->next_socket_id++; 1330 1331 /* set up name */ 1332 strlcpy(heap->name, heap_name, RTE_HEAP_NAME_MAX_LEN); 1333 return 0; 1334 } 1335 1336 int 1337 malloc_heap_destroy(struct malloc_heap *heap) 1338 { 1339 if (heap->alloc_count != 0) { 1340 RTE_LOG(ERR, EAL, "Heap is still in use\n"); 1341 rte_errno = EBUSY; 1342 return -1; 1343 } 1344 if (heap->first != NULL || heap->last != NULL) { 1345 RTE_LOG(ERR, EAL, "Heap still contains memory segments\n"); 1346 rte_errno = EBUSY; 1347 return -1; 1348 } 1349 if (heap->total_size != 0) 1350 RTE_LOG(ERR, EAL, "Total size not zero, heap is likely corrupt\n"); 1351 1352 /* after this, the lock will be dropped */ 1353 memset(heap, 0, sizeof(*heap)); 1354 1355 return 0; 1356 } 1357 1358 int 1359 rte_eal_malloc_heap_init(void) 1360 { 1361 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; 1362 unsigned int i; 1363 const struct internal_config *internal_conf = 1364 eal_get_internal_configuration(); 1365 1366 if (internal_conf->match_allocations) 1367 RTE_LOG(DEBUG, EAL, "Hugepages will be freed exactly as allocated.\n"); 1368 1369 if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 1370 /* assign min socket ID to external heaps */ 1371 mcfg->next_socket_id = EXTERNAL_HEAP_MIN_SOCKET_ID; 1372 1373 /* assign names to default DPDK heaps */ 1374 for (i = 0; i < rte_socket_count(); i++) { 1375 struct malloc_heap *heap = &mcfg->malloc_heaps[i]; 1376 char heap_name[RTE_HEAP_NAME_MAX_LEN]; 1377 int socket_id = rte_socket_id_by_idx(i); 1378 1379 snprintf(heap_name, sizeof(heap_name), 1380 "socket_%i", socket_id); 1381 strlcpy(heap->name, heap_name, RTE_HEAP_NAME_MAX_LEN); 1382 heap->socket_id = socket_id; 1383 } 1384 } 1385 1386 1387 if (register_mp_requests()) { 1388 RTE_LOG(ERR, EAL, "Couldn't register malloc multiprocess actions\n"); 1389 rte_mcfg_mem_read_unlock(); 1390 return -1; 1391 } 1392 1393 /* unlock mem hotplug here. it's safe for primary as no requests can 1394 * even come before primary itself is fully initialized, and secondaries 1395 * do not need to initialize the heap. 1396 */ 1397 rte_mcfg_mem_read_unlock(); 1398 1399 /* secondary process does not need to initialize anything */ 1400 if (rte_eal_process_type() != RTE_PROC_PRIMARY) 1401 return 0; 1402 1403 /* add all IOVA-contiguous areas to the heap */ 1404 return rte_memseg_contig_walk(malloc_add_seg, NULL); 1405 } 1406