LCOV - code coverage report
Current view: top level - lib/eal/linux - eal_memory.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 335 563 59.5 %
Date: 2025-05-01 17:49:45 Functions: 23 26 88.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 186 362 51.4 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2014 Intel Corporation.
       3                 :            :  * Copyright(c) 2013 6WIND S.A.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include <errno.h>
       7                 :            : #include <fcntl.h>
       8                 :            : #include <stdbool.h>
       9                 :            : #include <stdlib.h>
      10                 :            : #include <stdio.h>
      11                 :            : #include <stdint.h>
      12                 :            : #include <inttypes.h>
      13                 :            : #include <string.h>
      14                 :            : #include <sys/mman.h>
      15                 :            : #include <sys/stat.h>
      16                 :            : #include <sys/file.h>
      17                 :            : #include <sys/resource.h>
      18                 :            : #include <unistd.h>
      19                 :            : #include <limits.h>
      20                 :            : #include <signal.h>
      21                 :            : #include <setjmp.h>
      22                 :            : #ifdef F_ADD_SEALS /* if file sealing is supported, so is memfd */
      23                 :            : #define MEMFD_SUPPORTED
      24                 :            : #endif
      25                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
      26                 :            : #include <numa.h>
      27                 :            : #include <numaif.h>
      28                 :            : #endif
      29                 :            : 
      30                 :            : #include <rte_errno.h>
      31                 :            : #include <rte_log.h>
      32                 :            : #include <rte_memory.h>
      33                 :            : #include <rte_eal.h>
      34                 :            : #include <rte_lcore.h>
      35                 :            : #include <rte_common.h>
      36                 :            : 
      37                 :            : #include <eal_export.h>
      38                 :            : #include "eal_private.h"
      39                 :            : #include "eal_memalloc.h"
      40                 :            : #include "eal_memcfg.h"
      41                 :            : #include "eal_internal_cfg.h"
      42                 :            : #include "eal_filesystem.h"
      43                 :            : #include "eal_hugepages.h"
      44                 :            : #include "eal_options.h"
      45                 :            : 
      46                 :            : #define PFN_MASK_SIZE   8
      47                 :            : 
      48                 :            : /**
      49                 :            :  * @file
      50                 :            :  * Huge page mapping under linux
      51                 :            :  *
      52                 :            :  * To reserve a big contiguous amount of memory, we use the hugepage
      53                 :            :  * feature of linux. For that, we need to have hugetlbfs mounted. This
      54                 :            :  * code will create many files in this directory (one per page) and
      55                 :            :  * map them in virtual memory. For each page, we will retrieve its
      56                 :            :  * physical address and remap it in order to have a virtual contiguous
      57                 :            :  * zone as well as a physical contiguous zone.
      58                 :            :  */
      59                 :            : 
      60                 :            : static int phys_addrs_available = -1;
      61                 :            : 
      62                 :            : #define RANDOMIZE_VA_SPACE_FILE "/proc/sys/kernel/randomize_va_space"
      63                 :            : 
      64                 :        157 : uint64_t eal_get_baseaddr(void)
      65                 :            : {
      66                 :            :         /*
      67                 :            :          * Linux kernel uses a really high address as starting address for
      68                 :            :          * serving mmaps calls. If there exists addressing limitations and IOVA
      69                 :            :          * mode is VA, this starting address is likely too high for those
      70                 :            :          * devices. However, it is possible to use a lower address in the
      71                 :            :          * process virtual address space as with 64 bits there is a lot of
      72                 :            :          * available space.
      73                 :            :          *
      74                 :            :          * Current known limitations are 39 or 40 bits. Setting the starting
      75                 :            :          * address at 4GB implies there are 508GB or 1020GB for mapping the
      76                 :            :          * available hugepages. This is likely enough for most systems, although
      77                 :            :          * a device with addressing limitations should call
      78                 :            :          * rte_mem_check_dma_mask for ensuring all memory is within supported
      79                 :            :          * range.
      80                 :            :          */
      81                 :            : #if defined(RTE_ARCH_LOONGARCH)
      82                 :            :         return 0x7000000000ULL;
      83                 :            : #else
      84                 :        157 :         return 0x100000000ULL;
      85                 :            : #endif
      86                 :            : }
      87                 :            : 
      88                 :            : /*
      89                 :            :  * Get physical address of any mapped virtual address in the current process.
      90                 :            :  */
      91                 :            : RTE_EXPORT_SYMBOL(rte_mem_virt2phy)
      92                 :            : phys_addr_t
      93                 :       5344 : rte_mem_virt2phy(const void *virtaddr)
      94                 :            : {
      95                 :            :         int fd, retval;
      96                 :            :         uint64_t page, physaddr;
      97                 :            :         unsigned long virt_pfn;
      98                 :            :         int page_size;
      99                 :            :         off_t offset;
     100                 :            : 
     101         [ +  - ]:       5344 :         if (phys_addrs_available == 0)
     102                 :            :                 return RTE_BAD_IOVA;
     103                 :            : 
     104                 :            :         /* standard page size */
     105                 :       5344 :         page_size = getpagesize();
     106                 :            : 
     107                 :            :         fd = open("/proc/self/pagemap", O_RDONLY);
     108         [ -  + ]:       5344 :         if (fd < 0) {
     109                 :          0 :                 EAL_LOG(INFO, "%s(): cannot open /proc/self/pagemap: %s",
     110                 :            :                         __func__, strerror(errno));
     111                 :          0 :                 return RTE_BAD_IOVA;
     112                 :            :         }
     113                 :            : 
     114                 :       5344 :         virt_pfn = (unsigned long)virtaddr / page_size;
     115                 :       5344 :         offset = sizeof(uint64_t) * virt_pfn;
     116         [ -  + ]:       5344 :         if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
     117                 :          0 :                 EAL_LOG(INFO, "%s(): seek error in /proc/self/pagemap: %s",
     118                 :            :                                 __func__, strerror(errno));
     119                 :          0 :                 close(fd);
     120                 :          0 :                 return RTE_BAD_IOVA;
     121                 :            :         }
     122                 :            : 
     123                 :       5344 :         retval = read(fd, &page, PFN_MASK_SIZE);
     124                 :       5344 :         close(fd);
     125         [ -  + ]:       5344 :         if (retval < 0) {
     126                 :          0 :                 EAL_LOG(INFO, "%s(): cannot read /proc/self/pagemap: %s",
     127                 :            :                                 __func__, strerror(errno));
     128                 :          0 :                 return RTE_BAD_IOVA;
     129         [ -  + ]:       5344 :         } else if (retval != PFN_MASK_SIZE) {
     130                 :          0 :                 EAL_LOG(INFO, "%s(): read %d bytes from /proc/self/pagemap "
     131                 :            :                                 "but expected %d:",
     132                 :            :                                 __func__, retval, PFN_MASK_SIZE);
     133                 :          0 :                 return RTE_BAD_IOVA;
     134                 :            :         }
     135                 :            : 
     136                 :            :         /*
     137                 :            :          * the pfn (page frame number) are bits 0-54 (see
     138                 :            :          * pagemap.txt in linux Documentation)
     139                 :            :          */
     140         [ +  - ]:       5344 :         if ((page & 0x7fffffffffffffULL) == 0)
     141                 :            :                 return RTE_BAD_IOVA;
     142                 :            : 
     143                 :       5344 :         physaddr = ((page & 0x7fffffffffffffULL) * page_size)
     144                 :       5344 :                 + ((unsigned long)virtaddr % page_size);
     145                 :            : 
     146                 :       5344 :         return physaddr;
     147                 :            : }
     148                 :            : 
     149                 :            : RTE_EXPORT_SYMBOL(rte_mem_virt2iova)
     150                 :            : rte_iova_t
     151                 :       3212 : rte_mem_virt2iova(const void *virtaddr)
     152                 :            : {
     153         [ -  + ]:       3212 :         if (rte_eal_iova_mode() == RTE_IOVA_VA)
     154                 :          0 :                 return (uintptr_t)virtaddr;
     155                 :       3212 :         return rte_mem_virt2phy(virtaddr);
     156                 :            : }
     157                 :            : 
     158                 :            : /*
     159                 :            :  * For each hugepage in hugepg_tbl, fill the physaddr value. We find
     160                 :            :  * it by browsing the /proc/self/pagemap special file.
     161                 :            :  */
     162                 :            : static int
     163                 :          2 : find_physaddrs(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
     164                 :            : {
     165                 :            :         unsigned int i;
     166                 :            :         phys_addr_t addr;
     167                 :            : 
     168         [ +  + ]:       2048 :         for (i = 0; i < hpi->num_pages[0]; i++) {
     169                 :       2046 :                 addr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
     170         [ +  - ]:       2046 :                 if (addr == RTE_BAD_PHYS_ADDR)
     171                 :            :                         return -1;
     172                 :       2046 :                 hugepg_tbl[i].physaddr = addr;
     173                 :            :         }
     174                 :            :         return 0;
     175                 :            : }
     176                 :            : 
     177                 :            : /*
     178                 :            :  * For each hugepage in hugepg_tbl, fill the physaddr value sequentially.
     179                 :            :  */
     180                 :            : static int
     181                 :            : set_physaddrs(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
     182                 :            : {
     183                 :            :         unsigned int i;
     184                 :            :         static phys_addr_t addr;
     185                 :            : 
     186         [ #  # ]:          0 :         for (i = 0; i < hpi->num_pages[0]; i++) {
     187                 :          0 :                 hugepg_tbl[i].physaddr = addr;
     188                 :          0 :                 addr += hugepg_tbl[i].size;
     189                 :            :         }
     190                 :            :         return 0;
     191                 :            : }
     192                 :            : 
     193                 :            : /*
     194                 :            :  * Check whether address-space layout randomization is enabled in
     195                 :            :  * the kernel. This is important for multi-process as it can prevent
     196                 :            :  * two processes mapping data to the same virtual address
     197                 :            :  * Returns:
     198                 :            :  *    0 - address space randomization disabled
     199                 :            :  *    1/2 - address space randomization enabled
     200                 :            :  *    negative error code on error
     201                 :            :  */
     202                 :            : static int
     203                 :          2 : aslr_enabled(void)
     204                 :            : {
     205                 :            :         char c;
     206                 :            :         int retval, fd = open(RANDOMIZE_VA_SPACE_FILE, O_RDONLY);
     207         [ -  + ]:          2 :         if (fd < 0)
     208                 :          0 :                 return -errno;
     209                 :          2 :         retval = read(fd, &c, 1);
     210                 :          2 :         close(fd);
     211         [ -  + ]:          2 :         if (retval < 0)
     212                 :          0 :                 return -errno;
     213         [ +  - ]:          2 :         if (retval == 0)
     214                 :            :                 return -EIO;
     215         [ -  + ]:          2 :         switch (c) {
     216                 :            :                 case '0' : return 0;
     217                 :            :                 case '1' : return 1;
     218                 :            :                 case '2' : return 2;
     219                 :            :                 default: return -EINVAL;
     220                 :            :         }
     221                 :            : }
     222                 :            : 
     223                 :            : static sigjmp_buf huge_jmpenv;
     224                 :            : 
     225                 :          0 : static void huge_sigbus_handler(int signo __rte_unused)
     226                 :            : {
     227                 :          0 :         siglongjmp(huge_jmpenv, 1);
     228                 :            : }
     229                 :            : 
     230                 :            : /* Put setjmp into a wrap method to avoid compiling error. Any non-volatile,
     231                 :            :  * non-static local variable in the stack frame calling sigsetjmp might be
     232                 :            :  * clobbered by a call to longjmp.
     233                 :            :  */
     234                 :       2046 : static int huge_wrap_sigsetjmp(void)
     235                 :            : {
     236                 :       2046 :         return sigsetjmp(huge_jmpenv, 1);
     237                 :            : }
     238                 :            : 
     239                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     240                 :            : /* Callback for numa library. */
     241                 :            : void numa_error(char *where)
     242                 :            : {
     243                 :          0 :         EAL_LOG(ERR, "%s failed: %s", where, strerror(errno));
     244                 :          0 : }
     245                 :            : #endif
     246                 :            : 
     247                 :            : /*
     248                 :            :  * Mmap all hugepages of hugepage table: it first open a file in
     249                 :            :  * hugetlbfs, then mmap() hugepage_sz data in it. If orig is set, the
     250                 :            :  * virtual address is stored in hugepg_tbl[i].orig_va, else it is stored
     251                 :            :  * in hugepg_tbl[i].final_va. The second mapping (when orig is 0) tries to
     252                 :            :  * map contiguous physical blocks in contiguous virtual blocks.
     253                 :            :  */
     254                 :            : static unsigned
     255                 :          2 : map_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi,
     256                 :            :                   uint64_t *essential_memory __rte_unused)
     257                 :            : {
     258                 :            :         int fd;
     259                 :            :         unsigned i;
     260                 :            :         void *virtaddr;
     261                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     262                 :            :         int node_id = -1;
     263                 :            :         int essential_prev = 0;
     264                 :            :         int oldpolicy;
     265                 :            :         struct bitmask *oldmask = NULL;
     266                 :            :         bool have_numa = true;
     267                 :            :         unsigned long maxnode = 0;
     268                 :            :         const struct internal_config *internal_conf =
     269                 :          2 :                 eal_get_internal_configuration();
     270                 :            : 
     271                 :            :         /* Check if kernel supports NUMA. */
     272         [ +  - ]:          2 :         if (numa_available() != 0) {
     273                 :          0 :                 EAL_LOG(DEBUG, "NUMA is not supported.");
     274                 :            :                 have_numa = false;
     275                 :            :         }
     276                 :            : 
     277                 :            :         if (have_numa) {
     278                 :          2 :                 EAL_LOG(DEBUG, "Trying to obtain current memory policy.");
     279                 :          2 :                 oldmask = numa_allocate_nodemask();
     280         [ -  + ]:          2 :                 if (get_mempolicy(&oldpolicy, oldmask->maskp,
     281                 :          2 :                                   oldmask->size + 1, 0, 0) < 0) {
     282                 :          0 :                         EAL_LOG(ERR,
     283                 :            :                                 "Failed to get current mempolicy: %s. "
     284                 :            :                                 "Assuming MPOL_DEFAULT.", strerror(errno));
     285                 :          0 :                         oldpolicy = MPOL_DEFAULT;
     286                 :            :                 }
     287         [ +  + ]:         66 :                 for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
     288         [ -  + ]:         64 :                         if (internal_conf->socket_mem[i])
     289                 :          0 :                                 maxnode = i + 1;
     290                 :            :         }
     291                 :            : #endif
     292                 :            : 
     293         [ +  + ]:       2048 :         for (i = 0; i < hpi->num_pages[0]; i++) {
     294                 :       2046 :                 struct hugepage_file *hf = &hugepg_tbl[i];
     295                 :       2046 :                 uint64_t hugepage_sz = hpi->hugepage_sz;
     296                 :            : 
     297                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     298         [ -  + ]:       2046 :                 if (maxnode) {
     299                 :            :                         unsigned int j;
     300                 :            : 
     301         [ #  # ]:          0 :                         for (j = 0; j < maxnode; j++)
     302         [ #  # ]:          0 :                                 if (essential_memory[j])
     303                 :            :                                         break;
     304                 :            : 
     305         [ #  # ]:          0 :                         if (j == maxnode) {
     306                 :          0 :                                 node_id = (node_id + 1) % maxnode;
     307         [ #  # ]:          0 :                                 while (!internal_conf->socket_mem[node_id]) {
     308                 :          0 :                                         node_id++;
     309                 :          0 :                                         node_id %= maxnode;
     310                 :            :                                 }
     311                 :            :                                 essential_prev = 0;
     312                 :            :                         } else {
     313                 :          0 :                                 node_id = j;
     314                 :          0 :                                 essential_prev = essential_memory[j];
     315                 :            : 
     316         [ #  # ]:          0 :                                 if (essential_memory[j] < hugepage_sz)
     317                 :          0 :                                         essential_memory[j] = 0;
     318                 :            :                                 else
     319                 :          0 :                                         essential_memory[j] -= hugepage_sz;
     320                 :            :                         }
     321                 :            : 
     322                 :          0 :                         EAL_LOG(DEBUG,
     323                 :            :                                 "Setting policy MPOL_PREFERRED for socket %d",
     324                 :            :                                 node_id);
     325                 :          0 :                         numa_set_preferred(node_id);
     326                 :            :                 }
     327                 :            : #endif
     328                 :            : 
     329                 :       2046 :                 hf->file_id = i;
     330                 :       2046 :                 hf->size = hugepage_sz;
     331                 :       2046 :                 eal_get_hugefile_path(hf->filepath, sizeof(hf->filepath),
     332                 :       2046 :                                 hpi->hugedir, hf->file_id);
     333                 :       2046 :                 hf->filepath[sizeof(hf->filepath) - 1] = '\0';
     334                 :            : 
     335                 :            :                 /* try to create hugepage file */
     336                 :            :                 fd = open(hf->filepath, O_CREAT | O_RDWR, 0600);
     337         [ -  + ]:       2046 :                 if (fd < 0) {
     338                 :          0 :                         EAL_LOG(DEBUG, "%s(): open failed: %s", __func__,
     339                 :            :                                         strerror(errno));
     340                 :          0 :                         goto out;
     341                 :            :                 }
     342                 :            : 
     343                 :            :                 /* map the segment, and populate page tables,
     344                 :            :                  * the kernel fills this segment with zeros. we don't care where
     345                 :            :                  * this gets mapped - we already have contiguous memory areas
     346                 :            :                  * ready for us to map into.
     347                 :            :                  */
     348                 :       2046 :                 virtaddr = mmap(NULL, hugepage_sz, PROT_READ | PROT_WRITE,
     349                 :            :                                 MAP_SHARED | MAP_POPULATE, fd, 0);
     350         [ -  + ]:       2046 :                 if (virtaddr == MAP_FAILED) {
     351                 :          0 :                         EAL_LOG(DEBUG, "%s(): mmap failed: %s", __func__,
     352                 :            :                                         strerror(errno));
     353                 :          0 :                         close(fd);
     354                 :          0 :                         goto out;
     355                 :            :                 }
     356                 :            : 
     357                 :       2046 :                 hf->orig_va = virtaddr;
     358                 :            : 
     359                 :            :                 /* In linux, hugetlb limitations, like cgroup, are
     360                 :            :                  * enforced at fault time instead of mmap(), even
     361                 :            :                  * with the option of MAP_POPULATE. Kernel will send
     362                 :            :                  * a SIGBUS signal. To avoid to be killed, save stack
     363                 :            :                  * environment here, if SIGBUS happens, we can jump
     364                 :            :                  * back here.
     365                 :            :                  */
     366         [ -  + ]:       2046 :                 if (huge_wrap_sigsetjmp()) {
     367                 :          0 :                         EAL_LOG(DEBUG, "SIGBUS: Cannot mmap more "
     368                 :            :                                 "hugepages of size %u MB",
     369                 :            :                                 (unsigned int)(hugepage_sz / 0x100000));
     370                 :          0 :                         munmap(virtaddr, hugepage_sz);
     371                 :          0 :                         close(fd);
     372                 :          0 :                         unlink(hugepg_tbl[i].filepath);
     373                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     374         [ #  # ]:          0 :                         if (maxnode)
     375                 :          0 :                                 essential_memory[node_id] =
     376                 :            :                                         essential_prev;
     377                 :            : #endif
     378                 :          0 :                         goto out;
     379                 :            :                 }
     380                 :       2046 :                 *(int *)virtaddr = 0;
     381                 :            : 
     382                 :            :                 /* set shared lock on the file. */
     383         [ -  + ]:       2046 :                 if (flock(fd, LOCK_SH) < 0) {
     384                 :          0 :                         EAL_LOG(DEBUG, "%s(): Locking file failed:%s ",
     385                 :            :                                 __func__, strerror(errno));
     386                 :          0 :                         close(fd);
     387                 :          0 :                         goto out;
     388                 :            :                 }
     389                 :            : 
     390                 :       2046 :                 close(fd);
     391                 :            :         }
     392                 :            : 
     393                 :          2 : out:
     394                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     395         [ -  + ]:          2 :         if (maxnode) {
     396                 :          0 :                 EAL_LOG(DEBUG,
     397                 :            :                         "Restoring previous memory policy: %d", oldpolicy);
     398         [ #  # ]:          0 :                 if (oldpolicy == MPOL_DEFAULT) {
     399                 :          0 :                         numa_set_localalloc();
     400         [ #  # ]:          0 :                 } else if (set_mempolicy(oldpolicy, oldmask->maskp,
     401                 :          0 :                                          oldmask->size + 1) < 0) {
     402                 :          0 :                         EAL_LOG(ERR, "Failed to restore mempolicy: %s",
     403                 :            :                                 strerror(errno));
     404                 :          0 :                         numa_set_localalloc();
     405                 :            :                 }
     406                 :            :         }
     407         [ +  - ]:          2 :         if (oldmask != NULL)
     408                 :            :                 numa_free_cpumask(oldmask);
     409                 :            : #endif
     410                 :          2 :         return i;
     411                 :            : }
     412                 :            : 
     413                 :            : /*
     414                 :            :  * Parse /proc/self/numa_maps to get the NUMA socket ID for each huge
     415                 :            :  * page.
     416                 :            :  */
     417                 :            : static int
     418                 :          2 : find_numasocket(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi)
     419                 :            : {
     420                 :            :         int socket_id;
     421                 :            :         char *end, *nodestr;
     422                 :            :         unsigned i, hp_count = 0;
     423                 :            :         uint64_t virt_addr;
     424                 :            :         char buf[BUFSIZ];
     425                 :            :         char hugedir_str[PATH_MAX];
     426                 :            :         FILE *f;
     427                 :            : 
     428                 :          2 :         f = fopen("/proc/self/numa_maps", "r");
     429         [ -  + ]:          2 :         if (f == NULL) {
     430                 :          0 :                 EAL_LOG(NOTICE, "NUMA support not available"
     431                 :            :                         " consider that all memory is in socket_id 0");
     432                 :          0 :                 return 0;
     433                 :            :         }
     434                 :            : 
     435                 :          2 :         snprintf(hugedir_str, sizeof(hugedir_str),
     436                 :          2 :                         "%s/%s", hpi->hugedir, eal_get_hugefile_prefix());
     437                 :            : 
     438                 :            :         /* parse numa map */
     439         [ +  + ]:       2388 :         while (fgets(buf, sizeof(buf), f) != NULL) {
     440                 :            : 
     441                 :            :                 /* ignore non huge page */
     442         [ +  + ]:       2386 :                 if (strstr(buf, " huge ") == NULL &&
     443         [ +  - ]:        340 :                                 strstr(buf, hugedir_str) == NULL)
     444                 :        340 :                         continue;
     445                 :            : 
     446                 :            :                 /* get zone addr */
     447                 :       2046 :                 virt_addr = strtoull(buf, &end, 16);
     448   [ +  -  -  + ]:       2046 :                 if (virt_addr == 0 || end == buf) {
     449                 :          0 :                         EAL_LOG(ERR, "%s(): error in numa_maps parsing", __func__);
     450                 :          0 :                         goto error;
     451                 :            :                 }
     452                 :            : 
     453                 :            :                 /* get node id (socket id) */
     454                 :       2046 :                 nodestr = strstr(buf, " N");
     455         [ -  + ]:       2046 :                 if (nodestr == NULL) {
     456                 :          0 :                         EAL_LOG(ERR, "%s(): error in numa_maps parsing", __func__);
     457                 :          0 :                         goto error;
     458                 :            :                 }
     459                 :       2046 :                 nodestr += 2;
     460                 :       2046 :                 end = strstr(nodestr, "=");
     461         [ -  + ]:       2046 :                 if (end == NULL) {
     462                 :          0 :                         EAL_LOG(ERR, "%s(): error in numa_maps parsing", __func__);
     463                 :          0 :                         goto error;
     464                 :            :                 }
     465                 :       2046 :                 end[0] = '\0';
     466                 :       2046 :                 end = NULL;
     467                 :            : 
     468                 :       2046 :                 socket_id = strtoul(nodestr, &end, 0);
     469   [ +  -  +  -  :       2046 :                 if ((nodestr[0] == '\0') || (end == NULL) || (*end != '\0')) {
                   -  + ]
     470                 :          0 :                         EAL_LOG(ERR, "%s(): error in numa_maps parsing", __func__);
     471                 :          0 :                         goto error;
     472                 :            :                 }
     473                 :            : 
     474                 :            :                 /* if we find this page in our mappings, set socket_id */
     475         [ +  + ]:    2095104 :                 for (i = 0; i < hpi->num_pages[0]; i++) {
     476                 :    2093058 :                         void *va = (void *)(unsigned long)virt_addr;
     477         [ +  + ]:    2093058 :                         if (hugepg_tbl[i].orig_va == va) {
     478                 :       2046 :                                 hugepg_tbl[i].socket_id = socket_id;
     479                 :       2046 :                                 hp_count++;
     480                 :            : #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
     481                 :       2046 :                                 EAL_LOG(DEBUG,
     482                 :            :                                         "Hugepage %s is on socket %d",
     483                 :            :                                         hugepg_tbl[i].filepath, socket_id);
     484                 :            : #endif
     485                 :            :                         }
     486                 :            :                 }
     487                 :            :         }
     488                 :            : 
     489         [ -  + ]:          2 :         if (hp_count < hpi->num_pages[0])
     490                 :          0 :                 goto error;
     491                 :            : 
     492                 :          2 :         fclose(f);
     493                 :          2 :         return 0;
     494                 :            : 
     495                 :          0 : error:
     496                 :          0 :         fclose(f);
     497                 :          0 :         return -1;
     498                 :            : }
     499                 :            : 
     500                 :            : static int
     501                 :      10344 : cmp_physaddr(const void *a, const void *b)
     502                 :            : {
     503                 :            : #ifndef RTE_ARCH_PPC_64
     504                 :            :         const struct hugepage_file *p1 = a;
     505                 :            :         const struct hugepage_file *p2 = b;
     506                 :            : #else
     507                 :            :         /* PowerPC needs memory sorted in reverse order from x86 */
     508                 :            :         const struct hugepage_file *p1 = b;
     509                 :            :         const struct hugepage_file *p2 = a;
     510                 :            : #endif
     511         [ +  + ]:      10344 :         if (p1->physaddr < p2->physaddr)
     512                 :            :                 return -1;
     513         [ -  + ]:       9175 :         else if (p1->physaddr > p2->physaddr)
     514                 :            :                 return 1;
     515                 :            :         else
     516                 :          0 :                 return 0;
     517                 :            : }
     518                 :            : 
     519                 :            : /*
     520                 :            :  * Uses mmap to create a shared memory area for storage of data
     521                 :            :  * Used in this file to store the hugepage file map on disk
     522                 :            :  */
     523                 :            : static void *
     524                 :          2 : create_shared_memory(const char *filename, const size_t mem_size)
     525                 :            : {
     526                 :            :         void *retval;
     527                 :            :         int fd;
     528                 :            :         const struct internal_config *internal_conf =
     529                 :          2 :                 eal_get_internal_configuration();
     530                 :            : 
     531                 :            :         /* if no shared files mode is used, create anonymous memory instead */
     532         [ -  + ]:          2 :         if (internal_conf->no_shconf) {
     533                 :          0 :                 retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
     534                 :            :                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     535         [ #  # ]:          0 :                 if (retval == MAP_FAILED)
     536                 :            :                         return NULL;
     537                 :          0 :                 return retval;
     538                 :            :         }
     539                 :            : 
     540                 :            :         fd = open(filename, O_CREAT | O_RDWR, 0600);
     541         [ +  - ]:          2 :         if (fd < 0)
     542                 :            :                 return NULL;
     543         [ -  + ]:          2 :         if (ftruncate(fd, mem_size) < 0) {
     544                 :          0 :                 close(fd);
     545                 :          0 :                 return NULL;
     546                 :            :         }
     547                 :          2 :         retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     548                 :          2 :         close(fd);
     549         [ -  + ]:          2 :         if (retval == MAP_FAILED)
     550                 :          0 :                 return NULL;
     551                 :            :         return retval;
     552                 :            : }
     553                 :            : 
     554                 :            : /*
     555                 :            :  * this copies *active* hugepages from one hugepage table to another.
     556                 :            :  * destination is typically the shared memory.
     557                 :            :  */
     558                 :            : static int
     559                 :          2 : copy_hugepages_to_shared_mem(struct hugepage_file * dst, int dest_size,
     560                 :            :                 const struct hugepage_file * src, int src_size)
     561                 :            : {
     562                 :            :         int src_pos, dst_pos = 0;
     563                 :            : 
     564         [ +  + ]:       2048 :         for (src_pos = 0; src_pos < src_size; src_pos++) {
     565         [ +  + ]:       2046 :                 if (src[src_pos].orig_va != NULL) {
     566                 :            :                         /* error on overflow attempt */
     567         [ +  - ]:         18 :                         if (dst_pos == dest_size)
     568                 :            :                                 return -1;
     569                 :         18 :                         memcpy(&dst[dst_pos], &src[src_pos], sizeof(struct hugepage_file));
     570                 :         18 :                         dst_pos++;
     571                 :            :                 }
     572                 :            :         }
     573                 :            :         return 0;
     574                 :            : }
     575                 :            : 
     576                 :            : static int
     577                 :          0 : unlink_hugepage_files(struct hugepage_file *hugepg_tbl,
     578                 :            :                 unsigned num_hp_info)
     579                 :            : {
     580                 :            :         unsigned socket, size;
     581                 :            :         int page, nrpages = 0;
     582                 :            :         const struct internal_config *internal_conf =
     583                 :          0 :                 eal_get_internal_configuration();
     584                 :            : 
     585                 :            :         /* get total number of hugepages */
     586         [ #  # ]:          0 :         for (size = 0; size < num_hp_info; size++)
     587         [ #  # ]:          0 :                 for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++)
     588                 :          0 :                         nrpages +=
     589                 :          0 :                         internal_conf->hugepage_info[size].num_pages[socket];
     590                 :            : 
     591         [ #  # ]:          0 :         for (page = 0; page < nrpages; page++) {
     592                 :          0 :                 struct hugepage_file *hp = &hugepg_tbl[page];
     593                 :            : 
     594   [ #  #  #  # ]:          0 :                 if (hp->orig_va != NULL && unlink(hp->filepath)) {
     595                 :          0 :                         EAL_LOG(WARNING, "%s(): Removing %s failed: %s",
     596                 :            :                                 __func__, hp->filepath, strerror(errno));
     597                 :            :                 }
     598                 :            :         }
     599                 :          0 :         return 0;
     600                 :            : }
     601                 :            : 
     602                 :            : /*
     603                 :            :  * unmaps hugepages that are not going to be used. since we originally allocate
     604                 :            :  * ALL hugepages (not just those we need), additional unmapping needs to be done.
     605                 :            :  */
     606                 :            : static int
     607                 :          2 : unmap_unneeded_hugepages(struct hugepage_file *hugepg_tbl,
     608                 :            :                 struct hugepage_info *hpi,
     609                 :            :                 unsigned num_hp_info)
     610                 :            : {
     611                 :            :         unsigned socket, size;
     612                 :            :         int page, nrpages = 0;
     613                 :            :         const struct internal_config *internal_conf =
     614                 :          2 :                 eal_get_internal_configuration();
     615                 :            : 
     616                 :            :         /* get total number of hugepages */
     617         [ +  + ]:          4 :         for (size = 0; size < num_hp_info; size++)
     618         [ +  + ]:         66 :                 for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++)
     619                 :         64 :                         nrpages += internal_conf->hugepage_info[size].num_pages[socket];
     620                 :            : 
     621         [ +  + ]:          4 :         for (size = 0; size < num_hp_info; size++) {
     622         [ +  + ]:         66 :                 for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
     623                 :            :                         unsigned pages_found = 0;
     624                 :            : 
     625                 :            :                         /* traverse until we have unmapped all the unused pages */
     626         [ +  + ]:      65536 :                         for (page = 0; page < nrpages; page++) {
     627                 :      65472 :                                 struct hugepage_file *hp = &hugepg_tbl[page];
     628                 :            : 
     629                 :            :                                 /* find a page that matches the criteria */
     630         [ +  - ]:      65472 :                                 if ((hp->size == hpi[size].hugepage_sz) &&
     631         [ +  + ]:      65472 :                                                 (hp->socket_id == (int) socket)) {
     632                 :            : 
     633                 :            :                                         /* if we skipped enough pages, unmap the rest */
     634         [ +  + ]:       2046 :                                         if (pages_found == hpi[size].num_pages[socket]) {
     635                 :            :                                                 uint64_t unmap_len;
     636                 :            : 
     637                 :            :                                                 unmap_len = hp->size;
     638                 :            : 
     639                 :            :                                                 /* get start addr and len of the remaining segment */
     640                 :       2028 :                                                 munmap(hp->orig_va,
     641                 :            :                                                         (size_t)unmap_len);
     642                 :            : 
     643                 :       2028 :                                                 hp->orig_va = NULL;
     644         [ -  + ]:       2028 :                                                 if (unlink(hp->filepath) == -1) {
     645                 :          0 :                                                         EAL_LOG(ERR, "%s(): Removing %s failed: %s",
     646                 :            :                                                                         __func__, hp->filepath, strerror(errno));
     647                 :          0 :                                                         return -1;
     648                 :            :                                                 }
     649                 :            :                                         } else {
     650                 :            :                                                 /* lock the page and skip */
     651                 :         18 :                                                 pages_found++;
     652                 :            :                                         }
     653                 :            : 
     654                 :            :                                 } /* match page */
     655                 :            :                         } /* foreach page */
     656                 :            :                 } /* foreach socket */
     657                 :            :         } /* foreach pagesize */
     658                 :            : 
     659                 :            :         return 0;
     660                 :            : }
     661                 :            : 
     662                 :            : static int
     663                 :          2 : remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
     664                 :            : {
     665                 :          2 :         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
     666                 :            :         struct rte_memseg_list *msl;
     667                 :            :         struct rte_fbarray *arr;
     668                 :            :         int cur_page, seg_len;
     669                 :            :         unsigned int msl_idx;
     670                 :            :         int ms_idx;
     671                 :            :         uint64_t page_sz;
     672                 :            :         size_t memseg_len;
     673                 :            :         int socket_id;
     674                 :            : #ifndef RTE_ARCH_64
     675                 :            :         const struct internal_config *internal_conf =
     676                 :            :                 eal_get_internal_configuration();
     677                 :            : #endif
     678                 :          2 :         page_sz = hugepages[seg_start].size;
     679                 :          2 :         socket_id = hugepages[seg_start].socket_id;
     680                 :          2 :         seg_len = seg_end - seg_start;
     681                 :            : 
     682                 :          2 :         EAL_LOG(DEBUG, "Attempting to map %" PRIu64 "M on socket %i",
     683                 :            :                         (seg_len * page_sz) >> 20ULL, socket_id);
     684                 :            : 
     685                 :            :         /* find free space in memseg lists */
     686         [ +  - ]:          2 :         for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS; msl_idx++) {
     687                 :            :                 int free_len;
     688                 :            :                 bool empty;
     689                 :          2 :                 msl = &mcfg->memsegs[msl_idx];
     690                 :          2 :                 arr = &msl->memseg_arr;
     691                 :            : 
     692         [ -  + ]:          2 :                 if (msl->page_sz != page_sz)
     693                 :          0 :                         continue;
     694         [ -  + ]:          2 :                 if (msl->socket_id != socket_id)
     695                 :          0 :                         continue;
     696                 :            : 
     697                 :            :                 /* leave space for a hole if array is not empty */
     698                 :          2 :                 empty = arr->count == 0;
     699                 :            :                 /* find start of the biggest contiguous block and its size */
     700                 :          2 :                 ms_idx = rte_fbarray_find_biggest_free(arr, 0);
     701         [ -  + ]:          2 :                 if (ms_idx < 0)
     702                 :          0 :                         continue;
     703                 :            :                 /* hole is 1 segment long, so at least two segments long. */
     704                 :          2 :                 free_len = rte_fbarray_find_contig_free(arr, ms_idx);
     705         [ -  + ]:          2 :                 if (free_len < 2)
     706                 :          0 :                         continue;
     707                 :            :                 /* leave some space between memsegs, they are not IOVA
     708                 :            :                  * contiguous, so they shouldn't be VA contiguous either.
     709                 :            :                  */
     710         [ -  + ]:          2 :                 if (!empty) {
     711                 :          0 :                         ms_idx++;
     712                 :          0 :                         free_len--;
     713                 :            :                 }
     714                 :            : 
     715                 :            :                 /* we might not get all of the space we wanted */
     716                 :          2 :                 free_len = RTE_MIN(seg_len, free_len);
     717                 :          2 :                 seg_end = seg_start + free_len;
     718                 :            :                 seg_len = seg_end - seg_start;
     719                 :          2 :                 break;
     720                 :            :         }
     721         [ -  + ]:          2 :         if (msl_idx == RTE_MAX_MEMSEG_LISTS) {
     722                 :          0 :                 EAL_LOG(ERR, "Could not find space for memseg. Please increase RTE_MAX_MEMSEG_PER_LIST "
     723                 :            :                         "RTE_MAX_MEMSEG_PER_TYPE and/or RTE_MAX_MEM_MB_PER_TYPE in configuration.");
     724                 :          0 :                 return -1;
     725                 :            :         }
     726                 :            : 
     727                 :            : #ifdef RTE_ARCH_PPC_64
     728                 :            :         /* for PPC64 we go through the list backwards */
     729                 :            :         for (cur_page = seg_end - 1; cur_page >= seg_start;
     730                 :            :                         cur_page--, ms_idx++) {
     731                 :            : #else
     732         [ +  + ]:         20 :         for (cur_page = seg_start; cur_page < seg_end; cur_page++, ms_idx++) {
     733                 :            : #endif
     734                 :         18 :                 struct hugepage_file *hfile = &hugepages[cur_page];
     735                 :         18 :                 struct rte_memseg *ms = rte_fbarray_get(arr, ms_idx);
     736                 :            :                 void *addr;
     737                 :            :                 int fd;
     738                 :            : 
     739                 :         18 :                 fd = open(hfile->filepath, O_RDWR);
     740         [ -  + ]:         18 :                 if (fd < 0) {
     741                 :          0 :                         EAL_LOG(ERR, "Could not open '%s': %s",
     742                 :            :                                         hfile->filepath, strerror(errno));
     743                 :          0 :                         return -1;
     744                 :            :                 }
     745                 :            :                 /* set shared lock on the file. */
     746         [ -  + ]:         18 :                 if (flock(fd, LOCK_SH) < 0) {
     747                 :          0 :                         EAL_LOG(DEBUG, "Could not lock '%s': %s",
     748                 :            :                                         hfile->filepath, strerror(errno));
     749                 :          0 :                         close(fd);
     750                 :          0 :                         return -1;
     751                 :            :                 }
     752                 :            :                 memseg_len = (size_t)page_sz;
     753                 :         18 :                 addr = RTE_PTR_ADD(msl->base_va, ms_idx * memseg_len);
     754                 :            : 
     755                 :            :                 /* we know this address is already mmapped by memseg list, so
     756                 :            :                  * using MAP_FIXED here is safe
     757                 :            :                  */
     758                 :         18 :                 addr = mmap(addr, page_sz, PROT_READ | PROT_WRITE,
     759                 :            :                                 MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd, 0);
     760         [ -  + ]:         18 :                 if (addr == MAP_FAILED) {
     761                 :          0 :                         EAL_LOG(ERR, "Couldn't remap '%s': %s",
     762                 :            :                                         hfile->filepath, strerror(errno));
     763                 :          0 :                         close(fd);
     764                 :          0 :                         return -1;
     765                 :            :                 }
     766                 :            : 
     767                 :            :                 /* we have a new address, so unmap previous one */
     768                 :            : #ifndef RTE_ARCH_64
     769                 :            :                 /* in 32-bit legacy mode, we have already unmapped the page */
     770                 :            :                 if (!internal_conf->legacy_mem)
     771                 :            :                         munmap(hfile->orig_va, page_sz);
     772                 :            : #else
     773                 :         18 :                 munmap(hfile->orig_va, page_sz);
     774                 :            : #endif
     775                 :            : 
     776                 :         18 :                 hfile->orig_va = NULL;
     777                 :         18 :                 hfile->final_va = addr;
     778                 :            : 
     779                 :            :                 /* rewrite physical addresses in IOVA as VA mode */
     780         [ -  + ]:         18 :                 if (rte_eal_iova_mode() == RTE_IOVA_VA)
     781                 :          0 :                         hfile->physaddr = (uintptr_t)addr;
     782                 :            : 
     783                 :            :                 /* set up memseg data */
     784                 :         18 :                 ms->addr = addr;
     785                 :         18 :                 ms->hugepage_sz = page_sz;
     786                 :         18 :                 ms->len = memseg_len;
     787                 :         18 :                 ms->iova = hfile->physaddr;
     788                 :         18 :                 ms->socket_id = hfile->socket_id;
     789                 :         18 :                 ms->nchannel = rte_memory_get_nchannel();
     790                 :         18 :                 ms->nrank = rte_memory_get_nrank();
     791                 :            : 
     792                 :         18 :                 rte_fbarray_set_used(arr, ms_idx);
     793                 :            : 
     794                 :            :                 /* store segment fd internally */
     795         [ -  + ]:         18 :                 if (eal_memalloc_set_seg_fd(msl_idx, ms_idx, fd) < 0)
     796                 :          0 :                         EAL_LOG(ERR, "Could not store segment fd: %s",
     797                 :            :                                 rte_strerror(rte_errno));
     798                 :            :         }
     799                 :          2 :         EAL_LOG(DEBUG, "Allocated %" PRIu64 "M on socket %i",
     800                 :            :                         (seg_len * page_sz) >> 20, socket_id);
     801                 :          2 :         return seg_len;
     802                 :            : }
     803                 :            : 
     804                 :            : static uint64_t
     805                 :            : get_mem_amount(uint64_t page_sz, uint64_t max_mem)
     806                 :            : {
     807                 :            :         uint64_t area_sz, max_pages;
     808                 :            : 
     809                 :            :         /* limit to RTE_MAX_MEMSEG_PER_LIST pages or RTE_MAX_MEM_MB_PER_LIST */
     810                 :            :         max_pages = RTE_MAX_MEMSEG_PER_LIST;
     811                 :            :         max_mem = RTE_MIN((uint64_t)RTE_MAX_MEM_MB_PER_LIST << 20, max_mem);
     812                 :            : 
     813                 :            :         area_sz = RTE_MIN(page_sz * max_pages, max_mem);
     814                 :            : 
     815                 :            :         /* make sure the list isn't smaller than the page size */
     816                 :            :         area_sz = RTE_MAX(area_sz, page_sz);
     817                 :            : 
     818                 :            :         return RTE_ALIGN(area_sz, page_sz);
     819                 :            : }
     820                 :            : 
     821                 :            : static int
     822                 :            : memseg_list_free(struct rte_memseg_list *msl)
     823                 :            : {
     824                 :            :         if (rte_fbarray_destroy(&msl->memseg_arr)) {
     825                 :            :                 EAL_LOG(ERR, "Cannot destroy memseg list");
     826                 :            :                 return -1;
     827                 :            :         }
     828                 :            :         memset(msl, 0, sizeof(*msl));
     829                 :            :         return 0;
     830                 :            : }
     831                 :            : 
     832                 :            : /*
     833                 :            :  * Our VA space is not preallocated yet, so preallocate it here. We need to know
     834                 :            :  * how many segments there are in order to map all pages into one address space,
     835                 :            :  * and leave appropriate holes between segments so that rte_malloc does not
     836                 :            :  * concatenate them into one big segment.
     837                 :            :  *
     838                 :            :  * we also need to unmap original pages to free up address space.
     839                 :            :  */
     840                 :            : static int __rte_unused
     841                 :            : prealloc_segments(struct hugepage_file *hugepages, int n_pages)
     842                 :            : {
     843                 :            :         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
     844                 :            :         int cur_page, seg_start_page, end_seg, new_memseg;
     845                 :            :         unsigned int hpi_idx, socket, i;
     846                 :            :         int n_contig_segs, n_segs;
     847                 :            :         int msl_idx;
     848                 :            :         const struct internal_config *internal_conf =
     849                 :            :                 eal_get_internal_configuration();
     850                 :            : 
     851                 :            :         /* before we preallocate segments, we need to free up our VA space.
     852                 :            :          * we're not removing files, and we already have information about
     853                 :            :          * PA-contiguousness, so it is safe to unmap everything.
     854                 :            :          */
     855                 :            :         for (cur_page = 0; cur_page < n_pages; cur_page++) {
     856                 :            :                 struct hugepage_file *hpi = &hugepages[cur_page];
     857                 :            :                 munmap(hpi->orig_va, hpi->size);
     858                 :            :                 hpi->orig_va = NULL;
     859                 :            :         }
     860                 :            : 
     861                 :            :         /* we cannot know how many page sizes and sockets we have discovered, so
     862                 :            :          * loop over all of them
     863                 :            :          */
     864                 :            :         for (hpi_idx = 0; hpi_idx < internal_conf->num_hugepage_sizes;
     865                 :            :                         hpi_idx++) {
     866                 :            :                 uint64_t page_sz =
     867                 :            :                         internal_conf->hugepage_info[hpi_idx].hugepage_sz;
     868                 :            : 
     869                 :            :                 for (i = 0; i < rte_socket_count(); i++) {
     870                 :            :                         struct rte_memseg_list *msl;
     871                 :            : 
     872                 :            :                         socket = rte_socket_id_by_idx(i);
     873                 :            :                         n_contig_segs = 0;
     874                 :            :                         n_segs = 0;
     875                 :            :                         seg_start_page = -1;
     876                 :            : 
     877                 :            :                         for (cur_page = 0; cur_page < n_pages; cur_page++) {
     878                 :            :                                 struct hugepage_file *prev, *cur;
     879                 :            :                                 int prev_seg_start_page = -1;
     880                 :            : 
     881                 :            :                                 cur = &hugepages[cur_page];
     882                 :            :                                 prev = cur_page == 0 ? NULL :
     883                 :            :                                                 &hugepages[cur_page - 1];
     884                 :            : 
     885                 :            :                                 new_memseg = 0;
     886                 :            :                                 end_seg = 0;
     887                 :            : 
     888                 :            :                                 if (cur->size == 0)
     889                 :            :                                         end_seg = 1;
     890                 :            :                                 else if (cur->socket_id != (int) socket)
     891                 :            :                                         end_seg = 1;
     892                 :            :                                 else if (cur->size != page_sz)
     893                 :            :                                         end_seg = 1;
     894                 :            :                                 else if (cur_page == 0)
     895                 :            :                                         new_memseg = 1;
     896                 :            : #ifdef RTE_ARCH_PPC_64
     897                 :            :                                 /* On PPC64 architecture, the mmap always start
     898                 :            :                                  * from higher address to lower address. Here,
     899                 :            :                                  * physical addresses are in descending order.
     900                 :            :                                  */
     901                 :            :                                 else if ((prev->physaddr - cur->physaddr) !=
     902                 :            :                                                 cur->size)
     903                 :            :                                         new_memseg = 1;
     904                 :            : #else
     905                 :            :                                 else if ((cur->physaddr - prev->physaddr) !=
     906                 :            :                                                 cur->size)
     907                 :            :                                         new_memseg = 1;
     908                 :            : #endif
     909                 :            :                                 if (new_memseg) {
     910                 :            :                                         /* if we're already inside a segment,
     911                 :            :                                          * new segment means end of current one
     912                 :            :                                          */
     913                 :            :                                         if (seg_start_page != -1) {
     914                 :            :                                                 end_seg = 1;
     915                 :            :                                                 prev_seg_start_page =
     916                 :            :                                                                 seg_start_page;
     917                 :            :                                         }
     918                 :            :                                         seg_start_page = cur_page;
     919                 :            :                                 }
     920                 :            : 
     921                 :            :                                 if (end_seg) {
     922                 :            :                                         if (prev_seg_start_page != -1) {
     923                 :            :                                                 /* we've found a new segment */
     924                 :            :                                                 n_contig_segs++;
     925                 :            :                                                 n_segs += cur_page -
     926                 :            :                                                         prev_seg_start_page;
     927                 :            :                                         } else if (seg_start_page != -1) {
     928                 :            :                                                 /* we didn't find new segment,
     929                 :            :                                                  * but did end current one
     930                 :            :                                                  */
     931                 :            :                                                 n_contig_segs++;
     932                 :            :                                                 n_segs += cur_page -
     933                 :            :                                                                 seg_start_page;
     934                 :            :                                                 seg_start_page = -1;
     935                 :            :                                                 continue;
     936                 :            :                                         } else {
     937                 :            :                                                 /* we're skipping this page */
     938                 :            :                                                 continue;
     939                 :            :                                         }
     940                 :            :                                 }
     941                 :            :                                 /* segment continues */
     942                 :            :                         }
     943                 :            :                         /* check if we missed last segment */
     944                 :            :                         if (seg_start_page != -1) {
     945                 :            :                                 n_contig_segs++;
     946                 :            :                                 n_segs += cur_page - seg_start_page;
     947                 :            :                         }
     948                 :            : 
     949                 :            :                         /* if no segments were found, do not preallocate */
     950                 :            :                         if (n_segs == 0)
     951                 :            :                                 continue;
     952                 :            : 
     953                 :            :                         /* we now have total number of pages that we will
     954                 :            :                          * allocate for this segment list. add separator pages
     955                 :            :                          * to the total count, and preallocate VA space.
     956                 :            :                          */
     957                 :            :                         n_segs += n_contig_segs - 1;
     958                 :            : 
     959                 :            :                         /* now, preallocate VA space for these segments */
     960                 :            : 
     961                 :            :                         /* first, find suitable memseg list for this */
     962                 :            :                         for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS;
     963                 :            :                                         msl_idx++) {
     964                 :            :                                 msl = &mcfg->memsegs[msl_idx];
     965                 :            : 
     966                 :            :                                 if (msl->base_va != NULL)
     967                 :            :                                         continue;
     968                 :            :                                 break;
     969                 :            :                         }
     970                 :            :                         if (msl_idx == RTE_MAX_MEMSEG_LISTS) {
     971                 :            :                                 EAL_LOG(ERR, "Not enough space in memseg lists, please increase RTE_MAX_MEMSEG_LISTS");
     972                 :            :                                 return -1;
     973                 :            :                         }
     974                 :            : 
     975                 :            :                         /* now, allocate fbarray itself */
     976                 :            :                         if (eal_memseg_list_init(msl, page_sz, n_segs,
     977                 :            :                                         socket, msl_idx, true) < 0)
     978                 :            :                                 return -1;
     979                 :            : 
     980                 :            :                         /* finally, allocate VA space */
     981                 :            :                         if (eal_memseg_list_alloc(msl, 0) < 0) {
     982                 :            :                                 EAL_LOG(ERR, "Cannot preallocate 0x%"PRIx64"kB hugepages",
     983                 :            :                                         page_sz >> 10);
     984                 :            :                                 return -1;
     985                 :            :                         }
     986                 :            :                 }
     987                 :            :         }
     988                 :            :         return 0;
     989                 :            : }
     990                 :            : 
     991                 :            : /*
     992                 :            :  * We cannot reallocate memseg lists on the fly because PPC64 stores pages
     993                 :            :  * backwards, therefore we have to process the entire memseg first before
     994                 :            :  * remapping it into memseg list VA space.
     995                 :            :  */
     996                 :            : static int
     997                 :          2 : remap_needed_hugepages(struct hugepage_file *hugepages, int n_pages)
     998                 :            : {
     999                 :            :         int cur_page, seg_start_page, new_memseg, ret;
    1000                 :            : 
    1001                 :            :         seg_start_page = 0;
    1002         [ +  - ]:         20 :         for (cur_page = 0; cur_page < n_pages; cur_page++) {
    1003                 :            :                 struct hugepage_file *prev, *cur;
    1004                 :            : 
    1005                 :            :                 new_memseg = 0;
    1006                 :            : 
    1007                 :         20 :                 cur = &hugepages[cur_page];
    1008         [ +  + ]:         20 :                 prev = cur_page == 0 ? NULL : &hugepages[cur_page - 1];
    1009                 :            : 
    1010                 :            :                 /* if size is zero, no more pages left */
    1011         [ +  + ]:         20 :                 if (cur->size == 0)
    1012                 :            :                         break;
    1013                 :            : 
    1014         [ +  + ]:         18 :                 if (cur_page == 0)
    1015                 :            :                         new_memseg = 1;
    1016         [ +  - ]:         16 :                 else if (cur->socket_id != prev->socket_id)
    1017                 :            :                         new_memseg = 1;
    1018         [ +  - ]:         16 :                 else if (cur->size != prev->size)
    1019                 :            :                         new_memseg = 1;
    1020                 :            : #ifdef RTE_ARCH_PPC_64
    1021                 :            :                 /* On PPC64 architecture, the mmap always start from higher
    1022                 :            :                  * address to lower address. Here, physical addresses are in
    1023                 :            :                  * descending order.
    1024                 :            :                  */
    1025                 :            :                 else if ((prev->physaddr - cur->physaddr) != cur->size)
    1026                 :            :                         new_memseg = 1;
    1027                 :            : #else
    1028         [ -  + ]:         16 :                 else if ((cur->physaddr - prev->physaddr) != cur->size)
    1029                 :            :                         new_memseg = 1;
    1030                 :            : #endif
    1031                 :            : 
    1032                 :            :                 if (new_memseg) {
    1033                 :            :                         /* if this isn't the first time, remap segment */
    1034         [ -  + ]:          2 :                         if (cur_page != 0) {
    1035                 :            :                                 int n_remapped = 0;
    1036                 :          0 :                                 int n_needed = cur_page - seg_start_page;
    1037         [ #  # ]:          0 :                                 while (n_remapped < n_needed) {
    1038                 :          0 :                                         ret = remap_segment(hugepages, seg_start_page,
    1039                 :            :                                                         cur_page);
    1040         [ #  # ]:          0 :                                         if (ret < 0)
    1041                 :            :                                                 return -1;
    1042                 :          0 :                                         n_remapped += ret;
    1043                 :          0 :                                         seg_start_page += ret;
    1044                 :            :                                 }
    1045                 :            :                         }
    1046                 :            :                         /* remember where we started */
    1047                 :            :                         seg_start_page = cur_page;
    1048                 :            :                 }
    1049                 :            :                 /* continuation of previous memseg */
    1050                 :            :         }
    1051                 :            :         /* we were stopped, but we didn't remap the last segment, do it now */
    1052         [ +  - ]:          2 :         if (cur_page != 0) {
    1053                 :            :                 int n_remapped = 0;
    1054                 :          2 :                 int n_needed = cur_page - seg_start_page;
    1055         [ +  + ]:          4 :                 while (n_remapped < n_needed) {
    1056                 :          2 :                         ret = remap_segment(hugepages, seg_start_page,
    1057                 :            :                                         cur_page);
    1058         [ +  - ]:          2 :                         if (ret < 0)
    1059                 :            :                                 return -1;
    1060                 :          2 :                         n_remapped += ret;
    1061                 :          2 :                         seg_start_page += ret;
    1062                 :            :                 }
    1063                 :            :         }
    1064                 :            :         return 0;
    1065                 :            : }
    1066                 :            : 
    1067                 :            : static inline size_t
    1068                 :          0 : eal_get_hugepage_mem_size(void)
    1069                 :            : {
    1070                 :            :         uint64_t size = 0;
    1071                 :            :         unsigned i, j;
    1072                 :            :         struct internal_config *internal_conf =
    1073                 :          0 :                 eal_get_internal_configuration();
    1074                 :            : 
    1075         [ #  # ]:          0 :         for (i = 0; i < internal_conf->num_hugepage_sizes; i++) {
    1076                 :            :                 struct hugepage_info *hpi = &internal_conf->hugepage_info[i];
    1077         [ #  # ]:          0 :                 if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0) {
    1078         [ #  # ]:          0 :                         for (j = 0; j < RTE_MAX_NUMA_NODES; j++) {
    1079                 :          0 :                                 size += hpi->hugepage_sz * hpi->num_pages[j];
    1080                 :            :                         }
    1081                 :            :                 }
    1082                 :            :         }
    1083                 :            : 
    1084                 :          0 :         return (size < SIZE_MAX) ? (size_t)(size) : SIZE_MAX;
    1085                 :            : }
    1086                 :            : 
    1087                 :            : static struct sigaction huge_action_old;
    1088                 :            : static int huge_need_recover;
    1089                 :            : 
    1090                 :            : static void
    1091                 :          2 : huge_register_sigbus(void)
    1092                 :            : {
    1093                 :            :         sigset_t mask;
    1094                 :            :         struct sigaction action;
    1095                 :            : 
    1096                 :          2 :         sigemptyset(&mask);
    1097                 :          2 :         sigaddset(&mask, SIGBUS);
    1098                 :          2 :         action.sa_flags = 0;
    1099                 :          2 :         action.sa_mask = mask;
    1100                 :          2 :         action.sa_handler = huge_sigbus_handler;
    1101                 :            : 
    1102                 :          2 :         huge_need_recover = !sigaction(SIGBUS, &action, &huge_action_old);
    1103                 :          2 : }
    1104                 :            : 
    1105                 :            : static void
    1106                 :            : huge_recover_sigbus(void)
    1107                 :            : {
    1108         [ +  - ]:          2 :         if (huge_need_recover) {
    1109                 :          2 :                 sigaction(SIGBUS, &huge_action_old, NULL);
    1110                 :          2 :                 huge_need_recover = 0;
    1111                 :            :         }
    1112                 :            : }
    1113                 :            : 
    1114                 :            : /*
    1115                 :            :  * Prepare physical memory mapping: fill configuration structure with
    1116                 :            :  * these infos, return 0 on success.
    1117                 :            :  *  1. map N huge pages in separate files in hugetlbfs
    1118                 :            :  *  2. find associated physical addr
    1119                 :            :  *  3. find associated NUMA socket ID
    1120                 :            :  *  4. sort all huge pages by physical address
    1121                 :            :  *  5. remap these N huge pages in the correct order
    1122                 :            :  *  6. unmap the first mapping
    1123                 :            :  *  7. fill memsegs in configuration with contiguous zones
    1124                 :            :  */
    1125                 :            : static int
    1126                 :        101 : eal_legacy_hugepage_init(void)
    1127                 :            : {
    1128                 :            :         struct rte_mem_config *mcfg;
    1129                 :            :         struct hugepage_file *hugepage = NULL, *tmp_hp = NULL;
    1130                 :            :         struct hugepage_info used_hp[MAX_HUGEPAGE_SIZES];
    1131                 :            :         struct internal_config *internal_conf =
    1132                 :        101 :                 eal_get_internal_configuration();
    1133                 :            : 
    1134                 :            :         uint64_t memory[RTE_MAX_NUMA_NODES];
    1135                 :            : 
    1136                 :            :         unsigned hp_offset;
    1137                 :            :         int i, j;
    1138                 :            :         int nr_hugefiles, nr_hugepages = 0;
    1139                 :            :         void *addr;
    1140                 :            : 
    1141                 :            :         memset(used_hp, 0, sizeof(used_hp));
    1142                 :            : 
    1143                 :            :         /* get pointer to global configuration */
    1144                 :        101 :         mcfg = rte_eal_get_configuration()->mem_config;
    1145                 :            : 
    1146                 :            :         /* hugetlbfs can be disabled */
    1147         [ +  + ]:        101 :         if (internal_conf->no_hugetlbfs) {
    1148                 :            :                 void *prealloc_addr;
    1149                 :            :                 size_t mem_sz;
    1150                 :            :                 struct rte_memseg_list *msl;
    1151                 :            :                 int n_segs, fd, flags;
    1152                 :            : #ifdef MEMFD_SUPPORTED
    1153                 :            :                 int memfd;
    1154                 :            : #endif
    1155                 :            :                 uint64_t page_sz;
    1156                 :            : 
    1157                 :            :                 /* nohuge mode is legacy mode */
    1158                 :         99 :                 internal_conf->legacy_mem = 1;
    1159                 :            : 
    1160                 :            :                 /* nohuge mode is single-file segments mode */
    1161                 :         99 :                 internal_conf->single_file_segments = 1;
    1162                 :            : 
    1163                 :            :                 /* create a memseg list */
    1164                 :         99 :                 msl = &mcfg->memsegs[0];
    1165                 :            : 
    1166                 :         99 :                 mem_sz = internal_conf->memory;
    1167                 :            :                 page_sz = RTE_PGSIZE_4K;
    1168                 :         99 :                 n_segs = mem_sz / page_sz;
    1169                 :            : 
    1170         [ +  - ]:         99 :                 if (eal_memseg_list_init_named(
    1171                 :            :                                 msl, "nohugemem", page_sz, n_segs, 0, true)) {
    1172                 :            :                         return -1;
    1173                 :            :                 }
    1174                 :            : 
    1175                 :            :                 /* set up parameters for anonymous mmap */
    1176                 :            :                 fd = -1;
    1177                 :            :                 flags = MAP_PRIVATE | MAP_ANONYMOUS;
    1178                 :            : 
    1179                 :            : #ifdef MEMFD_SUPPORTED
    1180                 :            :                 /* create a memfd and store it in the segment fd table */
    1181                 :         99 :                 memfd = memfd_create("nohuge", 0);
    1182         [ -  + ]:         99 :                 if (memfd < 0) {
    1183                 :          0 :                         EAL_LOG(DEBUG, "Cannot create memfd: %s",
    1184                 :            :                                         strerror(errno));
    1185                 :          0 :                         EAL_LOG(DEBUG, "Falling back to anonymous map");
    1186                 :            :                 } else {
    1187                 :            :                         /* we got an fd - now resize it */
    1188         [ -  + ]:         99 :                         if (ftruncate(memfd, internal_conf->memory) < 0) {
    1189                 :          0 :                                 EAL_LOG(ERR, "Cannot resize memfd: %s",
    1190                 :            :                                                 strerror(errno));
    1191                 :          0 :                                 EAL_LOG(ERR, "Falling back to anonymous map");
    1192                 :          0 :                                 close(memfd);
    1193                 :            :                         } else {
    1194                 :            :                                 /* creating memfd-backed file was successful.
    1195                 :            :                                  * we want changes to memfd to be visible to
    1196                 :            :                                  * other processes (such as vhost backend), so
    1197                 :            :                                  * map it as shared memory.
    1198                 :            :                                  */
    1199                 :         99 :                                 EAL_LOG(DEBUG, "Using memfd for anonymous memory");
    1200                 :            :                                 fd = memfd;
    1201                 :            :                                 flags = MAP_SHARED;
    1202                 :            :                         }
    1203                 :            :                 }
    1204                 :            : #endif
    1205                 :            :                 /* preallocate address space for the memory, so that it can be
    1206                 :            :                  * fit into the DMA mask.
    1207                 :            :                  */
    1208         [ -  + ]:         99 :                 if (eal_memseg_list_alloc(msl, 0)) {
    1209                 :          0 :                         EAL_LOG(ERR, "Cannot preallocate VA space for hugepage memory");
    1210                 :          0 :                         return -1;
    1211                 :            :                 }
    1212                 :            : 
    1213                 :         99 :                 prealloc_addr = msl->base_va;
    1214                 :         99 :                 addr = mmap(prealloc_addr, mem_sz, PROT_READ | PROT_WRITE,
    1215                 :            :                                 flags | MAP_FIXED, fd, 0);
    1216         [ -  + ]:         99 :                 if (addr == MAP_FAILED || addr != prealloc_addr) {
    1217                 :          0 :                         EAL_LOG(ERR, "%s: mmap() failed: %s", __func__,
    1218                 :            :                                         strerror(errno));
    1219                 :          0 :                         munmap(prealloc_addr, mem_sz);
    1220                 :          0 :                         return -1;
    1221                 :            :                 }
    1222                 :            : 
    1223                 :            :                 /* we're in single-file segments mode, so only the segment list
    1224                 :            :                  * fd needs to be set up.
    1225                 :            :                  */
    1226         [ +  - ]:         99 :                 if (fd != -1) {
    1227         [ -  + ]:         99 :                         if (eal_memalloc_set_seg_list_fd(0, fd) < 0) {
    1228                 :          0 :                                 EAL_LOG(ERR, "Cannot set up segment list fd");
    1229                 :            :                                 /* not a serious error, proceed */
    1230                 :            :                         }
    1231                 :            :                 }
    1232                 :            : 
    1233                 :         99 :                 eal_memseg_list_populate(msl, addr, n_segs);
    1234                 :            : 
    1235   [ -  +  -  - ]:         99 :                 if (mcfg->dma_maskbits &&
    1236                 :          0 :                     rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) {
    1237                 :          0 :                         EAL_LOG(ERR,
    1238                 :            :                                 "%s(): couldn't allocate memory due to IOVA exceeding limits of current DMA mask.",
    1239                 :            :                                 __func__);
    1240   [ #  #  #  # ]:          0 :                         if (rte_eal_iova_mode() == RTE_IOVA_VA &&
    1241                 :          0 :                             rte_eal_using_phys_addrs())
    1242                 :          0 :                                 EAL_LOG(ERR,
    1243                 :            :                                         "%s(): Please try initializing EAL with --iova-mode=pa parameter.",
    1244                 :            :                                         __func__);
    1245                 :          0 :                         goto fail;
    1246                 :            :                 }
    1247                 :         99 :                 return 0;
    1248                 :            :         }
    1249                 :            : 
    1250                 :            :         /* calculate total number of hugepages available. at this point we haven't
    1251                 :            :          * yet started sorting them so they all are on socket 0 */
    1252         [ +  + ]:          4 :         for (i = 0; i < (int) internal_conf->num_hugepage_sizes; i++) {
    1253                 :            :                 /* meanwhile, also initialize used_hp hugepage sizes in used_hp */
    1254                 :          2 :                 used_hp[i].hugepage_sz = internal_conf->hugepage_info[i].hugepage_sz;
    1255                 :            : 
    1256                 :          2 :                 nr_hugepages += internal_conf->hugepage_info[i].num_pages[0];
    1257                 :            :         }
    1258                 :            : 
    1259                 :            :         /*
    1260                 :            :          * allocate a memory area for hugepage table.
    1261                 :            :          * this isn't shared memory yet. due to the fact that we need some
    1262                 :            :          * processing done on these pages, shared memory will be created
    1263                 :            :          * at a later stage.
    1264                 :            :          */
    1265                 :          2 :         tmp_hp = malloc(nr_hugepages * sizeof(struct hugepage_file));
    1266         [ -  + ]:          2 :         if (tmp_hp == NULL)
    1267                 :          0 :                 goto fail;
    1268                 :            : 
    1269                 :            :         memset(tmp_hp, 0, nr_hugepages * sizeof(struct hugepage_file));
    1270                 :            : 
    1271                 :            :         hp_offset = 0; /* where we start the current page size entries */
    1272                 :            : 
    1273                 :          2 :         huge_register_sigbus();
    1274                 :            : 
    1275                 :            :         /* make a copy of socket_mem, needed for balanced allocation. */
    1276         [ +  + ]:         66 :         for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
    1277                 :         64 :                 memory[i] = internal_conf->socket_mem[i];
    1278                 :            : 
    1279                 :            :         /* map all hugepages and sort them */
    1280         [ +  + ]:          4 :         for (i = 0; i < (int)internal_conf->num_hugepage_sizes; i++) {
    1281                 :            :                 unsigned pages_old, pages_new;
    1282                 :            :                 struct hugepage_info *hpi;
    1283                 :            : 
    1284                 :            :                 /*
    1285                 :            :                  * we don't yet mark hugepages as used at this stage, so
    1286                 :            :                  * we just map all hugepages available to the system
    1287                 :            :                  * all hugepages are still located on socket 0
    1288                 :            :                  */
    1289                 :          2 :                 hpi = &internal_conf->hugepage_info[i];
    1290                 :            : 
    1291         [ -  + ]:          2 :                 if (hpi->num_pages[0] == 0)
    1292                 :          0 :                         continue;
    1293                 :            : 
    1294                 :            :                 /* map all hugepages available */
    1295                 :            :                 pages_old = hpi->num_pages[0];
    1296                 :          2 :                 pages_new = map_all_hugepages(&tmp_hp[hp_offset], hpi, memory);
    1297         [ -  + ]:          2 :                 if (pages_new < pages_old) {
    1298                 :          0 :                         EAL_LOG(DEBUG,
    1299                 :            :                                 "%d not %d hugepages of size %u MB allocated",
    1300                 :            :                                 pages_new, pages_old,
    1301                 :            :                                 (unsigned)(hpi->hugepage_sz / 0x100000));
    1302                 :            : 
    1303                 :          0 :                         int pages = pages_old - pages_new;
    1304                 :            : 
    1305                 :          0 :                         nr_hugepages -= pages;
    1306                 :          0 :                         hpi->num_pages[0] = pages_new;
    1307         [ #  # ]:          0 :                         if (pages_new == 0)
    1308                 :          0 :                                 continue;
    1309                 :            :                 }
    1310                 :            : 
    1311   [ +  -  -  + ]:          4 :                 if (rte_eal_using_phys_addrs() &&
    1312                 :          2 :                                 rte_eal_iova_mode() != RTE_IOVA_VA) {
    1313                 :            :                         /* find physical addresses for each hugepage */
    1314         [ -  + ]:          2 :                         if (find_physaddrs(&tmp_hp[hp_offset], hpi) < 0) {
    1315                 :          0 :                                 EAL_LOG(DEBUG, "Failed to find phys addr "
    1316                 :            :                                         "for %u MB pages",
    1317                 :            :                                         (unsigned int)(hpi->hugepage_sz / 0x100000));
    1318                 :          0 :                                 goto fail;
    1319                 :            :                         }
    1320                 :            :                 } else {
    1321                 :            :                         /* set physical addresses for each hugepage */
    1322                 :            :                         if (set_physaddrs(&tmp_hp[hp_offset], hpi) < 0) {
    1323                 :            :                                 EAL_LOG(DEBUG, "Failed to set phys addr "
    1324                 :            :                                         "for %u MB pages",
    1325                 :            :                                         (unsigned int)(hpi->hugepage_sz / 0x100000));
    1326                 :            :                                 goto fail;
    1327                 :            :                         }
    1328                 :            :                 }
    1329                 :            : 
    1330         [ -  + ]:          2 :                 if (find_numasocket(&tmp_hp[hp_offset], hpi) < 0){
    1331                 :          0 :                         EAL_LOG(DEBUG, "Failed to find NUMA socket for %u MB pages",
    1332                 :            :                                         (unsigned)(hpi->hugepage_sz / 0x100000));
    1333                 :          0 :                         goto fail;
    1334                 :            :                 }
    1335                 :            : 
    1336                 :          2 :                 qsort(&tmp_hp[hp_offset], hpi->num_pages[0],
    1337                 :            :                       sizeof(struct hugepage_file), cmp_physaddr);
    1338                 :            : 
    1339                 :            :                 /* we have processed a num of hugepages of this size, so inc offset */
    1340                 :          2 :                 hp_offset += hpi->num_pages[0];
    1341                 :            :         }
    1342                 :            : 
    1343                 :            :         huge_recover_sigbus();
    1344                 :            : 
    1345   [ -  +  -  - ]:          2 :         if (internal_conf->memory == 0 && internal_conf->force_sockets == 0)
    1346                 :          0 :                 internal_conf->memory = eal_get_hugepage_mem_size();
    1347                 :            : 
    1348                 :            :         nr_hugefiles = nr_hugepages;
    1349                 :            : 
    1350                 :            : 
    1351                 :            :         /* clean out the numbers of pages */
    1352         [ +  + ]:          4 :         for (i = 0; i < (int) internal_conf->num_hugepage_sizes; i++)
    1353         [ +  + ]:         66 :                 for (j = 0; j < RTE_MAX_NUMA_NODES; j++)
    1354                 :         64 :                         internal_conf->hugepage_info[i].num_pages[j] = 0;
    1355                 :            : 
    1356                 :            :         /* get hugepages for each socket */
    1357         [ +  + ]:       2048 :         for (i = 0; i < nr_hugefiles; i++) {
    1358                 :       2046 :                 int socket = tmp_hp[i].socket_id;
    1359                 :            : 
    1360                 :            :                 /* find a hugepage info with right size and increment num_pages */
    1361                 :       2046 :                 const int nb_hpsizes = RTE_MIN(MAX_HUGEPAGE_SIZES,
    1362                 :            :                                 (int)internal_conf->num_hugepage_sizes);
    1363         [ +  + ]:       4092 :                 for (j = 0; j < nb_hpsizes; j++) {
    1364                 :       2046 :                         if (tmp_hp[i].size ==
    1365         [ +  - ]:       2046 :                                         internal_conf->hugepage_info[j].hugepage_sz) {
    1366                 :       2046 :                                 internal_conf->hugepage_info[j].num_pages[socket]++;
    1367                 :            :                         }
    1368                 :            :                 }
    1369                 :            :         }
    1370                 :            : 
    1371                 :            :         /* make a copy of socket_mem, needed for number of pages calculation */
    1372         [ +  + ]:         66 :         for (i = 0; i < RTE_MAX_NUMA_NODES; i++)
    1373                 :         64 :                 memory[i] = internal_conf->socket_mem[i];
    1374                 :            : 
    1375                 :            :         /* calculate final number of pages */
    1376                 :          2 :         nr_hugepages = eal_dynmem_calc_num_pages_per_socket(memory,
    1377                 :          2 :                         internal_conf->hugepage_info, used_hp,
    1378                 :            :                         internal_conf->num_hugepage_sizes);
    1379                 :            : 
    1380                 :            :         /* error if not enough memory available */
    1381         [ -  + ]:          2 :         if (nr_hugepages < 0)
    1382                 :          0 :                 goto fail;
    1383                 :            : 
    1384                 :            :         /* reporting in! */
    1385         [ +  + ]:          4 :         for (i = 0; i < (int) internal_conf->num_hugepage_sizes; i++) {
    1386         [ +  + ]:         66 :                 for (j = 0; j < RTE_MAX_NUMA_NODES; j++) {
    1387         [ +  + ]:         64 :                         if (used_hp[i].num_pages[j] > 0) {
    1388                 :          2 :                                 EAL_LOG(DEBUG,
    1389                 :            :                                         "Requesting %u pages of size %uMB"
    1390                 :            :                                         " from socket %i",
    1391                 :            :                                         used_hp[i].num_pages[j],
    1392                 :            :                                         (unsigned)
    1393                 :            :                                         (used_hp[i].hugepage_sz / 0x100000),
    1394                 :            :                                         j);
    1395                 :            :                         }
    1396                 :            :                 }
    1397                 :            :         }
    1398                 :            : 
    1399                 :            :         /* create shared memory */
    1400                 :          2 :         hugepage = create_shared_memory(eal_hugepage_data_path(),
    1401                 :            :                         nr_hugefiles * sizeof(struct hugepage_file));
    1402                 :            : 
    1403         [ -  + ]:          2 :         if (hugepage == NULL) {
    1404                 :          0 :                 EAL_LOG(ERR, "Failed to create shared memory!");
    1405                 :          0 :                 goto fail;
    1406                 :            :         }
    1407                 :            :         memset(hugepage, 0, nr_hugefiles * sizeof(struct hugepage_file));
    1408                 :            : 
    1409                 :            :         /*
    1410                 :            :          * unmap pages that we won't need (looks at used_hp).
    1411                 :            :          * also, sets final_va to NULL on pages that were unmapped.
    1412                 :            :          */
    1413         [ -  + ]:          2 :         if (unmap_unneeded_hugepages(tmp_hp, used_hp,
    1414                 :            :                         internal_conf->num_hugepage_sizes) < 0) {
    1415                 :          0 :                 EAL_LOG(ERR, "Unmapping and locking hugepages failed!");
    1416                 :          0 :                 goto fail;
    1417                 :            :         }
    1418                 :            : 
    1419                 :            :         /*
    1420                 :            :          * copy stuff from malloc'd hugepage* to the actual shared memory.
    1421                 :            :          * this procedure only copies those hugepages that have orig_va
    1422                 :            :          * not NULL. has overflow protection.
    1423                 :            :          */
    1424         [ -  + ]:          2 :         if (copy_hugepages_to_shared_mem(hugepage, nr_hugefiles,
    1425                 :            :                         tmp_hp, nr_hugefiles) < 0) {
    1426                 :          0 :                 EAL_LOG(ERR, "Copying tables to shared memory failed!");
    1427                 :          0 :                 goto fail;
    1428                 :            :         }
    1429                 :            : 
    1430                 :            : #ifndef RTE_ARCH_64
    1431                 :            :         /* for legacy 32-bit mode, we did not preallocate VA space, so do it */
    1432                 :            :         if (internal_conf->legacy_mem &&
    1433                 :            :                         prealloc_segments(hugepage, nr_hugefiles)) {
    1434                 :            :                 EAL_LOG(ERR, "Could not preallocate VA space for hugepages");
    1435                 :            :                 goto fail;
    1436                 :            :         }
    1437                 :            : #endif
    1438                 :            : 
    1439                 :            :         /* remap all pages we do need into memseg list VA space, so that those
    1440                 :            :          * pages become first-class citizens in DPDK memory subsystem
    1441                 :            :          */
    1442         [ -  + ]:          2 :         if (remap_needed_hugepages(hugepage, nr_hugefiles)) {
    1443                 :          0 :                 EAL_LOG(ERR, "Couldn't remap hugepage files into memseg lists");
    1444                 :          0 :                 goto fail;
    1445                 :            :         }
    1446                 :            : 
    1447                 :            :         /* free the hugepage backing files */
    1448   [ -  +  -  - ]:          2 :         if (internal_conf->hugepage_file.unlink_before_mapping &&
    1449                 :          0 :                 unlink_hugepage_files(tmp_hp, internal_conf->num_hugepage_sizes) < 0) {
    1450                 :          0 :                 EAL_LOG(ERR, "Unlinking hugepage files failed!");
    1451                 :          0 :                 goto fail;
    1452                 :            :         }
    1453                 :            : 
    1454                 :            :         /* free the temporary hugepage table */
    1455                 :          2 :         free(tmp_hp);
    1456                 :            :         tmp_hp = NULL;
    1457                 :            : 
    1458                 :          2 :         munmap(hugepage, nr_hugefiles * sizeof(struct hugepage_file));
    1459                 :            :         hugepage = NULL;
    1460                 :            : 
    1461                 :            :         /* we're not going to allocate more pages, so release VA space for
    1462                 :            :          * unused memseg lists
    1463                 :            :          */
    1464         [ +  + ]:        258 :         for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
    1465                 :            :                 struct rte_memseg_list *msl = &mcfg->memsegs[i];
    1466                 :            :                 size_t mem_sz;
    1467                 :            : 
    1468                 :            :                 /* skip inactive lists */
    1469         [ +  + ]:        256 :                 if (msl->base_va == NULL)
    1470                 :        240 :                         continue;
    1471                 :            :                 /* skip lists where there is at least one page allocated */
    1472         [ +  + ]:         16 :                 if (msl->memseg_arr.count > 0)
    1473                 :          2 :                         continue;
    1474                 :            :                 /* this is an unused list, deallocate it */
    1475                 :         14 :                 mem_sz = msl->len;
    1476                 :         14 :                 munmap(msl->base_va, mem_sz);
    1477                 :         14 :                 msl->base_va = NULL;
    1478                 :         14 :                 msl->len = 0;
    1479                 :         14 :                 msl->heap = 0;
    1480                 :            : 
    1481                 :            :                 /* destroy backing fbarray */
    1482                 :         14 :                 rte_fbarray_destroy(&msl->memseg_arr);
    1483                 :            :         }
    1484                 :            : 
    1485   [ -  +  -  - ]:          2 :         if (mcfg->dma_maskbits &&
    1486                 :          0 :             rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) {
    1487                 :          0 :                 EAL_LOG(ERR,
    1488                 :            :                         "%s(): couldn't allocate memory due to IOVA exceeding limits of current DMA mask.",
    1489                 :            :                         __func__);
    1490                 :          0 :                 goto fail;
    1491                 :            :         }
    1492                 :            : 
    1493                 :            :         return 0;
    1494                 :            : 
    1495         [ #  # ]:          0 : fail:
    1496                 :            :         huge_recover_sigbus();
    1497                 :          0 :         free(tmp_hp);
    1498         [ #  # ]:          0 :         if (hugepage != NULL)
    1499                 :          0 :                 munmap(hugepage, nr_hugefiles * sizeof(struct hugepage_file));
    1500                 :            : 
    1501                 :            :         return -1;
    1502                 :            : }
    1503                 :            : 
    1504                 :            : /*
    1505                 :            :  * uses fstat to report the size of a file on disk
    1506                 :            :  */
    1507                 :            : static off_t
    1508                 :            : getFileSize(int fd)
    1509                 :            : {
    1510                 :            :         struct stat st;
    1511         [ #  # ]:          0 :         if (fstat(fd, &st) < 0)
    1512                 :            :                 return 0;
    1513                 :          0 :         return st.st_size;
    1514                 :            : }
    1515                 :            : 
    1516                 :            : /*
    1517                 :            :  * This creates the memory mappings in the secondary process to match that of
    1518                 :            :  * the server process. It goes through each memory segment in the DPDK runtime
    1519                 :            :  * configuration and finds the hugepages which form that segment, mapping them
    1520                 :            :  * in order to form a contiguous block in the virtual memory space
    1521                 :            :  */
    1522                 :            : static int
    1523                 :          1 : eal_legacy_hugepage_attach(void)
    1524                 :            : {
    1525                 :          1 :         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
    1526                 :            :         struct hugepage_file *hp = NULL;
    1527                 :            :         unsigned int num_hp = 0;
    1528                 :            :         unsigned int i = 0;
    1529                 :            :         unsigned int cur_seg;
    1530                 :            :         off_t size = 0;
    1531                 :            :         int fd, fd_hugepage = -1;
    1532                 :            : 
    1533         [ +  - ]:          1 :         if (aslr_enabled() > 0) {
    1534                 :          1 :                 EAL_LOG(WARNING, "WARNING: Address Space Layout Randomization "
    1535                 :            :                                 "(ASLR) is enabled in the kernel.");
    1536                 :          1 :                 EAL_LOG(WARNING, "   This may cause issues with mapping memory "
    1537                 :            :                                 "into secondary processes");
    1538                 :            :         }
    1539                 :            : 
    1540                 :          1 :         fd_hugepage = open(eal_hugepage_data_path(), O_RDONLY);
    1541         [ +  - ]:          1 :         if (fd_hugepage < 0) {
    1542                 :          1 :                 EAL_LOG(ERR, "Could not open %s",
    1543                 :            :                                 eal_hugepage_data_path());
    1544                 :          1 :                 goto error;
    1545                 :            :         }
    1546                 :            : 
    1547                 :            :         size = getFileSize(fd_hugepage);
    1548                 :          0 :         hp = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd_hugepage, 0);
    1549         [ #  # ]:          0 :         if (hp == MAP_FAILED) {
    1550                 :          0 :                 EAL_LOG(ERR, "Could not mmap %s",
    1551                 :            :                                 eal_hugepage_data_path());
    1552                 :          0 :                 goto error;
    1553                 :            :         }
    1554                 :            : 
    1555                 :          0 :         num_hp = size / sizeof(struct hugepage_file);
    1556                 :          0 :         EAL_LOG(DEBUG, "Analysing %u files", num_hp);
    1557                 :            : 
    1558                 :            :         /* map all segments into memory to make sure we get the addrs. the
    1559                 :            :          * segments themselves are already in memseg list (which is shared and
    1560                 :            :          * has its VA space already preallocated), so we just need to map
    1561                 :            :          * everything into correct addresses.
    1562                 :            :          */
    1563         [ #  # ]:          0 :         for (i = 0; i < num_hp; i++) {
    1564                 :          0 :                 struct hugepage_file *hf = &hp[i];
    1565                 :          0 :                 size_t map_sz = hf->size;
    1566                 :          0 :                 void *map_addr = hf->final_va;
    1567                 :            :                 int msl_idx, ms_idx;
    1568                 :            :                 struct rte_memseg_list *msl;
    1569                 :            :                 struct rte_memseg *ms;
    1570                 :            : 
    1571                 :            :                 /* if size is zero, no more pages left */
    1572         [ #  # ]:          0 :                 if (map_sz == 0)
    1573                 :            :                         break;
    1574                 :            : 
    1575                 :          0 :                 fd = open(hf->filepath, O_RDWR);
    1576         [ #  # ]:          0 :                 if (fd < 0) {
    1577                 :          0 :                         EAL_LOG(ERR, "Could not open %s: %s",
    1578                 :            :                                 hf->filepath, strerror(errno));
    1579                 :          0 :                         goto error;
    1580                 :            :                 }
    1581                 :            : 
    1582                 :          0 :                 map_addr = mmap(map_addr, map_sz, PROT_READ | PROT_WRITE,
    1583                 :            :                                 MAP_SHARED | MAP_FIXED, fd, 0);
    1584         [ #  # ]:          0 :                 if (map_addr == MAP_FAILED) {
    1585                 :          0 :                         EAL_LOG(ERR, "Could not map %s: %s",
    1586                 :            :                                 hf->filepath, strerror(errno));
    1587                 :          0 :                         goto fd_error;
    1588                 :            :                 }
    1589                 :            : 
    1590                 :            :                 /* set shared lock on the file. */
    1591         [ #  # ]:          0 :                 if (flock(fd, LOCK_SH) < 0) {
    1592                 :          0 :                         EAL_LOG(DEBUG, "%s(): Locking file failed: %s",
    1593                 :            :                                 __func__, strerror(errno));
    1594                 :          0 :                         goto mmap_error;
    1595                 :            :                 }
    1596                 :            : 
    1597                 :            :                 /* find segment data */
    1598                 :          0 :                 msl = rte_mem_virt2memseg_list(map_addr);
    1599         [ #  # ]:          0 :                 if (msl == NULL) {
    1600                 :          0 :                         EAL_LOG(DEBUG, "%s(): Cannot find memseg list",
    1601                 :            :                                 __func__);
    1602                 :          0 :                         goto mmap_error;
    1603                 :            :                 }
    1604                 :          0 :                 ms = rte_mem_virt2memseg(map_addr, msl);
    1605         [ #  # ]:          0 :                 if (ms == NULL) {
    1606                 :          0 :                         EAL_LOG(DEBUG, "%s(): Cannot find memseg",
    1607                 :            :                                 __func__);
    1608                 :          0 :                         goto mmap_error;
    1609                 :            :                 }
    1610                 :            : 
    1611                 :          0 :                 msl_idx = msl - mcfg->memsegs;
    1612                 :          0 :                 ms_idx = rte_fbarray_find_idx(&msl->memseg_arr, ms);
    1613         [ #  # ]:          0 :                 if (ms_idx < 0) {
    1614                 :          0 :                         EAL_LOG(DEBUG, "%s(): Cannot find memseg idx",
    1615                 :            :                                 __func__);
    1616                 :          0 :                         goto mmap_error;
    1617                 :            :                 }
    1618                 :            : 
    1619                 :            :                 /* store segment fd internally */
    1620         [ #  # ]:          0 :                 if (eal_memalloc_set_seg_fd(msl_idx, ms_idx, fd) < 0)
    1621                 :          0 :                         EAL_LOG(ERR, "Could not store segment fd: %s",
    1622                 :            :                                 rte_strerror(rte_errno));
    1623                 :            :         }
    1624                 :            :         /* unmap the hugepage config file, since we are done using it */
    1625                 :          0 :         munmap(hp, size);
    1626                 :          0 :         close(fd_hugepage);
    1627                 :          0 :         return 0;
    1628                 :            : 
    1629                 :          0 : mmap_error:
    1630                 :          0 :         munmap(hp[i].final_va, hp[i].size);
    1631                 :          0 : fd_error:
    1632                 :          0 :         close(fd);
    1633                 :          1 : error:
    1634                 :            :         /* unwind mmap's done so far */
    1635         [ -  + ]:          1 :         for (cur_seg = 0; cur_seg < i; cur_seg++)
    1636                 :          0 :                 munmap(hp[cur_seg].final_va, hp[cur_seg].size);
    1637                 :            : 
    1638         [ -  + ]:          1 :         if (hp != NULL && hp != MAP_FAILED)
    1639                 :          0 :                 munmap(hp, size);
    1640         [ -  + ]:          1 :         if (fd_hugepage >= 0)
    1641                 :          0 :                 close(fd_hugepage);
    1642                 :            :         return -1;
    1643                 :            : }
    1644                 :            : 
    1645                 :            : static int
    1646                 :         26 : eal_hugepage_attach(void)
    1647                 :            : {
    1648         [ +  + ]:         26 :         if (eal_memalloc_sync_with_primary()) {
    1649                 :          1 :                 EAL_LOG(ERR, "Could not map memory from primary process");
    1650         [ +  - ]:          1 :                 if (aslr_enabled() > 0)
    1651                 :          1 :                         EAL_LOG(ERR, "It is recommended to disable ASLR in the kernel and retry running both primary and secondary processes");
    1652                 :          1 :                 return -1;
    1653                 :            :         }
    1654                 :            :         return 0;
    1655                 :            : }
    1656                 :            : 
    1657                 :            : int
    1658                 :        156 : rte_eal_hugepage_init(void)
    1659                 :            : {
    1660                 :            :         const struct internal_config *internal_conf =
    1661                 :        156 :                 eal_get_internal_configuration();
    1662                 :            : 
    1663                 :        156 :         return internal_conf->legacy_mem ?
    1664         [ +  + ]:        156 :                         eal_legacy_hugepage_init() :
    1665                 :         55 :                         eal_dynmem_hugepage_init();
    1666                 :            : }
    1667                 :            : 
    1668                 :            : int
    1669                 :         27 : rte_eal_hugepage_attach(void)
    1670                 :            : {
    1671                 :            :         const struct internal_config *internal_conf =
    1672                 :         27 :                 eal_get_internal_configuration();
    1673                 :            : 
    1674                 :         27 :         return internal_conf->legacy_mem ?
    1675         [ +  + ]:         27 :                         eal_legacy_hugepage_attach() :
    1676                 :         26 :                         eal_hugepage_attach();
    1677                 :            : }
    1678                 :            : 
    1679                 :            : RTE_EXPORT_SYMBOL(rte_eal_using_phys_addrs)
    1680                 :            : int
    1681                 :        187 : rte_eal_using_phys_addrs(void)
    1682                 :            : {
    1683         [ +  + ]:        187 :         if (phys_addrs_available == -1) {
    1684                 :        185 :                 uint64_t tmp = 0;
    1685                 :            : 
    1686   [ +  +  +  - ]:        271 :                 if (rte_eal_has_hugepages() != 0 &&
    1687                 :         86 :                     rte_mem_virt2phy(&tmp) != RTE_BAD_PHYS_ADDR)
    1688                 :         86 :                         phys_addrs_available = 1;
    1689                 :            :                 else
    1690                 :         99 :                         phys_addrs_available = 0;
    1691                 :            :         }
    1692                 :        187 :         return phys_addrs_available;
    1693                 :            : }
    1694                 :            : 
    1695                 :            : static int __rte_unused
    1696                 :            : memseg_primary_init_32(void)
    1697                 :            : {
    1698                 :            :         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
    1699                 :            :         int active_sockets, hpi_idx, msl_idx = 0;
    1700                 :            :         unsigned int socket_id, i;
    1701                 :            :         struct rte_memseg_list *msl;
    1702                 :            :         uint64_t extra_mem_per_socket, total_extra_mem, total_requested_mem;
    1703                 :            :         uint64_t max_mem;
    1704                 :            :         struct internal_config *internal_conf =
    1705                 :            :                 eal_get_internal_configuration();
    1706                 :            : 
    1707                 :            :         /* no-huge does not need this at all */
    1708                 :            :         if (internal_conf->no_hugetlbfs)
    1709                 :            :                 return 0;
    1710                 :            : 
    1711                 :            :         /* this is a giant hack, but desperate times call for desperate
    1712                 :            :          * measures. in legacy 32-bit mode, we cannot preallocate VA space,
    1713                 :            :          * because having upwards of 2 gigabytes of VA space already mapped will
    1714                 :            :          * interfere with our ability to map and sort hugepages.
    1715                 :            :          *
    1716                 :            :          * therefore, in legacy 32-bit mode, we will be initializing memseg
    1717                 :            :          * lists much later - in eal_memory.c, right after we unmap all the
    1718                 :            :          * unneeded pages. this will not affect secondary processes, as those
    1719                 :            :          * should be able to mmap the space without (too many) problems.
    1720                 :            :          */
    1721                 :            :         if (internal_conf->legacy_mem)
    1722                 :            :                 return 0;
    1723                 :            : 
    1724                 :            :         /* 32-bit mode is a very special case. we cannot know in advance where
    1725                 :            :          * the user will want to allocate their memory, so we have to do some
    1726                 :            :          * heuristics.
    1727                 :            :          */
    1728                 :            :         active_sockets = 0;
    1729                 :            :         total_requested_mem = 0;
    1730                 :            :         if (internal_conf->force_sockets)
    1731                 :            :                 for (i = 0; i < rte_socket_count(); i++) {
    1732                 :            :                         uint64_t mem;
    1733                 :            : 
    1734                 :            :                         socket_id = rte_socket_id_by_idx(i);
    1735                 :            :                         mem = internal_conf->socket_mem[socket_id];
    1736                 :            : 
    1737                 :            :                         if (mem == 0)
    1738                 :            :                                 continue;
    1739                 :            : 
    1740                 :            :                         active_sockets++;
    1741                 :            :                         total_requested_mem += mem;
    1742                 :            :                 }
    1743                 :            :         else
    1744                 :            :                 total_requested_mem = internal_conf->memory;
    1745                 :            : 
    1746                 :            :         max_mem = (uint64_t)RTE_MAX_MEM_MB << 20;
    1747                 :            :         if (total_requested_mem > max_mem) {
    1748                 :            :                 EAL_LOG(ERR, "Invalid parameters: 32-bit process can at most use %uM of memory",
    1749                 :            :                                 (unsigned int)(max_mem >> 20));
    1750                 :            :                 return -1;
    1751                 :            :         }
    1752                 :            :         total_extra_mem = max_mem - total_requested_mem;
    1753                 :            :         extra_mem_per_socket = active_sockets == 0 ? total_extra_mem :
    1754                 :            :                         total_extra_mem / active_sockets;
    1755                 :            : 
    1756                 :            :         /* the allocation logic is a little bit convoluted, but here's how it
    1757                 :            :          * works, in a nutshell:
    1758                 :            :          *  - if user hasn't specified on which sockets to allocate memory via
    1759                 :            :          *    --socket-mem, we allocate all of our memory on main core socket.
    1760                 :            :          *  - if user has specified sockets to allocate memory on, there may be
    1761                 :            :          *    some "unused" memory left (e.g. if user has specified --socket-mem
    1762                 :            :          *    such that not all memory adds up to 2 gigabytes), so add it to all
    1763                 :            :          *    sockets that are in use equally.
    1764                 :            :          *
    1765                 :            :          * page sizes are sorted by size in descending order, so we can safely
    1766                 :            :          * assume that we dispense with bigger page sizes first.
    1767                 :            :          */
    1768                 :            : 
    1769                 :            :         /* create memseg lists */
    1770                 :            :         for (i = 0; i < rte_socket_count(); i++) {
    1771                 :            :                 int hp_sizes = (int) internal_conf->num_hugepage_sizes;
    1772                 :            :                 uint64_t max_socket_mem, cur_socket_mem;
    1773                 :            :                 unsigned int main_lcore_socket;
    1774                 :            :                 struct rte_config *cfg = rte_eal_get_configuration();
    1775                 :            :                 bool skip;
    1776                 :            : 
    1777                 :            :                 socket_id = rte_socket_id_by_idx(i);
    1778                 :            : 
    1779                 :            : #ifndef RTE_EAL_NUMA_AWARE_HUGEPAGES
    1780                 :            :                 /* we can still sort pages by socket in legacy mode */
    1781                 :            :                 if (!internal_conf->legacy_mem && socket_id > 0)
    1782                 :            :                         break;
    1783                 :            : #endif
    1784                 :            : 
    1785                 :            :                 /* if we didn't specifically request memory on this socket */
    1786                 :            :                 skip = active_sockets != 0 &&
    1787                 :            :                                 internal_conf->socket_mem[socket_id] == 0;
    1788                 :            :                 /* ...or if we didn't specifically request memory on *any*
    1789                 :            :                  * socket, and this is not main lcore
    1790                 :            :                  */
    1791                 :            :                 main_lcore_socket = rte_lcore_to_socket_id(cfg->main_lcore);
    1792                 :            :                 skip |= active_sockets == 0 && socket_id != main_lcore_socket;
    1793                 :            : 
    1794                 :            :                 if (skip) {
    1795                 :            :                         EAL_LOG(DEBUG, "Will not preallocate memory on socket %u",
    1796                 :            :                                         socket_id);
    1797                 :            :                         continue;
    1798                 :            :                 }
    1799                 :            : 
    1800                 :            :                 /* max amount of memory on this socket */
    1801                 :            :                 max_socket_mem = (active_sockets != 0 ?
    1802                 :            :                                         internal_conf->socket_mem[socket_id] :
    1803                 :            :                                         internal_conf->memory) +
    1804                 :            :                                         extra_mem_per_socket;
    1805                 :            :                 cur_socket_mem = 0;
    1806                 :            : 
    1807                 :            :                 for (hpi_idx = 0; hpi_idx < hp_sizes; hpi_idx++) {
    1808                 :            :                         uint64_t max_pagesz_mem, cur_pagesz_mem = 0;
    1809                 :            :                         uint64_t hugepage_sz;
    1810                 :            :                         struct hugepage_info *hpi;
    1811                 :            :                         int type_msl_idx, max_segs, total_segs = 0;
    1812                 :            : 
    1813                 :            :                         hpi = &internal_conf->hugepage_info[hpi_idx];
    1814                 :            :                         hugepage_sz = hpi->hugepage_sz;
    1815                 :            : 
    1816                 :            :                         /* check if pages are actually available */
    1817                 :            :                         if (hpi->num_pages[socket_id] == 0)
    1818                 :            :                                 continue;
    1819                 :            : 
    1820                 :            :                         max_segs = RTE_MAX_MEMSEG_PER_TYPE;
    1821                 :            :                         max_pagesz_mem = max_socket_mem - cur_socket_mem;
    1822                 :            : 
    1823                 :            :                         /* make it multiple of page size */
    1824                 :            :                         max_pagesz_mem = RTE_ALIGN_FLOOR(max_pagesz_mem,
    1825                 :            :                                         hugepage_sz);
    1826                 :            : 
    1827                 :            :                         EAL_LOG(DEBUG, "Attempting to preallocate "
    1828                 :            :                                         "%" PRIu64 "M on socket %i",
    1829                 :            :                                         max_pagesz_mem >> 20, socket_id);
    1830                 :            : 
    1831                 :            :                         type_msl_idx = 0;
    1832                 :            :                         while (cur_pagesz_mem < max_pagesz_mem &&
    1833                 :            :                                         total_segs < max_segs) {
    1834                 :            :                                 uint64_t cur_mem;
    1835                 :            :                                 unsigned int n_segs;
    1836                 :            : 
    1837                 :            :                                 if (msl_idx >= RTE_MAX_MEMSEG_LISTS) {
    1838                 :            :                                         EAL_LOG(ERR,
    1839                 :            :                                                 "No more space in memseg lists, please increase RTE_MAX_MEMSEG_LISTS");
    1840                 :            :                                         return -1;
    1841                 :            :                                 }
    1842                 :            : 
    1843                 :            :                                 msl = &mcfg->memsegs[msl_idx];
    1844                 :            : 
    1845                 :            :                                 cur_mem = get_mem_amount(hugepage_sz,
    1846                 :            :                                                 max_pagesz_mem);
    1847                 :            :                                 n_segs = cur_mem / hugepage_sz;
    1848                 :            : 
    1849                 :            :                                 if (eal_memseg_list_init(msl, hugepage_sz,
    1850                 :            :                                                 n_segs, socket_id, type_msl_idx,
    1851                 :            :                                                 true)) {
    1852                 :            :                                         /* failing to allocate a memseg list is
    1853                 :            :                                          * a serious error.
    1854                 :            :                                          */
    1855                 :            :                                         EAL_LOG(ERR, "Cannot allocate memseg list");
    1856                 :            :                                         return -1;
    1857                 :            :                                 }
    1858                 :            : 
    1859                 :            :                                 if (eal_memseg_list_alloc(msl, 0)) {
    1860                 :            :                                         /* if we couldn't allocate VA space, we
    1861                 :            :                                          * can try with smaller page sizes.
    1862                 :            :                                          */
    1863                 :            :                                         EAL_LOG(ERR, "Cannot allocate VA space for memseg list, retrying with different page size");
    1864                 :            :                                         /* deallocate memseg list */
    1865                 :            :                                         if (memseg_list_free(msl))
    1866                 :            :                                                 return -1;
    1867                 :            :                                         break;
    1868                 :            :                                 }
    1869                 :            : 
    1870                 :            :                                 total_segs += msl->memseg_arr.len;
    1871                 :            :                                 cur_pagesz_mem = total_segs * hugepage_sz;
    1872                 :            :                                 type_msl_idx++;
    1873                 :            :                                 msl_idx++;
    1874                 :            :                         }
    1875                 :            :                         cur_socket_mem += cur_pagesz_mem;
    1876                 :            :                 }
    1877                 :            :                 if (cur_socket_mem == 0) {
    1878                 :            :                         EAL_LOG(ERR, "Cannot allocate VA space on socket %u",
    1879                 :            :                                 socket_id);
    1880                 :            :                         return -1;
    1881                 :            :                 }
    1882                 :            :         }
    1883                 :            : 
    1884                 :            :         return 0;
    1885                 :            : }
    1886                 :            : 
    1887                 :            : static int __rte_unused
    1888                 :            : memseg_primary_init(void)
    1889                 :            : {
    1890                 :        156 :         return eal_dynmem_memseg_lists_init();
    1891                 :            : }
    1892                 :            : 
    1893                 :            : static int
    1894                 :         27 : memseg_secondary_init(void)
    1895                 :            : {
    1896                 :         27 :         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
    1897                 :            :         int msl_idx = 0;
    1898                 :            :         struct rte_memseg_list *msl;
    1899                 :            : 
    1900         [ +  + ]:       3483 :         for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS; msl_idx++) {
    1901                 :            : 
    1902                 :       3456 :                 msl = &mcfg->memsegs[msl_idx];
    1903                 :            : 
    1904                 :            :                 /* skip empty and external memseg lists */
    1905   [ +  +  -  + ]:       3456 :                 if (msl->memseg_arr.len == 0 || msl->external)
    1906                 :       3247 :                         continue;
    1907                 :            : 
    1908         [ -  + ]:        209 :                 if (rte_fbarray_attach(&msl->memseg_arr)) {
    1909                 :          0 :                         EAL_LOG(ERR, "Cannot attach to primary process memseg lists");
    1910                 :          0 :                         return -1;
    1911                 :            :                 }
    1912                 :            : 
    1913                 :            :                 /* preallocate VA space */
    1914         [ -  + ]:        209 :                 if (eal_memseg_list_alloc(msl, 0)) {
    1915                 :          0 :                         EAL_LOG(ERR, "Cannot preallocate VA space for hugepage memory");
    1916                 :          0 :                         return -1;
    1917                 :            :                 }
    1918                 :            :         }
    1919                 :            : 
    1920                 :            :         return 0;
    1921                 :            : }
    1922                 :            : 
    1923                 :            : int
    1924                 :        183 : rte_eal_memseg_init(void)
    1925                 :            : {
    1926                 :            :         /* increase rlimit to maximum */
    1927                 :            :         struct rlimit lim;
    1928                 :            : 
    1929                 :            : #ifndef RTE_EAL_NUMA_AWARE_HUGEPAGES
    1930                 :            :         const struct internal_config *internal_conf =
    1931                 :            :                 eal_get_internal_configuration();
    1932                 :            : #endif
    1933         [ +  - ]:        183 :         if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
    1934                 :            :                 /* set limit to maximum */
    1935                 :        183 :                 lim.rlim_cur = lim.rlim_max;
    1936                 :            : 
    1937         [ -  + ]:        183 :                 if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
    1938                 :          0 :                         EAL_LOG(DEBUG, "Setting maximum number of open files failed: %s",
    1939                 :            :                                         strerror(errno));
    1940                 :            :                 } else {
    1941                 :        183 :                         EAL_LOG(DEBUG, "Setting maximum number of open files to %"
    1942                 :            :                                         PRIu64,
    1943                 :            :                                         (uint64_t)lim.rlim_cur);
    1944                 :            :                 }
    1945                 :            :         } else {
    1946                 :          0 :                 EAL_LOG(ERR, "Cannot get current resource limits");
    1947                 :            :         }
    1948                 :            : #ifndef RTE_EAL_NUMA_AWARE_HUGEPAGES
    1949                 :            :         if (!internal_conf->legacy_mem && rte_socket_count() > 1) {
    1950                 :            :                 EAL_LOG(WARNING, "DPDK is running on a NUMA system, but is compiled without NUMA support.");
    1951                 :            :                 EAL_LOG(WARNING, "This will have adverse consequences for performance and usability.");
    1952                 :            :                 EAL_LOG(WARNING, "Please use --"OPT_LEGACY_MEM" option, or recompile with NUMA support.");
    1953                 :            :         }
    1954                 :            : #endif
    1955                 :            : 
    1956                 :        183 :         return rte_eal_process_type() == RTE_PROC_PRIMARY ?
    1957                 :            : #ifndef RTE_ARCH_64
    1958                 :            :                         memseg_primary_init_32() :
    1959                 :            : #else
    1960         [ +  + ]:        183 :                         memseg_primary_init() :
    1961                 :            : #endif
    1962                 :         27 :                         memseg_secondary_init();
    1963                 :            : }

Generated by: LCOV version 1.14