1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright(c) 2016 6WIND S.A. 4 */ 5 6 #include <stdbool.h> 7 #include <stdio.h> 8 #include <string.h> 9 #include <stdint.h> 10 #include <unistd.h> 11 #include <inttypes.h> 12 #include <errno.h> 13 #include <sys/queue.h> 14 15 #include <rte_common.h> 16 #include <rte_log.h> 17 #include <rte_debug.h> 18 #include <rte_memory.h> 19 #include <rte_memzone.h> 20 #include <rte_malloc.h> 21 #include <rte_eal.h> 22 #include <rte_eal_memconfig.h> 23 #include <rte_errno.h> 24 #include <rte_string_fns.h> 25 #include <rte_tailq.h> 26 #include <rte_eal_paging.h> 27 #include <rte_telemetry.h> 28 29 #include "rte_mempool.h" 30 #include "rte_mempool_trace.h" 31 32 TAILQ_HEAD(rte_mempool_list, rte_tailq_entry); 33 34 static struct rte_tailq_elem rte_mempool_tailq = { 35 .name = "RTE_MEMPOOL", 36 }; 37 EAL_REGISTER_TAILQ(rte_mempool_tailq) 38 39 TAILQ_HEAD(mempool_callback_list, rte_tailq_entry); 40 41 static struct rte_tailq_elem callback_tailq = { 42 .name = "RTE_MEMPOOL_CALLBACK", 43 }; 44 EAL_REGISTER_TAILQ(callback_tailq) 45 46 /* Invoke all registered mempool event callbacks. */ 47 static void 48 mempool_event_callback_invoke(enum rte_mempool_event event, 49 struct rte_mempool *mp); 50 51 #define CACHE_FLUSHTHRESH_MULTIPLIER 1.5 52 #define CALC_CACHE_FLUSHTHRESH(c) \ 53 ((typeof(c))((c) * CACHE_FLUSHTHRESH_MULTIPLIER)) 54 55 #if defined(RTE_ARCH_X86) 56 /* 57 * return the greatest common divisor between a and b (fast algorithm) 58 * 59 */ 60 static unsigned get_gcd(unsigned a, unsigned b) 61 { 62 unsigned c; 63 64 if (0 == a) 65 return b; 66 if (0 == b) 67 return a; 68 69 if (a < b) { 70 c = a; 71 a = b; 72 b = c; 73 } 74 75 while (b != 0) { 76 c = a % b; 77 a = b; 78 b = c; 79 } 80 81 return a; 82 } 83 84 /* 85 * Depending on memory configuration on x86 arch, objects addresses are spread 86 * between channels and ranks in RAM: the pool allocator will add 87 * padding between objects. This function return the new size of the 88 * object. 89 */ 90 static unsigned int 91 arch_mem_object_align(unsigned int obj_size) 92 { 93 unsigned nrank, nchan; 94 unsigned new_obj_size; 95 96 /* get number of channels */ 97 nchan = rte_memory_get_nchannel(); 98 if (nchan == 0) 99 nchan = 4; 100 101 nrank = rte_memory_get_nrank(); 102 if (nrank == 0) 103 nrank = 1; 104 105 /* process new object size */ 106 new_obj_size = (obj_size + RTE_MEMPOOL_ALIGN_MASK) / RTE_MEMPOOL_ALIGN; 107 while (get_gcd(new_obj_size, nrank * nchan) != 1) 108 new_obj_size++; 109 return new_obj_size * RTE_MEMPOOL_ALIGN; 110 } 111 #else 112 static unsigned int 113 arch_mem_object_align(unsigned int obj_size) 114 { 115 return obj_size; 116 } 117 #endif 118 119 struct pagesz_walk_arg { 120 int socket_id; 121 size_t min; 122 }; 123 124 static int 125 find_min_pagesz(const struct rte_memseg_list *msl, void *arg) 126 { 127 struct pagesz_walk_arg *wa = arg; 128 bool valid; 129 130 /* 131 * we need to only look at page sizes available for a particular socket 132 * ID. so, we either need an exact match on socket ID (can match both 133 * native and external memory), or, if SOCKET_ID_ANY was specified as a 134 * socket ID argument, we must only look at native memory and ignore any 135 * page sizes associated with external memory. 136 */ 137 valid = msl->socket_id == wa->socket_id; 138 valid |= wa->socket_id == SOCKET_ID_ANY && msl->external == 0; 139 140 if (valid && msl->page_sz < wa->min) 141 wa->min = msl->page_sz; 142 143 return 0; 144 } 145 146 static size_t 147 get_min_page_size(int socket_id) 148 { 149 struct pagesz_walk_arg wa; 150 151 wa.min = SIZE_MAX; 152 wa.socket_id = socket_id; 153 154 rte_memseg_list_walk(find_min_pagesz, &wa); 155 156 return wa.min == SIZE_MAX ? (size_t) rte_mem_page_size() : wa.min; 157 } 158 159 160 static void 161 mempool_add_elem(struct rte_mempool *mp, __rte_unused void *opaque, 162 void *obj, rte_iova_t iova) 163 { 164 struct rte_mempool_objhdr *hdr; 165 struct rte_mempool_objtlr *tlr __rte_unused; 166 167 /* set mempool ptr in header */ 168 hdr = RTE_PTR_SUB(obj, sizeof(*hdr)); 169 hdr->mp = mp; 170 hdr->iova = iova; 171 STAILQ_INSERT_TAIL(&mp->elt_list, hdr, next); 172 mp->populated_size++; 173 174 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 175 hdr->cookie = RTE_MEMPOOL_HEADER_COOKIE2; 176 tlr = rte_mempool_get_trailer(obj); 177 tlr->cookie = RTE_MEMPOOL_TRAILER_COOKIE; 178 #endif 179 } 180 181 /* call obj_cb() for each mempool element */ 182 uint32_t 183 rte_mempool_obj_iter(struct rte_mempool *mp, 184 rte_mempool_obj_cb_t *obj_cb, void *obj_cb_arg) 185 { 186 struct rte_mempool_objhdr *hdr; 187 void *obj; 188 unsigned n = 0; 189 190 STAILQ_FOREACH(hdr, &mp->elt_list, next) { 191 obj = (char *)hdr + sizeof(*hdr); 192 obj_cb(mp, obj_cb_arg, obj, n); 193 n++; 194 } 195 196 return n; 197 } 198 199 /* call mem_cb() for each mempool memory chunk */ 200 uint32_t 201 rte_mempool_mem_iter(struct rte_mempool *mp, 202 rte_mempool_mem_cb_t *mem_cb, void *mem_cb_arg) 203 { 204 struct rte_mempool_memhdr *hdr; 205 unsigned n = 0; 206 207 STAILQ_FOREACH(hdr, &mp->mem_list, next) { 208 mem_cb(mp, mem_cb_arg, hdr, n); 209 n++; 210 } 211 212 return n; 213 } 214 215 /* get the header, trailer and total size of a mempool element. */ 216 uint32_t 217 rte_mempool_calc_obj_size(uint32_t elt_size, uint32_t flags, 218 struct rte_mempool_objsz *sz) 219 { 220 struct rte_mempool_objsz lsz; 221 222 sz = (sz != NULL) ? sz : &lsz; 223 224 sz->header_size = sizeof(struct rte_mempool_objhdr); 225 if ((flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN) == 0) 226 sz->header_size = RTE_ALIGN_CEIL(sz->header_size, 227 RTE_MEMPOOL_ALIGN); 228 229 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 230 sz->trailer_size = sizeof(struct rte_mempool_objtlr); 231 #else 232 sz->trailer_size = 0; 233 #endif 234 235 /* element size is 8 bytes-aligned at least */ 236 sz->elt_size = RTE_ALIGN_CEIL(elt_size, sizeof(uint64_t)); 237 238 /* expand trailer to next cache line */ 239 if ((flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN) == 0) { 240 sz->total_size = sz->header_size + sz->elt_size + 241 sz->trailer_size; 242 sz->trailer_size += ((RTE_MEMPOOL_ALIGN - 243 (sz->total_size & RTE_MEMPOOL_ALIGN_MASK)) & 244 RTE_MEMPOOL_ALIGN_MASK); 245 } 246 247 /* 248 * increase trailer to add padding between objects in order to 249 * spread them across memory channels/ranks 250 */ 251 if ((flags & RTE_MEMPOOL_F_NO_SPREAD) == 0) { 252 unsigned new_size; 253 new_size = arch_mem_object_align 254 (sz->header_size + sz->elt_size + sz->trailer_size); 255 sz->trailer_size = new_size - sz->header_size - sz->elt_size; 256 } 257 258 /* this is the size of an object, including header and trailer */ 259 sz->total_size = sz->header_size + sz->elt_size + sz->trailer_size; 260 261 return sz->total_size; 262 } 263 264 /* free a memchunk allocated with rte_memzone_reserve() */ 265 static void 266 rte_mempool_memchunk_mz_free(__rte_unused struct rte_mempool_memhdr *memhdr, 267 void *opaque) 268 { 269 const struct rte_memzone *mz = opaque; 270 rte_memzone_free(mz); 271 } 272 273 /* Free memory chunks used by a mempool. Objects must be in pool */ 274 static void 275 rte_mempool_free_memchunks(struct rte_mempool *mp) 276 { 277 struct rte_mempool_memhdr *memhdr; 278 void *elt; 279 280 while (!STAILQ_EMPTY(&mp->elt_list)) { 281 rte_mempool_ops_dequeue_bulk(mp, &elt, 1); 282 (void)elt; 283 STAILQ_REMOVE_HEAD(&mp->elt_list, next); 284 mp->populated_size--; 285 } 286 287 while (!STAILQ_EMPTY(&mp->mem_list)) { 288 memhdr = STAILQ_FIRST(&mp->mem_list); 289 STAILQ_REMOVE_HEAD(&mp->mem_list, next); 290 if (memhdr->free_cb != NULL) 291 memhdr->free_cb(memhdr, memhdr->opaque); 292 rte_free(memhdr); 293 mp->nb_mem_chunks--; 294 } 295 } 296 297 static int 298 mempool_ops_alloc_once(struct rte_mempool *mp) 299 { 300 int ret; 301 302 /* create the internal ring if not already done */ 303 if ((mp->flags & RTE_MEMPOOL_F_POOL_CREATED) == 0) { 304 ret = rte_mempool_ops_alloc(mp); 305 if (ret != 0) 306 return ret; 307 mp->flags |= RTE_MEMPOOL_F_POOL_CREATED; 308 } 309 return 0; 310 } 311 312 /* Add objects in the pool, using a physically contiguous memory 313 * zone. Return the number of objects added, or a negative value 314 * on error. 315 */ 316 int 317 rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr, 318 rte_iova_t iova, size_t len, rte_mempool_memchunk_free_cb_t *free_cb, 319 void *opaque) 320 { 321 unsigned i = 0; 322 size_t off; 323 struct rte_mempool_memhdr *memhdr; 324 int ret; 325 326 ret = mempool_ops_alloc_once(mp); 327 if (ret != 0) 328 return ret; 329 330 /* mempool is already populated */ 331 if (mp->populated_size >= mp->size) 332 return -ENOSPC; 333 334 memhdr = rte_zmalloc("MEMPOOL_MEMHDR", sizeof(*memhdr), 0); 335 if (memhdr == NULL) 336 return -ENOMEM; 337 338 memhdr->mp = mp; 339 memhdr->addr = vaddr; 340 memhdr->iova = iova; 341 memhdr->len = len; 342 memhdr->free_cb = free_cb; 343 memhdr->opaque = opaque; 344 345 if (mp->flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN) 346 off = RTE_PTR_ALIGN_CEIL(vaddr, 8) - vaddr; 347 else 348 off = RTE_PTR_ALIGN_CEIL(vaddr, RTE_MEMPOOL_ALIGN) - vaddr; 349 350 if (off > len) { 351 ret = 0; 352 goto fail; 353 } 354 355 i = rte_mempool_ops_populate(mp, mp->size - mp->populated_size, 356 (char *)vaddr + off, 357 (iova == RTE_BAD_IOVA) ? RTE_BAD_IOVA : (iova + off), 358 len - off, mempool_add_elem, NULL); 359 360 /* not enough room to store one object */ 361 if (i == 0) { 362 ret = 0; 363 goto fail; 364 } 365 366 STAILQ_INSERT_TAIL(&mp->mem_list, memhdr, next); 367 mp->nb_mem_chunks++; 368 369 /* Check if at least some objects in the pool are now usable for IO. */ 370 if (!(mp->flags & RTE_MEMPOOL_F_NO_IOVA_CONTIG) && iova != RTE_BAD_IOVA) 371 mp->flags &= ~RTE_MEMPOOL_F_NON_IO; 372 373 /* Report the mempool as ready only when fully populated. */ 374 if (mp->populated_size >= mp->size) 375 mempool_event_callback_invoke(RTE_MEMPOOL_EVENT_READY, mp); 376 377 rte_mempool_trace_populate_iova(mp, vaddr, iova, len, free_cb, opaque); 378 return i; 379 380 fail: 381 rte_free(memhdr); 382 return ret; 383 } 384 385 static rte_iova_t 386 get_iova(void *addr) 387 { 388 struct rte_memseg *ms; 389 390 /* try registered memory first */ 391 ms = rte_mem_virt2memseg(addr, NULL); 392 if (ms == NULL || ms->iova == RTE_BAD_IOVA) 393 /* fall back to actual physical address */ 394 return rte_mem_virt2iova(addr); 395 return ms->iova + RTE_PTR_DIFF(addr, ms->addr); 396 } 397 398 /* Populate the mempool with a virtual area. Return the number of 399 * objects added, or a negative value on error. 400 */ 401 int 402 rte_mempool_populate_virt(struct rte_mempool *mp, char *addr, 403 size_t len, size_t pg_sz, rte_mempool_memchunk_free_cb_t *free_cb, 404 void *opaque) 405 { 406 rte_iova_t iova; 407 size_t off, phys_len; 408 int ret, cnt = 0; 409 410 if (mp->flags & RTE_MEMPOOL_F_NO_IOVA_CONTIG) 411 return rte_mempool_populate_iova(mp, addr, RTE_BAD_IOVA, 412 len, free_cb, opaque); 413 414 for (off = 0; off < len && 415 mp->populated_size < mp->size; off += phys_len) { 416 417 iova = get_iova(addr + off); 418 419 /* populate with the largest group of contiguous pages */ 420 for (phys_len = RTE_MIN( 421 (size_t)(RTE_PTR_ALIGN_CEIL(addr + off + 1, pg_sz) - 422 (addr + off)), 423 len - off); 424 off + phys_len < len; 425 phys_len = RTE_MIN(phys_len + pg_sz, len - off)) { 426 rte_iova_t iova_tmp; 427 428 iova_tmp = get_iova(addr + off + phys_len); 429 430 if (iova_tmp == RTE_BAD_IOVA || 431 iova_tmp != iova + phys_len) 432 break; 433 } 434 435 ret = rte_mempool_populate_iova(mp, addr + off, iova, 436 phys_len, free_cb, opaque); 437 if (ret == 0) 438 continue; 439 if (ret < 0) 440 goto fail; 441 /* no need to call the free callback for next chunks */ 442 free_cb = NULL; 443 cnt += ret; 444 } 445 446 rte_mempool_trace_populate_virt(mp, addr, len, pg_sz, free_cb, opaque); 447 return cnt; 448 449 fail: 450 rte_mempool_free_memchunks(mp); 451 return ret; 452 } 453 454 /* Get the minimal page size used in a mempool before populating it. */ 455 int 456 rte_mempool_get_page_size(struct rte_mempool *mp, size_t *pg_sz) 457 { 458 bool need_iova_contig_obj; 459 bool alloc_in_ext_mem; 460 int ret; 461 462 /* check if we can retrieve a valid socket ID */ 463 ret = rte_malloc_heap_socket_is_external(mp->socket_id); 464 if (ret < 0) 465 return -EINVAL; 466 alloc_in_ext_mem = (ret == 1); 467 need_iova_contig_obj = !(mp->flags & RTE_MEMPOOL_F_NO_IOVA_CONTIG); 468 469 if (!need_iova_contig_obj) 470 *pg_sz = 0; 471 else if (rte_eal_has_hugepages() || alloc_in_ext_mem) 472 *pg_sz = get_min_page_size(mp->socket_id); 473 else 474 *pg_sz = rte_mem_page_size(); 475 476 rte_mempool_trace_get_page_size(mp, *pg_sz); 477 return 0; 478 } 479 480 /* Default function to populate the mempool: allocate memory in memzones, 481 * and populate them. Return the number of objects added, or a negative 482 * value on error. 483 */ 484 int 485 rte_mempool_populate_default(struct rte_mempool *mp) 486 { 487 unsigned int mz_flags = RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY; 488 char mz_name[RTE_MEMZONE_NAMESIZE]; 489 const struct rte_memzone *mz; 490 ssize_t mem_size; 491 size_t align, pg_sz, pg_shift = 0; 492 rte_iova_t iova; 493 unsigned mz_id, n; 494 int ret; 495 bool need_iova_contig_obj; 496 size_t max_alloc_size = SIZE_MAX; 497 498 ret = mempool_ops_alloc_once(mp); 499 if (ret != 0) 500 return ret; 501 502 /* mempool must not be populated */ 503 if (mp->nb_mem_chunks != 0) 504 return -EEXIST; 505 506 /* 507 * the following section calculates page shift and page size values. 508 * 509 * these values impact the result of calc_mem_size operation, which 510 * returns the amount of memory that should be allocated to store the 511 * desired number of objects. when not zero, it allocates more memory 512 * for the padding between objects, to ensure that an object does not 513 * cross a page boundary. in other words, page size/shift are to be set 514 * to zero if mempool elements won't care about page boundaries. 515 * there are several considerations for page size and page shift here. 516 * 517 * if we don't need our mempools to have physically contiguous objects, 518 * then just set page shift and page size to 0, because the user has 519 * indicated that there's no need to care about anything. 520 * 521 * if we do need contiguous objects (if a mempool driver has its 522 * own calc_size() method returning min_chunk_size = mem_size), 523 * there is also an option to reserve the entire mempool memory 524 * as one contiguous block of memory. 525 * 526 * if we require contiguous objects, but not necessarily the entire 527 * mempool reserved space to be contiguous, pg_sz will be != 0, 528 * and the default ops->populate() will take care of not placing 529 * objects across pages. 530 * 531 * if our IO addresses are physical, we may get memory from bigger 532 * pages, or we might get memory from smaller pages, and how much of it 533 * we require depends on whether we want bigger or smaller pages. 534 * However, requesting each and every memory size is too much work, so 535 * what we'll do instead is walk through the page sizes available, pick 536 * the smallest one and set up page shift to match that one. We will be 537 * wasting some space this way, but it's much nicer than looping around 538 * trying to reserve each and every page size. 539 * 540 * If we fail to get enough contiguous memory, then we'll go and 541 * reserve space in smaller chunks. 542 */ 543 544 need_iova_contig_obj = !(mp->flags & RTE_MEMPOOL_F_NO_IOVA_CONTIG); 545 ret = rte_mempool_get_page_size(mp, &pg_sz); 546 if (ret < 0) 547 return ret; 548 549 if (pg_sz != 0) 550 pg_shift = rte_bsf32(pg_sz); 551 552 for (mz_id = 0, n = mp->size; n > 0; mz_id++, n -= ret) { 553 size_t min_chunk_size; 554 555 mem_size = rte_mempool_ops_calc_mem_size( 556 mp, n, pg_shift, &min_chunk_size, &align); 557 558 if (mem_size < 0) { 559 ret = mem_size; 560 goto fail; 561 } 562 563 ret = snprintf(mz_name, sizeof(mz_name), 564 RTE_MEMPOOL_MZ_FORMAT "_%d", mp->name, mz_id); 565 if (ret < 0 || ret >= (int)sizeof(mz_name)) { 566 ret = -ENAMETOOLONG; 567 goto fail; 568 } 569 570 /* if we're trying to reserve contiguous memory, add appropriate 571 * memzone flag. 572 */ 573 if (min_chunk_size == (size_t)mem_size) 574 mz_flags |= RTE_MEMZONE_IOVA_CONTIG; 575 576 /* Allocate a memzone, retrying with a smaller area on ENOMEM */ 577 do { 578 mz = rte_memzone_reserve_aligned(mz_name, 579 RTE_MIN((size_t)mem_size, max_alloc_size), 580 mp->socket_id, mz_flags, align); 581 582 if (mz != NULL || rte_errno != ENOMEM) 583 break; 584 585 max_alloc_size = RTE_MIN(max_alloc_size, 586 (size_t)mem_size) / 2; 587 } while (mz == NULL && max_alloc_size >= min_chunk_size); 588 589 if (mz == NULL) { 590 ret = -rte_errno; 591 goto fail; 592 } 593 594 if (need_iova_contig_obj) 595 iova = mz->iova; 596 else 597 iova = RTE_BAD_IOVA; 598 599 if (pg_sz == 0 || (mz_flags & RTE_MEMZONE_IOVA_CONTIG)) 600 ret = rte_mempool_populate_iova(mp, mz->addr, 601 iova, mz->len, 602 rte_mempool_memchunk_mz_free, 603 (void *)(uintptr_t)mz); 604 else 605 ret = rte_mempool_populate_virt(mp, mz->addr, 606 mz->len, pg_sz, 607 rte_mempool_memchunk_mz_free, 608 (void *)(uintptr_t)mz); 609 if (ret == 0) /* should not happen */ 610 ret = -ENOBUFS; 611 if (ret < 0) { 612 rte_memzone_free(mz); 613 goto fail; 614 } 615 } 616 617 rte_mempool_trace_populate_default(mp); 618 return mp->size; 619 620 fail: 621 rte_mempool_free_memchunks(mp); 622 return ret; 623 } 624 625 /* return the memory size required for mempool objects in anonymous mem */ 626 static ssize_t 627 get_anon_size(const struct rte_mempool *mp) 628 { 629 ssize_t size; 630 size_t pg_sz, pg_shift; 631 size_t min_chunk_size; 632 size_t align; 633 634 pg_sz = rte_mem_page_size(); 635 pg_shift = rte_bsf32(pg_sz); 636 size = rte_mempool_ops_calc_mem_size(mp, mp->size, pg_shift, 637 &min_chunk_size, &align); 638 639 return size; 640 } 641 642 /* unmap a memory zone mapped by rte_mempool_populate_anon() */ 643 static void 644 rte_mempool_memchunk_anon_free(struct rte_mempool_memhdr *memhdr, 645 void *opaque) 646 { 647 ssize_t size; 648 649 /* 650 * Calculate size since memhdr->len has contiguous chunk length 651 * which may be smaller if anon map is split into many contiguous 652 * chunks. Result must be the same as we calculated on populate. 653 */ 654 size = get_anon_size(memhdr->mp); 655 if (size < 0) 656 return; 657 658 rte_mem_unmap(opaque, size); 659 } 660 661 /* populate the mempool with an anonymous mapping */ 662 int 663 rte_mempool_populate_anon(struct rte_mempool *mp) 664 { 665 ssize_t size; 666 int ret; 667 char *addr; 668 669 /* mempool is already populated, error */ 670 if ((!STAILQ_EMPTY(&mp->mem_list)) || mp->nb_mem_chunks != 0) { 671 rte_errno = EINVAL; 672 return 0; 673 } 674 675 ret = mempool_ops_alloc_once(mp); 676 if (ret < 0) { 677 rte_errno = -ret; 678 return 0; 679 } 680 681 size = get_anon_size(mp); 682 if (size < 0) { 683 rte_errno = -size; 684 return 0; 685 } 686 687 /* get chunk of virtually continuous memory */ 688 addr = rte_mem_map(NULL, size, RTE_PROT_READ | RTE_PROT_WRITE, 689 RTE_MAP_SHARED | RTE_MAP_ANONYMOUS, -1, 0); 690 if (addr == NULL) 691 return 0; 692 /* can't use MMAP_LOCKED, it does not exist on BSD */ 693 if (rte_mem_lock(addr, size) < 0) { 694 rte_mem_unmap(addr, size); 695 return 0; 696 } 697 698 ret = rte_mempool_populate_virt(mp, addr, size, rte_mem_page_size(), 699 rte_mempool_memchunk_anon_free, addr); 700 if (ret == 0) /* should not happen */ 701 ret = -ENOBUFS; 702 if (ret < 0) { 703 rte_errno = -ret; 704 goto fail; 705 } 706 707 rte_mempool_trace_populate_anon(mp); 708 return mp->populated_size; 709 710 fail: 711 rte_mempool_free_memchunks(mp); 712 return 0; 713 } 714 715 /* free a mempool */ 716 void 717 rte_mempool_free(struct rte_mempool *mp) 718 { 719 struct rte_mempool_list *mempool_list = NULL; 720 struct rte_tailq_entry *te; 721 722 if (mp == NULL) 723 return; 724 725 mempool_list = RTE_TAILQ_CAST(rte_mempool_tailq.head, rte_mempool_list); 726 rte_mcfg_tailq_write_lock(); 727 /* find out tailq entry */ 728 TAILQ_FOREACH(te, mempool_list, next) { 729 if (te->data == (void *)mp) 730 break; 731 } 732 733 if (te != NULL) { 734 TAILQ_REMOVE(mempool_list, te, next); 735 rte_free(te); 736 } 737 rte_mcfg_tailq_write_unlock(); 738 739 mempool_event_callback_invoke(RTE_MEMPOOL_EVENT_DESTROY, mp); 740 rte_mempool_trace_free(mp); 741 rte_mempool_free_memchunks(mp); 742 rte_mempool_ops_free(mp); 743 rte_memzone_free(mp->mz); 744 } 745 746 static void 747 mempool_cache_init(struct rte_mempool_cache *cache, uint32_t size) 748 { 749 cache->size = size; 750 cache->flushthresh = CALC_CACHE_FLUSHTHRESH(size); 751 cache->len = 0; 752 } 753 754 /* 755 * Create and initialize a cache for objects that are retrieved from and 756 * returned to an underlying mempool. This structure is identical to the 757 * local_cache[lcore_id] pointed to by the mempool structure. 758 */ 759 struct rte_mempool_cache * 760 rte_mempool_cache_create(uint32_t size, int socket_id) 761 { 762 struct rte_mempool_cache *cache; 763 764 if (size == 0 || size > RTE_MEMPOOL_CACHE_MAX_SIZE) { 765 rte_errno = EINVAL; 766 return NULL; 767 } 768 769 cache = rte_zmalloc_socket("MEMPOOL_CACHE", sizeof(*cache), 770 RTE_CACHE_LINE_SIZE, socket_id); 771 if (cache == NULL) { 772 RTE_LOG(ERR, MEMPOOL, "Cannot allocate mempool cache.\n"); 773 rte_errno = ENOMEM; 774 return NULL; 775 } 776 777 mempool_cache_init(cache, size); 778 779 rte_mempool_trace_cache_create(size, socket_id, cache); 780 return cache; 781 } 782 783 /* 784 * Free a cache. It's the responsibility of the user to make sure that any 785 * remaining objects in the cache are flushed to the corresponding 786 * mempool. 787 */ 788 void 789 rte_mempool_cache_free(struct rte_mempool_cache *cache) 790 { 791 rte_mempool_trace_cache_free(cache); 792 rte_free(cache); 793 } 794 795 /* create an empty mempool */ 796 struct rte_mempool * 797 rte_mempool_create_empty(const char *name, unsigned n, unsigned elt_size, 798 unsigned cache_size, unsigned private_data_size, 799 int socket_id, unsigned flags) 800 { 801 char mz_name[RTE_MEMZONE_NAMESIZE]; 802 struct rte_mempool_list *mempool_list; 803 struct rte_mempool *mp = NULL; 804 struct rte_tailq_entry *te = NULL; 805 const struct rte_memzone *mz = NULL; 806 size_t mempool_size; 807 unsigned int mz_flags = RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY; 808 struct rte_mempool_objsz objsz; 809 unsigned lcore_id; 810 int ret; 811 812 /* compilation-time checks */ 813 RTE_BUILD_BUG_ON((sizeof(struct rte_mempool) & 814 RTE_CACHE_LINE_MASK) != 0); 815 RTE_BUILD_BUG_ON((sizeof(struct rte_mempool_cache) & 816 RTE_CACHE_LINE_MASK) != 0); 817 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 818 RTE_BUILD_BUG_ON((sizeof(struct rte_mempool_debug_stats) & 819 RTE_CACHE_LINE_MASK) != 0); 820 RTE_BUILD_BUG_ON((offsetof(struct rte_mempool, stats) & 821 RTE_CACHE_LINE_MASK) != 0); 822 #endif 823 824 mempool_list = RTE_TAILQ_CAST(rte_mempool_tailq.head, rte_mempool_list); 825 826 /* asked for zero items */ 827 if (n == 0) { 828 rte_errno = EINVAL; 829 return NULL; 830 } 831 832 /* asked cache too big */ 833 if (cache_size > RTE_MEMPOOL_CACHE_MAX_SIZE || 834 CALC_CACHE_FLUSHTHRESH(cache_size) > n) { 835 rte_errno = EINVAL; 836 return NULL; 837 } 838 839 /* enforce only user flags are passed by the application */ 840 if ((flags & ~RTE_MEMPOOL_VALID_USER_FLAGS) != 0) { 841 rte_errno = EINVAL; 842 return NULL; 843 } 844 845 /* 846 * No objects in the pool can be used for IO until it's populated 847 * with at least some objects with valid IOVA. 848 */ 849 flags |= RTE_MEMPOOL_F_NON_IO; 850 851 /* "no cache align" imply "no spread" */ 852 if (flags & RTE_MEMPOOL_F_NO_CACHE_ALIGN) 853 flags |= RTE_MEMPOOL_F_NO_SPREAD; 854 855 /* calculate mempool object sizes. */ 856 if (!rte_mempool_calc_obj_size(elt_size, flags, &objsz)) { 857 rte_errno = EINVAL; 858 return NULL; 859 } 860 861 rte_mcfg_mempool_write_lock(); 862 863 /* 864 * reserve a memory zone for this mempool: private data is 865 * cache-aligned 866 */ 867 private_data_size = (private_data_size + 868 RTE_MEMPOOL_ALIGN_MASK) & (~RTE_MEMPOOL_ALIGN_MASK); 869 870 871 /* try to allocate tailq entry */ 872 te = rte_zmalloc("MEMPOOL_TAILQ_ENTRY", sizeof(*te), 0); 873 if (te == NULL) { 874 RTE_LOG(ERR, MEMPOOL, "Cannot allocate tailq entry!\n"); 875 goto exit_unlock; 876 } 877 878 mempool_size = RTE_MEMPOOL_HEADER_SIZE(mp, cache_size); 879 mempool_size += private_data_size; 880 mempool_size = RTE_ALIGN_CEIL(mempool_size, RTE_MEMPOOL_ALIGN); 881 882 ret = snprintf(mz_name, sizeof(mz_name), RTE_MEMPOOL_MZ_FORMAT, name); 883 if (ret < 0 || ret >= (int)sizeof(mz_name)) { 884 rte_errno = ENAMETOOLONG; 885 goto exit_unlock; 886 } 887 888 mz = rte_memzone_reserve(mz_name, mempool_size, socket_id, mz_flags); 889 if (mz == NULL) 890 goto exit_unlock; 891 892 /* init the mempool structure */ 893 mp = mz->addr; 894 memset(mp, 0, RTE_MEMPOOL_HEADER_SIZE(mp, cache_size)); 895 ret = strlcpy(mp->name, name, sizeof(mp->name)); 896 if (ret < 0 || ret >= (int)sizeof(mp->name)) { 897 rte_errno = ENAMETOOLONG; 898 goto exit_unlock; 899 } 900 mp->mz = mz; 901 mp->size = n; 902 mp->flags = flags; 903 mp->socket_id = socket_id; 904 mp->elt_size = objsz.elt_size; 905 mp->header_size = objsz.header_size; 906 mp->trailer_size = objsz.trailer_size; 907 /* Size of default caches, zero means disabled. */ 908 mp->cache_size = cache_size; 909 mp->private_data_size = private_data_size; 910 STAILQ_INIT(&mp->elt_list); 911 STAILQ_INIT(&mp->mem_list); 912 913 /* 914 * local_cache pointer is set even if cache_size is zero. 915 * The local_cache points to just past the elt_pa[] array. 916 */ 917 mp->local_cache = (struct rte_mempool_cache *) 918 RTE_PTR_ADD(mp, RTE_MEMPOOL_HEADER_SIZE(mp, 0)); 919 920 /* Init all default caches. */ 921 if (cache_size != 0) { 922 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) 923 mempool_cache_init(&mp->local_cache[lcore_id], 924 cache_size); 925 } 926 927 te->data = mp; 928 929 rte_mcfg_tailq_write_lock(); 930 TAILQ_INSERT_TAIL(mempool_list, te, next); 931 rte_mcfg_tailq_write_unlock(); 932 rte_mcfg_mempool_write_unlock(); 933 934 rte_mempool_trace_create_empty(name, n, elt_size, cache_size, 935 private_data_size, flags, mp); 936 return mp; 937 938 exit_unlock: 939 rte_mcfg_mempool_write_unlock(); 940 rte_free(te); 941 rte_mempool_free(mp); 942 return NULL; 943 } 944 945 /* create the mempool */ 946 struct rte_mempool * 947 rte_mempool_create(const char *name, unsigned n, unsigned elt_size, 948 unsigned cache_size, unsigned private_data_size, 949 rte_mempool_ctor_t *mp_init, void *mp_init_arg, 950 rte_mempool_obj_cb_t *obj_init, void *obj_init_arg, 951 int socket_id, unsigned flags) 952 { 953 int ret; 954 struct rte_mempool *mp; 955 956 mp = rte_mempool_create_empty(name, n, elt_size, cache_size, 957 private_data_size, socket_id, flags); 958 if (mp == NULL) 959 return NULL; 960 961 /* 962 * Since we have 4 combinations of the SP/SC/MP/MC examine the flags to 963 * set the correct index into the table of ops structs. 964 */ 965 if ((flags & RTE_MEMPOOL_F_SP_PUT) && (flags & RTE_MEMPOOL_F_SC_GET)) 966 ret = rte_mempool_set_ops_byname(mp, "ring_sp_sc", NULL); 967 else if (flags & RTE_MEMPOOL_F_SP_PUT) 968 ret = rte_mempool_set_ops_byname(mp, "ring_sp_mc", NULL); 969 else if (flags & RTE_MEMPOOL_F_SC_GET) 970 ret = rte_mempool_set_ops_byname(mp, "ring_mp_sc", NULL); 971 else 972 ret = rte_mempool_set_ops_byname(mp, "ring_mp_mc", NULL); 973 974 if (ret) 975 goto fail; 976 977 /* call the mempool priv initializer */ 978 if (mp_init) 979 mp_init(mp, mp_init_arg); 980 981 if (rte_mempool_populate_default(mp) < 0) 982 goto fail; 983 984 /* call the object initializers */ 985 if (obj_init) 986 rte_mempool_obj_iter(mp, obj_init, obj_init_arg); 987 988 rte_mempool_trace_create(name, n, elt_size, cache_size, 989 private_data_size, mp_init, mp_init_arg, obj_init, 990 obj_init_arg, flags, mp); 991 return mp; 992 993 fail: 994 rte_mempool_free(mp); 995 return NULL; 996 } 997 998 /* Return the number of entries in the mempool */ 999 unsigned int 1000 rte_mempool_avail_count(const struct rte_mempool *mp) 1001 { 1002 unsigned count; 1003 unsigned lcore_id; 1004 1005 count = rte_mempool_ops_get_count(mp); 1006 1007 if (mp->cache_size == 0) 1008 return count; 1009 1010 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) 1011 count += mp->local_cache[lcore_id].len; 1012 1013 /* 1014 * due to race condition (access to len is not locked), the 1015 * total can be greater than size... so fix the result 1016 */ 1017 if (count > mp->size) 1018 return mp->size; 1019 return count; 1020 } 1021 1022 /* return the number of entries allocated from the mempool */ 1023 unsigned int 1024 rte_mempool_in_use_count(const struct rte_mempool *mp) 1025 { 1026 return mp->size - rte_mempool_avail_count(mp); 1027 } 1028 1029 /* dump the cache status */ 1030 static unsigned 1031 rte_mempool_dump_cache(FILE *f, const struct rte_mempool *mp) 1032 { 1033 unsigned lcore_id; 1034 unsigned count = 0; 1035 unsigned cache_count; 1036 1037 fprintf(f, " internal cache infos:\n"); 1038 fprintf(f, " cache_size=%"PRIu32"\n", mp->cache_size); 1039 1040 if (mp->cache_size == 0) 1041 return count; 1042 1043 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 1044 cache_count = mp->local_cache[lcore_id].len; 1045 fprintf(f, " cache_count[%u]=%"PRIu32"\n", 1046 lcore_id, cache_count); 1047 count += cache_count; 1048 } 1049 fprintf(f, " total_cache_count=%u\n", count); 1050 return count; 1051 } 1052 1053 #ifndef __INTEL_COMPILER 1054 #pragma GCC diagnostic ignored "-Wcast-qual" 1055 #endif 1056 1057 /* check and update cookies or panic (internal) */ 1058 void rte_mempool_check_cookies(const struct rte_mempool *mp, 1059 void * const *obj_table_const, unsigned n, int free) 1060 { 1061 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 1062 struct rte_mempool_objhdr *hdr; 1063 struct rte_mempool_objtlr *tlr; 1064 uint64_t cookie; 1065 void *tmp; 1066 void *obj; 1067 void **obj_table; 1068 1069 /* Force to drop the "const" attribute. This is done only when 1070 * DEBUG is enabled */ 1071 tmp = (void *) obj_table_const; 1072 obj_table = tmp; 1073 1074 while (n--) { 1075 obj = obj_table[n]; 1076 1077 if (rte_mempool_from_obj(obj) != mp) 1078 rte_panic("MEMPOOL: object is owned by another " 1079 "mempool\n"); 1080 1081 hdr = rte_mempool_get_header(obj); 1082 cookie = hdr->cookie; 1083 1084 if (free == 0) { 1085 if (cookie != RTE_MEMPOOL_HEADER_COOKIE1) { 1086 RTE_LOG(CRIT, MEMPOOL, 1087 "obj=%p, mempool=%p, cookie=%" PRIx64 "\n", 1088 obj, (const void *) mp, cookie); 1089 rte_panic("MEMPOOL: bad header cookie (put)\n"); 1090 } 1091 hdr->cookie = RTE_MEMPOOL_HEADER_COOKIE2; 1092 } else if (free == 1) { 1093 if (cookie != RTE_MEMPOOL_HEADER_COOKIE2) { 1094 RTE_LOG(CRIT, MEMPOOL, 1095 "obj=%p, mempool=%p, cookie=%" PRIx64 "\n", 1096 obj, (const void *) mp, cookie); 1097 rte_panic("MEMPOOL: bad header cookie (get)\n"); 1098 } 1099 hdr->cookie = RTE_MEMPOOL_HEADER_COOKIE1; 1100 } else if (free == 2) { 1101 if (cookie != RTE_MEMPOOL_HEADER_COOKIE1 && 1102 cookie != RTE_MEMPOOL_HEADER_COOKIE2) { 1103 RTE_LOG(CRIT, MEMPOOL, 1104 "obj=%p, mempool=%p, cookie=%" PRIx64 "\n", 1105 obj, (const void *) mp, cookie); 1106 rte_panic("MEMPOOL: bad header cookie (audit)\n"); 1107 } 1108 } 1109 tlr = rte_mempool_get_trailer(obj); 1110 cookie = tlr->cookie; 1111 if (cookie != RTE_MEMPOOL_TRAILER_COOKIE) { 1112 RTE_LOG(CRIT, MEMPOOL, 1113 "obj=%p, mempool=%p, cookie=%" PRIx64 "\n", 1114 obj, (const void *) mp, cookie); 1115 rte_panic("MEMPOOL: bad trailer cookie\n"); 1116 } 1117 } 1118 #else 1119 RTE_SET_USED(mp); 1120 RTE_SET_USED(obj_table_const); 1121 RTE_SET_USED(n); 1122 RTE_SET_USED(free); 1123 #endif 1124 } 1125 1126 void 1127 rte_mempool_contig_blocks_check_cookies(const struct rte_mempool *mp, 1128 void * const *first_obj_table_const, unsigned int n, int free) 1129 { 1130 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 1131 struct rte_mempool_info info; 1132 const size_t total_elt_sz = 1133 mp->header_size + mp->elt_size + mp->trailer_size; 1134 unsigned int i, j; 1135 1136 rte_mempool_ops_get_info(mp, &info); 1137 1138 for (i = 0; i < n; ++i) { 1139 void *first_obj = first_obj_table_const[i]; 1140 1141 for (j = 0; j < info.contig_block_size; ++j) { 1142 void *obj; 1143 1144 obj = (void *)((uintptr_t)first_obj + j * total_elt_sz); 1145 rte_mempool_check_cookies(mp, &obj, 1, free); 1146 } 1147 } 1148 #else 1149 RTE_SET_USED(mp); 1150 RTE_SET_USED(first_obj_table_const); 1151 RTE_SET_USED(n); 1152 RTE_SET_USED(free); 1153 #endif 1154 } 1155 1156 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 1157 static void 1158 mempool_obj_audit(struct rte_mempool *mp, __rte_unused void *opaque, 1159 void *obj, __rte_unused unsigned idx) 1160 { 1161 RTE_MEMPOOL_CHECK_COOKIES(mp, &obj, 1, 2); 1162 } 1163 1164 static void 1165 mempool_audit_cookies(struct rte_mempool *mp) 1166 { 1167 unsigned num; 1168 1169 num = rte_mempool_obj_iter(mp, mempool_obj_audit, NULL); 1170 if (num != mp->size) { 1171 rte_panic("rte_mempool_obj_iter(mempool=%p, size=%u) " 1172 "iterated only over %u elements\n", 1173 mp, mp->size, num); 1174 } 1175 } 1176 #else 1177 #define mempool_audit_cookies(mp) do {} while(0) 1178 #endif 1179 1180 #ifndef __INTEL_COMPILER 1181 #pragma GCC diagnostic error "-Wcast-qual" 1182 #endif 1183 1184 /* check cookies before and after objects */ 1185 static void 1186 mempool_audit_cache(const struct rte_mempool *mp) 1187 { 1188 /* check cache size consistency */ 1189 unsigned lcore_id; 1190 1191 if (mp->cache_size == 0) 1192 return; 1193 1194 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 1195 const struct rte_mempool_cache *cache; 1196 cache = &mp->local_cache[lcore_id]; 1197 if (cache->len > RTE_DIM(cache->objs)) { 1198 RTE_LOG(CRIT, MEMPOOL, "badness on cache[%u]\n", 1199 lcore_id); 1200 rte_panic("MEMPOOL: invalid cache len\n"); 1201 } 1202 } 1203 } 1204 1205 /* check the consistency of mempool (size, cookies, ...) */ 1206 void 1207 rte_mempool_audit(struct rte_mempool *mp) 1208 { 1209 mempool_audit_cache(mp); 1210 mempool_audit_cookies(mp); 1211 1212 /* For case where mempool DEBUG is not set, and cache size is 0 */ 1213 RTE_SET_USED(mp); 1214 } 1215 1216 /* dump the status of the mempool on the console */ 1217 void 1218 rte_mempool_dump(FILE *f, struct rte_mempool *mp) 1219 { 1220 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 1221 struct rte_mempool_info info; 1222 struct rte_mempool_debug_stats sum; 1223 unsigned lcore_id; 1224 #endif 1225 struct rte_mempool_memhdr *memhdr; 1226 struct rte_mempool_ops *ops; 1227 unsigned common_count; 1228 unsigned cache_count; 1229 size_t mem_len = 0; 1230 1231 RTE_ASSERT(f != NULL); 1232 RTE_ASSERT(mp != NULL); 1233 1234 fprintf(f, "mempool <%s>@%p\n", mp->name, mp); 1235 fprintf(f, " flags=%x\n", mp->flags); 1236 fprintf(f, " socket_id=%d\n", mp->socket_id); 1237 fprintf(f, " pool=%p\n", mp->pool_data); 1238 fprintf(f, " iova=0x%" PRIx64 "\n", mp->mz->iova); 1239 fprintf(f, " nb_mem_chunks=%u\n", mp->nb_mem_chunks); 1240 fprintf(f, " size=%"PRIu32"\n", mp->size); 1241 fprintf(f, " populated_size=%"PRIu32"\n", mp->populated_size); 1242 fprintf(f, " header_size=%"PRIu32"\n", mp->header_size); 1243 fprintf(f, " elt_size=%"PRIu32"\n", mp->elt_size); 1244 fprintf(f, " trailer_size=%"PRIu32"\n", mp->trailer_size); 1245 fprintf(f, " total_obj_size=%"PRIu32"\n", 1246 mp->header_size + mp->elt_size + mp->trailer_size); 1247 1248 fprintf(f, " private_data_size=%"PRIu32"\n", mp->private_data_size); 1249 1250 fprintf(f, " ops_index=%d\n", mp->ops_index); 1251 ops = rte_mempool_get_ops(mp->ops_index); 1252 fprintf(f, " ops_name: <%s>\n", (ops != NULL) ? ops->name : "NA"); 1253 1254 STAILQ_FOREACH(memhdr, &mp->mem_list, next) 1255 mem_len += memhdr->len; 1256 if (mem_len != 0) { 1257 fprintf(f, " avg bytes/object=%#Lf\n", 1258 (long double)mem_len / mp->size); 1259 } 1260 1261 cache_count = rte_mempool_dump_cache(f, mp); 1262 common_count = rte_mempool_ops_get_count(mp); 1263 if ((cache_count + common_count) > mp->size) 1264 common_count = mp->size - cache_count; 1265 fprintf(f, " common_pool_count=%u\n", common_count); 1266 1267 /* sum and dump statistics */ 1268 #ifdef RTE_LIBRTE_MEMPOOL_DEBUG 1269 rte_mempool_ops_get_info(mp, &info); 1270 memset(&sum, 0, sizeof(sum)); 1271 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 1272 sum.put_bulk += mp->stats[lcore_id].put_bulk; 1273 sum.put_objs += mp->stats[lcore_id].put_objs; 1274 sum.put_common_pool_bulk += mp->stats[lcore_id].put_common_pool_bulk; 1275 sum.put_common_pool_objs += mp->stats[lcore_id].put_common_pool_objs; 1276 sum.get_common_pool_bulk += mp->stats[lcore_id].get_common_pool_bulk; 1277 sum.get_common_pool_objs += mp->stats[lcore_id].get_common_pool_objs; 1278 sum.get_success_bulk += mp->stats[lcore_id].get_success_bulk; 1279 sum.get_success_objs += mp->stats[lcore_id].get_success_objs; 1280 sum.get_fail_bulk += mp->stats[lcore_id].get_fail_bulk; 1281 sum.get_fail_objs += mp->stats[lcore_id].get_fail_objs; 1282 sum.get_success_blks += mp->stats[lcore_id].get_success_blks; 1283 sum.get_fail_blks += mp->stats[lcore_id].get_fail_blks; 1284 } 1285 fprintf(f, " stats:\n"); 1286 fprintf(f, " put_bulk=%"PRIu64"\n", sum.put_bulk); 1287 fprintf(f, " put_objs=%"PRIu64"\n", sum.put_objs); 1288 fprintf(f, " put_common_pool_bulk=%"PRIu64"\n", sum.put_common_pool_bulk); 1289 fprintf(f, " put_common_pool_objs=%"PRIu64"\n", sum.put_common_pool_objs); 1290 fprintf(f, " get_common_pool_bulk=%"PRIu64"\n", sum.get_common_pool_bulk); 1291 fprintf(f, " get_common_pool_objs=%"PRIu64"\n", sum.get_common_pool_objs); 1292 fprintf(f, " get_success_bulk=%"PRIu64"\n", sum.get_success_bulk); 1293 fprintf(f, " get_success_objs=%"PRIu64"\n", sum.get_success_objs); 1294 fprintf(f, " get_fail_bulk=%"PRIu64"\n", sum.get_fail_bulk); 1295 fprintf(f, " get_fail_objs=%"PRIu64"\n", sum.get_fail_objs); 1296 if (info.contig_block_size > 0) { 1297 fprintf(f, " get_success_blks=%"PRIu64"\n", 1298 sum.get_success_blks); 1299 fprintf(f, " get_fail_blks=%"PRIu64"\n", sum.get_fail_blks); 1300 } 1301 #else 1302 fprintf(f, " no statistics available\n"); 1303 #endif 1304 1305 rte_mempool_audit(mp); 1306 } 1307 1308 /* dump the status of all mempools on the console */ 1309 void 1310 rte_mempool_list_dump(FILE *f) 1311 { 1312 struct rte_mempool *mp = NULL; 1313 struct rte_tailq_entry *te; 1314 struct rte_mempool_list *mempool_list; 1315 1316 mempool_list = RTE_TAILQ_CAST(rte_mempool_tailq.head, rte_mempool_list); 1317 1318 rte_mcfg_mempool_read_lock(); 1319 1320 TAILQ_FOREACH(te, mempool_list, next) { 1321 mp = (struct rte_mempool *) te->data; 1322 rte_mempool_dump(f, mp); 1323 } 1324 1325 rte_mcfg_mempool_read_unlock(); 1326 } 1327 1328 /* search a mempool from its name */ 1329 struct rte_mempool * 1330 rte_mempool_lookup(const char *name) 1331 { 1332 struct rte_mempool *mp = NULL; 1333 struct rte_tailq_entry *te; 1334 struct rte_mempool_list *mempool_list; 1335 1336 mempool_list = RTE_TAILQ_CAST(rte_mempool_tailq.head, rte_mempool_list); 1337 1338 rte_mcfg_mempool_read_lock(); 1339 1340 TAILQ_FOREACH(te, mempool_list, next) { 1341 mp = (struct rte_mempool *) te->data; 1342 if (strncmp(name, mp->name, RTE_MEMPOOL_NAMESIZE) == 0) 1343 break; 1344 } 1345 1346 rte_mcfg_mempool_read_unlock(); 1347 1348 if (te == NULL) { 1349 rte_errno = ENOENT; 1350 return NULL; 1351 } 1352 1353 return mp; 1354 } 1355 1356 void rte_mempool_walk(void (*func)(struct rte_mempool *, void *), 1357 void *arg) 1358 { 1359 struct rte_tailq_entry *te = NULL; 1360 struct rte_mempool_list *mempool_list; 1361 void *tmp_te; 1362 1363 mempool_list = RTE_TAILQ_CAST(rte_mempool_tailq.head, rte_mempool_list); 1364 1365 rte_mcfg_mempool_read_lock(); 1366 1367 RTE_TAILQ_FOREACH_SAFE(te, mempool_list, next, tmp_te) { 1368 (*func)((struct rte_mempool *) te->data, arg); 1369 } 1370 1371 rte_mcfg_mempool_read_unlock(); 1372 } 1373 1374 struct mempool_callback_data { 1375 rte_mempool_event_callback *func; 1376 void *user_data; 1377 }; 1378 1379 static void 1380 mempool_event_callback_invoke(enum rte_mempool_event event, 1381 struct rte_mempool *mp) 1382 { 1383 struct mempool_callback_list *list; 1384 struct rte_tailq_entry *te; 1385 void *tmp_te; 1386 1387 rte_mcfg_tailq_read_lock(); 1388 list = RTE_TAILQ_CAST(callback_tailq.head, mempool_callback_list); 1389 RTE_TAILQ_FOREACH_SAFE(te, list, next, tmp_te) { 1390 struct mempool_callback_data *cb = te->data; 1391 rte_mcfg_tailq_read_unlock(); 1392 cb->func(event, mp, cb->user_data); 1393 rte_mcfg_tailq_read_lock(); 1394 } 1395 rte_mcfg_tailq_read_unlock(); 1396 } 1397 1398 int 1399 rte_mempool_event_callback_register(rte_mempool_event_callback *func, 1400 void *user_data) 1401 { 1402 struct mempool_callback_list *list; 1403 struct rte_tailq_entry *te = NULL; 1404 struct mempool_callback_data *cb; 1405 void *tmp_te; 1406 int ret; 1407 1408 if (func == NULL) { 1409 rte_errno = EINVAL; 1410 return -rte_errno; 1411 } 1412 1413 rte_mcfg_tailq_write_lock(); 1414 list = RTE_TAILQ_CAST(callback_tailq.head, mempool_callback_list); 1415 RTE_TAILQ_FOREACH_SAFE(te, list, next, tmp_te) { 1416 cb = te->data; 1417 if (cb->func == func && cb->user_data == user_data) { 1418 ret = -EEXIST; 1419 goto exit; 1420 } 1421 } 1422 1423 te = rte_zmalloc("mempool_cb_tail_entry", sizeof(*te), 0); 1424 if (te == NULL) { 1425 RTE_LOG(ERR, MEMPOOL, 1426 "Cannot allocate event callback tailq entry!\n"); 1427 ret = -ENOMEM; 1428 goto exit; 1429 } 1430 1431 cb = rte_malloc("mempool_cb_data", sizeof(*cb), 0); 1432 if (cb == NULL) { 1433 RTE_LOG(ERR, MEMPOOL, 1434 "Cannot allocate event callback!\n"); 1435 rte_free(te); 1436 ret = -ENOMEM; 1437 goto exit; 1438 } 1439 1440 cb->func = func; 1441 cb->user_data = user_data; 1442 te->data = cb; 1443 TAILQ_INSERT_TAIL(list, te, next); 1444 ret = 0; 1445 1446 exit: 1447 rte_mcfg_tailq_write_unlock(); 1448 rte_errno = -ret; 1449 return ret; 1450 } 1451 1452 int 1453 rte_mempool_event_callback_unregister(rte_mempool_event_callback *func, 1454 void *user_data) 1455 { 1456 struct mempool_callback_list *list; 1457 struct rte_tailq_entry *te = NULL; 1458 struct mempool_callback_data *cb; 1459 int ret = -ENOENT; 1460 1461 rte_mcfg_tailq_write_lock(); 1462 list = RTE_TAILQ_CAST(callback_tailq.head, mempool_callback_list); 1463 TAILQ_FOREACH(te, list, next) { 1464 cb = te->data; 1465 if (cb->func == func && cb->user_data == user_data) { 1466 TAILQ_REMOVE(list, te, next); 1467 ret = 0; 1468 break; 1469 } 1470 } 1471 rte_mcfg_tailq_write_unlock(); 1472 1473 if (ret == 0) { 1474 rte_free(te); 1475 rte_free(cb); 1476 } 1477 rte_errno = -ret; 1478 return ret; 1479 } 1480 1481 static void 1482 mempool_list_cb(struct rte_mempool *mp, void *arg) 1483 { 1484 struct rte_tel_data *d = (struct rte_tel_data *)arg; 1485 1486 rte_tel_data_add_array_string(d, mp->name); 1487 } 1488 1489 static int 1490 mempool_handle_list(const char *cmd __rte_unused, 1491 const char *params __rte_unused, struct rte_tel_data *d) 1492 { 1493 rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 1494 rte_mempool_walk(mempool_list_cb, d); 1495 return 0; 1496 } 1497 1498 struct mempool_info_cb_arg { 1499 char *pool_name; 1500 struct rte_tel_data *d; 1501 }; 1502 1503 static void 1504 mempool_info_cb(struct rte_mempool *mp, void *arg) 1505 { 1506 struct mempool_info_cb_arg *info = (struct mempool_info_cb_arg *)arg; 1507 const struct rte_memzone *mz; 1508 1509 if (strncmp(mp->name, info->pool_name, RTE_MEMZONE_NAMESIZE)) 1510 return; 1511 1512 rte_tel_data_add_dict_string(info->d, "name", mp->name); 1513 rte_tel_data_add_dict_int(info->d, "pool_id", mp->pool_id); 1514 rte_tel_data_add_dict_int(info->d, "flags", mp->flags); 1515 rte_tel_data_add_dict_int(info->d, "socket_id", mp->socket_id); 1516 rte_tel_data_add_dict_int(info->d, "size", mp->size); 1517 rte_tel_data_add_dict_int(info->d, "cache_size", mp->cache_size); 1518 rte_tel_data_add_dict_int(info->d, "elt_size", mp->elt_size); 1519 rte_tel_data_add_dict_int(info->d, "header_size", mp->header_size); 1520 rte_tel_data_add_dict_int(info->d, "trailer_size", mp->trailer_size); 1521 rte_tel_data_add_dict_int(info->d, "private_data_size", 1522 mp->private_data_size); 1523 rte_tel_data_add_dict_int(info->d, "ops_index", mp->ops_index); 1524 rte_tel_data_add_dict_int(info->d, "populated_size", 1525 mp->populated_size); 1526 1527 mz = mp->mz; 1528 rte_tel_data_add_dict_string(info->d, "mz_name", mz->name); 1529 rte_tel_data_add_dict_int(info->d, "mz_len", mz->len); 1530 rte_tel_data_add_dict_int(info->d, "mz_hugepage_sz", 1531 mz->hugepage_sz); 1532 rte_tel_data_add_dict_int(info->d, "mz_socket_id", mz->socket_id); 1533 rte_tel_data_add_dict_int(info->d, "mz_flags", mz->flags); 1534 } 1535 1536 static int 1537 mempool_handle_info(const char *cmd __rte_unused, const char *params, 1538 struct rte_tel_data *d) 1539 { 1540 struct mempool_info_cb_arg mp_arg; 1541 char name[RTE_MEMZONE_NAMESIZE]; 1542 1543 if (!params || strlen(params) == 0) 1544 return -EINVAL; 1545 1546 rte_strlcpy(name, params, RTE_MEMZONE_NAMESIZE); 1547 1548 rte_tel_data_start_dict(d); 1549 mp_arg.pool_name = name; 1550 mp_arg.d = d; 1551 rte_mempool_walk(mempool_info_cb, &mp_arg); 1552 1553 return 0; 1554 } 1555 1556 RTE_INIT(mempool_init_telemetry) 1557 { 1558 rte_telemetry_register_cmd("/mempool/list", mempool_handle_list, 1559 "Returns list of available mempool. Takes no parameters"); 1560 rte_telemetry_register_cmd("/mempool/info", mempool_handle_info, 1561 "Returns mempool info. Parameters: pool_name"); 1562 } 1563