mem: preallocate VA space in no-huge mode
authorAnatoly Burakov <anatoly.burakov@intel.com>
Fri, 7 Feb 2020 11:11:14 +0000 (11:11 +0000)
committerDavid Marchand <david.marchand@redhat.com>
Fri, 27 Mar 2020 10:04:09 +0000 (11:04 +0100)
When --no-huge mode is used, the memory is currently allocated with
mmap(NULL, ...). This is fine in most cases, but can fail in cases
where DPDK is run on a machine with an IOMMU that is of more limited
address width than that of a VA, because we're not specifying the
address hint for mmap() call.

Fix it by preallocating VA space before mapping it.

Cc: stable@dpdk.org
Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Tested-by: David Marchand <david.marchand@redhat.com>
Tested-by: Jun W Zhou <junx.w.zhou@intel.com>
lib/librte_eal/linux/eal/eal_memory.c

index 5604c2a..7a9c97f 100644 (file)
@@ -1340,6 +1340,8 @@ eal_legacy_hugepage_init(void)
 
        /* hugetlbfs can be disabled */
        if (internal_config.no_hugetlbfs) {
+               void *prealloc_addr;
+               size_t mem_sz;
                struct rte_memseg_list *msl;
                int n_segs, cur_seg, fd, flags;
 #ifdef MEMFD_SUPPORTED
@@ -1395,17 +1397,31 @@ eal_legacy_hugepage_init(void)
                        }
                }
 #endif
-               addr = mmap(NULL, internal_config.memory, PROT_READ | PROT_WRITE,
-                               flags, fd, 0);
-               if (addr == MAP_FAILED) {
+               /* preallocate address space for the memory, so that it can be
+                * fit into the DMA mask.
+                */
+               mem_sz = internal_config.memory;
+               prealloc_addr = eal_get_virtual_area(
+                               NULL, &mem_sz, page_sz, 0, 0);
+               if (prealloc_addr == NULL) {
+                       RTE_LOG(ERR, EAL,
+                                       "%s: reserving memory area failed: "
+                                       "%s\n",
+                                       __func__, strerror(errno));
+                       return -1;
+               }
+               addr = mmap(prealloc_addr, mem_sz, PROT_READ | PROT_WRITE,
+                               flags | MAP_FIXED, fd, 0);
+               if (addr == MAP_FAILED || addr != prealloc_addr) {
                        RTE_LOG(ERR, EAL, "%s: mmap() failed: %s\n", __func__,
                                        strerror(errno));
+                       munmap(prealloc_addr, mem_sz);
                        return -1;
                }
                msl->base_va = addr;
                msl->page_sz = page_sz;
                msl->socket_id = 0;
-               msl->len = internal_config.memory;
+               msl->len = mem_sz;
                msl->heap = 1;
 
                /* we're in single-file segments mode, so only the segment list