mem: move virtual area function in common directory

Move get_virtual_area out of linuxapp EAL memory and make it
common to EAL, so that other code could reserve virtual areas
as well.

Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Tested-by: Santosh Shukla <santosh.shukla@caviumnetworks.com>
Tested-by: Hemant Agrawal <hemant.agrawal@nxp.com>
Tested-by: Gowrishankar Muthukrishnan <gowrishankar.m@linux.vnet.ibm.com>
This commit is contained in:
Anatoly Burakov 2018-04-11 13:29:36 +01:00 committed by Thomas Monjalon
parent bef5a2d629
commit b7cc54187e
3 changed files with 161 additions and 110 deletions

View File

@ -2,10 +2,12 @@
* Copyright(c) 2010-2014 Intel Corporation
*/
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/mman.h>
@ -14,11 +16,110 @@
#include <rte_memory.h>
#include <rte_eal.h>
#include <rte_eal_memconfig.h>
#include <rte_errno.h>
#include <rte_log.h>
#include "eal_private.h"
#include "eal_internal_cfg.h"
/*
* Try to mmap *size bytes in /dev/zero. If it is successful, return the
* pointer to the mmap'd area and keep *size unmodified. Else, retry
* with a smaller zone: decrease *size by hugepage_sz until it reaches
* 0. In this case, return NULL. Note: this function returns an address
* which is a multiple of hugepage size.
*/
static uint64_t baseaddr_offset;
static uint64_t system_page_sz;
void *
eal_get_virtual_area(void *requested_addr, size_t *size,
size_t page_sz, int flags, int mmap_flags)
{
bool addr_is_hint, allow_shrink, unmap, no_align;
uint64_t map_sz;
void *mapped_addr, *aligned_addr;
if (system_page_sz == 0)
system_page_sz = sysconf(_SC_PAGESIZE);
mmap_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zx bytes\n", *size);
addr_is_hint = (flags & EAL_VIRTUAL_AREA_ADDR_IS_HINT) > 0;
allow_shrink = (flags & EAL_VIRTUAL_AREA_ALLOW_SHRINK) > 0;
unmap = (flags & EAL_VIRTUAL_AREA_UNMAP) > 0;
if (requested_addr == NULL && internal_config.base_virtaddr != 0) {
requested_addr = (void *) (internal_config.base_virtaddr +
(size_t)baseaddr_offset);
requested_addr = RTE_PTR_ALIGN(requested_addr, page_sz);
addr_is_hint = true;
}
/* if requested address is not aligned by page size, or if requested
* address is NULL, add page size to requested length as we may get an
* address that's aligned by system page size, which can be smaller than
* our requested page size. additionally, we shouldn't try to align if
* system page size is the same as requested page size.
*/
no_align = (requested_addr != NULL &&
((uintptr_t)requested_addr & (page_sz - 1)) == 0) ||
page_sz == system_page_sz;
do {
map_sz = no_align ? *size : *size + page_sz;
mapped_addr = mmap(requested_addr, map_sz, PROT_READ,
mmap_flags, -1, 0);
if (mapped_addr == MAP_FAILED && allow_shrink)
*size -= page_sz;
} while (allow_shrink && mapped_addr == MAP_FAILED && *size > 0);
/* align resulting address - if map failed, we will ignore the value
* anyway, so no need to add additional checks.
*/
aligned_addr = no_align ? mapped_addr :
RTE_PTR_ALIGN(mapped_addr, page_sz);
if (*size == 0) {
RTE_LOG(ERR, EAL, "Cannot get a virtual area of any size: %s\n",
strerror(errno));
rte_errno = errno;
return NULL;
} else if (mapped_addr == MAP_FAILED) {
RTE_LOG(ERR, EAL, "Cannot get a virtual area: %s\n",
strerror(errno));
/* pass errno up the call chain */
rte_errno = errno;
return NULL;
} else if (requested_addr != NULL && !addr_is_hint &&
aligned_addr != requested_addr) {
RTE_LOG(ERR, EAL, "Cannot get a virtual area at requested address: %p (got %p)\n",
requested_addr, aligned_addr);
munmap(mapped_addr, map_sz);
rte_errno = EADDRNOTAVAIL;
return NULL;
} else if (requested_addr != NULL && addr_is_hint &&
aligned_addr != requested_addr) {
RTE_LOG(WARNING, EAL, "WARNING! Base virtual address hint (%p != %p) not respected!\n",
requested_addr, aligned_addr);
RTE_LOG(WARNING, EAL, " This may cause issues with mapping memory into secondary processes\n");
}
if (unmap)
munmap(mapped_addr, map_sz);
RTE_LOG(DEBUG, EAL, "Virtual area found at %p (size = 0x%zx)\n",
aligned_addr, *size);
baseaddr_offset += *size;
return aligned_addr;
}
/*
* Return a pointer to a read-only table of struct rte_physmem_desc
* elements, containing the layout of all addressable physical

View File

@ -126,6 +126,39 @@ int rte_eal_alarm_init(void);
*/
int rte_eal_check_module(const char *module_name);
/**
* Get virtual area of specified size from the OS.
*
* This function is private to the EAL.
*
* @param requested_addr
* Address where to request address space.
* @param size
* Size of requested area.
* @param page_sz
* Page size on which to align requested virtual area.
* @param flags
* EAL_VIRTUAL_AREA_* flags.
* @param mmap_flags
* Extra flags passed directly to mmap().
*
* @return
* Virtual area address if successful.
* NULL if unsuccessful.
*/
#define EAL_VIRTUAL_AREA_ADDR_IS_HINT (1 << 0)
/**< don't fail if cannot get exact requested address. */
#define EAL_VIRTUAL_AREA_ALLOW_SHRINK (1 << 1)
/**< try getting smaller sized (decrement by page size) virtual areas if cannot
* get area of requested size.
*/
#define EAL_VIRTUAL_AREA_UNMAP (1 << 2)
/**< immediately unmap reserved virtual area. */
void *
eal_get_virtual_area(void *requested_addr, size_t *size,
size_t page_sz, int flags, int mmap_flags);
/**
* Get cpu core_id.
*

View File

@ -28,6 +28,7 @@
#include <numaif.h>
#endif
#include <rte_errno.h>
#include <rte_log.h>
#include <rte_memory.h>
#include <rte_launch.h>
@ -57,8 +58,6 @@
* zone as well as a physical contiguous zone.
*/
static uint64_t baseaddr_offset;
static bool phys_addrs_available = true;
#define RANDOMIZE_VA_SPACE_FILE "/proc/sys/kernel/randomize_va_space"
@ -221,82 +220,6 @@ aslr_enabled(void)
}
}
/*
* Try to mmap *size bytes in /dev/zero. If it is successful, return the
* pointer to the mmap'd area and keep *size unmodified. Else, retry
* with a smaller zone: decrease *size by hugepage_sz until it reaches
* 0. In this case, return NULL. Note: this function returns an address
* which is a multiple of hugepage size.
*/
static void *
get_virtual_area(size_t *size, size_t hugepage_sz)
{
void *addr;
void *addr_hint;
int fd;
long aligned_addr;
if (internal_config.base_virtaddr != 0) {
int page_size = sysconf(_SC_PAGE_SIZE);
addr_hint = (void *) (uintptr_t)
(internal_config.base_virtaddr + baseaddr_offset);
addr_hint = RTE_PTR_ALIGN_FLOOR(addr_hint, page_size);
} else {
addr_hint = NULL;
}
RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zx bytes\n", *size);
fd = open("/dev/zero", O_RDONLY);
if (fd < 0){
RTE_LOG(ERR, EAL, "Cannot open /dev/zero\n");
return NULL;
}
do {
addr = mmap(addr_hint, (*size) + hugepage_sz, PROT_READ,
#ifdef RTE_ARCH_PPC_64
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
#else
MAP_PRIVATE,
#endif
fd, 0);
if (addr == MAP_FAILED) {
*size -= hugepage_sz;
} else if (addr_hint != NULL && addr != addr_hint) {
RTE_LOG(WARNING, EAL, "WARNING! Base virtual address "
"hint (%p != %p) not respected!\n",
addr_hint, addr);
RTE_LOG(WARNING, EAL, " This may cause issues with "
"mapping memory into secondary processes\n");
}
} while (addr == MAP_FAILED && *size > 0);
if (addr == MAP_FAILED) {
close(fd);
RTE_LOG(ERR, EAL, "Cannot get a virtual area: %s\n",
strerror(errno));
return NULL;
}
munmap(addr, (*size) + hugepage_sz);
close(fd);
/* align addr to a huge page size boundary */
aligned_addr = (long)addr;
aligned_addr += (hugepage_sz - 1);
aligned_addr &= (~(hugepage_sz - 1));
addr = (void *)(aligned_addr);
RTE_LOG(DEBUG, EAL, "Virtual area found at %p (size = 0x%zx)\n",
addr, *size);
/* increment offset */
baseaddr_offset += *size;
return addr;
}
static sigjmp_buf huge_jmpenv;
static void huge_sigbus_handler(int signo __rte_unused)
@ -445,7 +368,16 @@ map_all_hugepages(struct hugepage_file *hugepg_tbl, struct hugepage_info *hpi,
/* get the biggest virtual memory area up to
* vma_len. If it fails, vma_addr is NULL, so
* let the kernel provide the address. */
vma_addr = get_virtual_area(&vma_len, hpi->hugepage_sz);
vma_addr = eal_get_virtual_area(NULL, &vma_len,
hpi->hugepage_sz,
EAL_VIRTUAL_AREA_ALLOW_SHRINK |
EAL_VIRTUAL_AREA_UNMAP,
#ifdef RTE_ARCH_PPC_64
MAP_HUGETLB
#else
0
#endif
);
if (vma_addr == NULL)
vma_len = hugepage_sz;
}
@ -1343,7 +1275,7 @@ rte_eal_hugepage_attach(void)
unsigned i, s = 0; /* s used to track the segment number */
unsigned max_seg = RTE_MAX_MEMSEG;
off_t size = 0;
int fd, fd_zero = -1, fd_hugepage = -1;
int fd, fd_hugepage = -1;
if (aslr_enabled() > 0) {
RTE_LOG(WARNING, EAL, "WARNING: Address Space Layout Randomization "
@ -1354,11 +1286,6 @@ rte_eal_hugepage_attach(void)
test_phys_addrs_available();
fd_zero = open("/dev/zero", O_RDONLY);
if (fd_zero < 0) {
RTE_LOG(ERR, EAL, "Could not open /dev/zero\n");
goto error;
}
fd_hugepage = open(eal_hugepage_info_path(), O_RDONLY);
if (fd_hugepage < 0) {
RTE_LOG(ERR, EAL, "Could not open %s\n", eal_hugepage_info_path());
@ -1368,6 +1295,8 @@ rte_eal_hugepage_attach(void)
/* map all segments into memory to make sure we get the addrs */
for (s = 0; s < RTE_MAX_MEMSEG; ++s) {
void *base_addr;
size_t mmap_sz;
int mmap_flags = 0;
/*
* the first memory segment with len==0 is the one that
@ -1376,35 +1305,26 @@ rte_eal_hugepage_attach(void)
if (mcfg->memseg[s].len == 0)
break;
/*
* fdzero is mmapped to get a contiguous block of virtual
* addresses of the appropriate memseg size.
* use mmap to get identical addresses as the primary process.
/* get identical addresses as the primary process.
*/
base_addr = mmap(mcfg->memseg[s].addr, mcfg->memseg[s].len,
PROT_READ,
#ifdef RTE_ARCH_PPC_64
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
#else
MAP_PRIVATE,
mmap_flags |= MAP_HUGETLB;
#endif
fd_zero, 0);
if (base_addr == MAP_FAILED ||
base_addr != mcfg->memseg[s].addr) {
mmap_sz = mcfg->memseg[s].len;
base_addr = eal_get_virtual_area(mcfg->memseg[s].addr,
&mmap_sz, mcfg->memseg[s].hugepage_sz, 0,
mmap_flags);
if (base_addr == NULL) {
max_seg = s;
if (base_addr != MAP_FAILED) {
/* errno is stale, don't use */
RTE_LOG(ERR, EAL, "Could not mmap %zu bytes "
"in /dev/zero at [%p], got [%p] - "
"please use '--base-virtaddr' option\n",
if (rte_errno == EADDRNOTAVAIL) {
RTE_LOG(ERR, EAL, "Could not mmap %zu bytes at [%p] - please use '--base-virtaddr' option\n",
mcfg->memseg[s].len,
mcfg->memseg[s].addr, base_addr);
munmap(base_addr, mcfg->memseg[s].len);
mcfg->memseg[s].addr);
} else {
RTE_LOG(ERR, EAL, "Could not mmap %zu bytes "
"in /dev/zero at [%p]: '%s'\n",
RTE_LOG(ERR, EAL, "Could not mmap %zu bytes at [%p]: '%s'\n",
mcfg->memseg[s].len,
mcfg->memseg[s].addr, strerror(errno));
mcfg->memseg[s].addr,
rte_strerror(rte_errno));
}
if (aslr_enabled() > 0) {
RTE_LOG(ERR, EAL, "It is recommended to "
@ -1469,7 +1389,6 @@ rte_eal_hugepage_attach(void)
}
/* unmap the hugepage config file, since we are done using it */
munmap(hp, size);
close(fd_zero);
close(fd_hugepage);
return 0;
@ -1478,8 +1397,6 @@ error:
munmap(mcfg->memseg[i].addr, mcfg->memseg[i].len);
if (hp != NULL && hp != MAP_FAILED)
munmap(hp, size);
if (fd_zero >= 0)
close(fd_zero);
if (fd_hugepage >= 0)
close(fd_hugepage);
return -1;