Memory Hotplug for DPDK
Subsystems (4)
v4 cover Memory Hotplug for DPDK
In reply to Anatoly BurakovThis patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].
Dependencies (to be applied in specified order):
- EAL IOVA fix [2]
Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [3]
The vast majority of changes are in the EAL and malloc, the external API disruption is minimal: a new set of API's are added for contiguous memory allocation for rte_memzone, and a few API additions in rte_memory due to switch to memseg_lists as opposed to memsegs. Every other API change is internal to EAL, and all of the memory allocation/freeing is handled through rte_malloc, with no externally visible API changes.
Quick outline of all changes done as part of this patchset:
* Malloc heap adjusted to handle holes in address space
* Single memseg list replaced by multiple memseg lists
* VA space for hugepages is preallocated in advance
* Added alloc/free for pages happening as needed on rte_malloc/rte_free
* Added contiguous memory allocation API's for rte_memzone
* Added convenience API calls to walk over memsegs
* Integrated Pawel Wodkowski's patch for registering/unregistering memory with VFIO [4]
* Callbacks for registering memory allocations
* Callbacks for allowing/disallowing allocations above specified limit
* Multiprocess support done via DPDK IPC introduced in 18.02
The biggest difference is a "memseg" now represents a single page (as opposed to being a big contiguous block of pages). As a consequence, both memzones and malloc elements are no longer guaranteed to be physically contiguous, unless the user asks for it at reserve time. To preserve whatever functionality that was dependent on previous behavior, a legacy memory option is also provided, however it is expected (or perhaps vainly hoped) to be temporary solution.
Why multiple memseg lists instead of one? Since memseg is a single page now, the list of memsegs will get quite big, and we need to locate pages somehow when we allocate and free them. We could of course just walk the list and allocate one contiguous chunk of VA space for memsegs, but this implementation uses separate lists instead in order to speed up many operations with memseg lists.
For v4, the following limitations are present:
- VFIO support for multiple processes is not well-tested; work is ongoing to validate VFIO for all use cases
- There are known problems with PPC64 VFIO code
- For DPAA and FSLMC platforms, performance will be heavily degraded for IOVA as PA cases; separate patches are expected to address the issue
For testing, it is recommended to use the GitHub repository [5], as it will have all of the dependencies already integrated.
v4:
- Fixed bug in memzone lookup
- Added draft fslmc VFIO code
- Rebased on latest master + dependent patchset
- Documented limitations for *_walk() functions
v3:
- Lots of compile fixes
- Fixes for multiprocess synchronization
- Introduced support for sPAPR IOMMU, courtesy of Gowrishankar @ IBM
- Fixes for mempool size calculation
- Added convenience memseg walk() API's
- Added alloc validation callback
v2: - fixed deadlock at init
- reverted rte_panic changes at init, this is now handled inside IPC
[1] http://dpdk.org/dev/patchwork/bundle/aburakov/Memory_RFC/
[2] http://dpdk.org/dev/patchwork/bundle/aburakov/IOVA_mode_fixes/
[3] http://dpdk.org/dev/patchwork/patch/34002/
[4] http://dpdk.org/dev/patchwork/patch/24484/
[5] https://github.com/anatolyburakov/dpdk
Anatoly Burakov (70):
eal: move get_virtual_area out of linuxapp eal_memory.c
eal: move all locking to heap
eal: make malloc heap a doubly-linked list
eal: add function to dump malloc heap contents
test: add command to dump malloc heap contents
eal: make malloc_elem_join_adjacent_free public
eal: make malloc free list remove public
eal: make malloc free return resulting malloc element
eal: replace panics with error messages in malloc
eal: add backend support for contiguous allocation
eal: enable reserving physically contiguous memzones
ethdev: use contiguous allocation for DMA memory crypto/qat: use contiguous allocation for DMA memory net/avf: use contiguous allocation for DMA memory net/bnx2x: use contiguous allocation for DMA memory net/bnxt: use contiguous allocation for DMA memory net/cxgbe: use contiguous allocation for DMA memory net/ena: use contiguous allocation for DMA memory net/enic: use contiguous allocation for DMA memory net/i40e: use contiguous allocation for DMA memory net/qede: use contiguous allocation for DMA memory net/virtio: use contiguous allocation for DMA memory net/vmxnet3: use contiguous allocation for DMA memory
mempool: add support for the new allocation methods
eal: add function to walk all memsegs
bus/fslmc: use memseg walk instead of iteration bus/pci: use memseg walk instead of iteration net/mlx5: use memseg walk instead of iteration
eal: use memseg walk instead of iteration
mempool: use memseg walk instead of iteration
test: use memseg walk instead of iteration vfio/type1: use memseg walk instead of iteration vfio/spapr: use memseg walk instead of iteration
eal: add contig walk function
virtio: use memseg contig walk instead of iteration
eal: add iova2virt function
bus/dpaa: use iova2virt instead of memseg iteration bus/fslmc: use iova2virt instead of memseg iteration crypto/dpaa_sec: use iova2virt instead of memseg iteration
eal: add virt2memseg function
bus/fslmc: use virt2memseg instead of iteration crypto/dpaa_sec: use virt2memseg instead of iteration net/mlx4: use virt2memseg instead of iteration net/mlx5: use virt2memseg instead of iteration
eal: use memzone walk instead of iteration
vfio: allow to map other memory regions
eal: add "legacy memory" option
eal: add rte_fbarray
eal: replace memseg with memseg lists
eal: replace memzone array with fbarray
eal: add support for mapping hugepages at runtime
eal: add support for unmapping pages at runtime
eal: add "single file segments" command-line option
eal: add API to check if memory is contiguous
eal: prepare memseg lists for multiprocess sync
eal: read hugepage counts from node-specific sysfs path
eal: make use of memory hotplug for init
eal: share hugepage info primary and secondary
eal: add secondary process init with memory hotplug
eal: enable memory hotplug support in rte_malloc
eal: add support for multiprocess memory hotplug
eal: add support for callbacks on memory hotplug
eal: enable callbacks on malloc/free and mp sync
vfio: enable support for mem event callbacks bus/fslmc: move vfio DMA map into bus probe bus/fslmc: enable support for mem event callbacks for vfio
eal: enable non-legacy memory mode
eal: add memory validator callback
eal: enable validation before new page allocation
eal: prevent preallocated pages from being freed
config/common_base | 15 +- config/defconfig_i686-native-linuxapp-gcc | 3 + config/defconfig_i686-native-linuxapp-icc | 3 + config/defconfig_x86_x32-native-linuxapp-gcc | 3 + config/rte_config.h | 7 +- doc/guides/rel_notes/deprecation.rst | 9 - drivers/bus/dpaa/rte_dpaa_bus.h | 12 +- drivers/bus/fslmc/fslmc_bus.c | 11 + drivers/bus/fslmc/fslmc_vfio.c | 194 +++- drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 27 +- drivers/bus/pci/Makefile | 3 + drivers/bus/pci/linux/pci.c | 28 +- drivers/bus/pci/meson.build | 3 + drivers/crypto/dpaa_sec/dpaa_sec.c | 30 +- drivers/crypto/qat/qat_qp.c | 23 +- drivers/event/dpaa2/Makefile | 3 + drivers/mempool/dpaa/Makefile | 3 + drivers/mempool/dpaa/meson.build | 3 + drivers/mempool/dpaa2/Makefile | 3 + drivers/mempool/dpaa2/meson.build | 3 + drivers/net/avf/avf_ethdev.c | 4 +- drivers/net/bnx2x/bnx2x.c | 2 +- drivers/net/bnx2x/bnx2x_rxtx.c | 3 +- drivers/net/bnxt/bnxt_ethdev.c | 17 +- drivers/net/bnxt/bnxt_ring.c | 9 +- drivers/net/bnxt/bnxt_vnic.c | 8 +- drivers/net/cxgbe/sge.c | 3 +- drivers/net/dpaa/Makefile | 3 + drivers/net/dpaa2/Makefile | 3 + drivers/net/dpaa2/dpaa2_ethdev.c | 1 - drivers/net/dpaa2/meson.build | 3 + drivers/net/ena/Makefile | 3 + drivers/net/ena/base/ena_plat_dpdk.h | 9 +- drivers/net/ena/ena_ethdev.c | 10 +- drivers/net/enic/enic_main.c | 9 +- drivers/net/i40e/i40e_ethdev.c | 4 +- drivers/net/i40e/i40e_rxtx.c | 4 +- drivers/net/mlx4/mlx4_mr.c | 17 +- drivers/net/mlx5/Makefile | 3 + drivers/net/mlx5/mlx5.c | 25 +- drivers/net/mlx5/mlx5_mr.c | 18 +- drivers/net/qede/base/bcm_osal.c | 7 +- drivers/net/virtio/virtio_ethdev.c | 8 +- drivers/net/virtio/virtio_user/vhost_kernel.c | 83 +- drivers/net/vmxnet3/vmxnet3_ethdev.c | 5 +- lib/librte_eal/bsdapp/eal/Makefile | 4 + lib/librte_eal/bsdapp/eal/eal.c | 83 +- lib/librte_eal/bsdapp/eal/eal_hugepage_info.c | 65 +- lib/librte_eal/bsdapp/eal/eal_memalloc.c | 48 + lib/librte_eal/bsdapp/eal/eal_memory.c | 222 +++- lib/librte_eal/bsdapp/eal/meson.build | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_fbarray.c | 859 ++++++++++++++++ lib/librte_eal/common/eal_common_memalloc.c | 359 +++++++ lib/librte_eal/common/eal_common_memory.c | 823 ++++++++++++++- lib/librte_eal/common/eal_common_memzone.c | 235 +++-- lib/librte_eal/common/eal_common_options.c | 13 +- lib/librte_eal/common/eal_filesystem.h | 30 + lib/librte_eal/common/eal_hugepages.h | 11 +- lib/librte_eal/common/eal_internal_cfg.h | 12 +- lib/librte_eal/common/eal_memalloc.h | 80 ++ lib/librte_eal/common/eal_options.h | 4 + lib/librte_eal/common/eal_private.h | 33 + lib/librte_eal/common/include/rte_eal_memconfig.h | 28 +- lib/librte_eal/common/include/rte_fbarray.h | 353 +++++++ lib/librte_eal/common/include/rte_malloc.h | 10 + lib/librte_eal/common/include/rte_malloc_heap.h | 6 + lib/librte_eal/common/include/rte_memory.h | 258 ++++- lib/librte_eal/common/include/rte_memzone.h | 12 +- lib/librte_eal/common/include/rte_vfio.h | 39 + lib/librte_eal/common/malloc_elem.c | 433 ++++++-- lib/librte_eal/common/malloc_elem.h | 43 +- lib/librte_eal/common/malloc_heap.c | 704 ++++++++++++- lib/librte_eal/common/malloc_heap.h | 15 +- lib/librte_eal/common/malloc_mp.c | 744 ++++++++++++++ lib/librte_eal/common/malloc_mp.h | 86 ++ lib/librte_eal/common/meson.build | 4 + lib/librte_eal/common/rte_malloc.c | 85 +- lib/librte_eal/linuxapp/eal/Makefile | 5 + lib/librte_eal/linuxapp/eal/eal.c | 62 +- lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 218 +++- lib/librte_eal/linuxapp/eal/eal_memalloc.c | 1124 +++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 1119 ++++++++++++-------- lib/librte_eal/linuxapp/eal/eal_vfio.c | 501 +++++++-- lib/librte_eal/linuxapp/eal/eal_vfio.h | 12 + lib/librte_eal/linuxapp/eal/meson.build | 1 + lib/librte_eal/rte_eal_version.map | 30 +- lib/librte_ether/rte_ethdev.c | 3 +- lib/librte_mempool/Makefile | 3 + lib/librte_mempool/meson.build | 3 + lib/librte_mempool/rte_mempool.c | 150 ++- test/test/commands.c | 3 + test/test/test_malloc.c | 30 +- test/test/test_memory.c | 27 +- test/test/test_memzone.c | 62 +- 95 files changed, 8425 insertions(+), 1279 deletions(-) create mode 100644 lib/librte_eal/bsdapp/eal/eal_memalloc.c create mode 100644 lib/librte_eal/common/eal_common_fbarray.c create mode 100644 lib/librte_eal/common/eal_common_memalloc.c create mode 100644 lib/librte_eal/common/eal_memalloc.h create mode 100644 lib/librte_eal/common/include/rte_fbarray.h create mode 100644 lib/librte_eal/common/malloc_mp.c create mode 100644 lib/librte_eal/common/malloc_mp.h create mode 100644 lib/librte_eal/linuxapp/eal/eal_memalloc.c
Signature · 1 line
2.7.4
PATCH v4 1/70 eal: move get_virtual_area out of linuxapp eal_memory.c
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.
---
Notes:
v3: replace uint64_t with size_t for size variables
lib/librte_eal/common/eal_common_memory.c | 101 ++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 33 +++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 137 ++++++------------------------ 3 files changed, 161 insertions(+), 110 deletions(-)
lib/librte_eal/common/eal_common_memory.c +101 -0
@@ -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,12 +16,111 @@#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 * memory. The last element of the table contains a NULL address.
lib/librte_eal/common/eal_private.h +33 -0
@@ -127,6 +127,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. * * This function is private to the EAL.
lib/librte_eal/linuxapp/eal/eal_memory.c +27 -110
204 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 2/70 eal: move all locking to heap
In reply to Anatoly BurakovDown the line, we will need to do everything from the heap as any alloc or free may trigger alloc/free OS memory, which would involve growing/shrinking heap.
--- lib/librte_eal/common/malloc_elem.c | 16 ++-------------- lib/librte_eal/common/malloc_heap.c | 38 +++++++++++++++++++++++++++++++++++++ lib/librte_eal/common/malloc_heap.h | 6 ++++++ lib/librte_eal/common/rte_malloc.c | 4 ++-- 4 files changed, 48 insertions(+), 16 deletions(-)
lib/librte_eal/common/malloc_elem.c +2 -14
@@ -243,10 +243,6 @@ join_elem(struct malloc_elem *elem1, struct malloc_elem *elem2)int malloc_elem_free (struct malloc_elem *elem) { -if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) -return -1 ; - -rte_spinlock_lock (&(elem->heap->lock));size_t sz = elem->size -sizeof (*elem) -MALLOC_ELEM_TRAILER_LEN ;uint8_t *ptr = (uint8_t *)&elem[1 ];struct malloc_elem *next =RTE_PTR_ADD (elem, elem->size);
@@ -274,8 +270,6 @@ malloc_elem_free(struct malloc_elem *elem)memset (ptr,0 , sz); -rte_spinlock_unlock (&(elem->heap->lock)); -return 0 ; }
@@ -292,11 +286,10 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)return 0 ;struct malloc_elem *next =RTE_PTR_ADD (elem, elem->size); -rte_spinlock_lock (&elem->heap->lock);if (next ->state !=ELEM_FREE ) - goto err_return; +return -1 ;if (elem->size + next->size < new_size) - goto err_return; +return -1 ;/* we now know the element fits, so remove from free list, * join the two
@@ -311,10 +304,5 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)split_elem (elem, split_pt);malloc_elem_free_list_insert (split_pt); } -rte_spinlock_unlock (&elem->heap->lock);return 0 ; - -err_return: -rte_spinlock_unlock (&elem->heap->lock); -return -1 ; }
lib/librte_eal/common/malloc_heap.c +38 -0
@@ -145,6 +145,44 @@ malloc_heap_alloc(struct malloc_heap *heap,return elem ==NULL ?NULL : (void *)(&elem[1 ]); } +int +malloc_heap_free (struct malloc_elem *elem) +{ +struct malloc_heap *heap; +int ret; + +if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) +return -1 ; + +/* elem may be merged with previous element, so keep heap address */ + heap = elem->heap; + +rte_spinlock_lock (&(heap->lock)); + + ret =malloc_elem_free (elem); + +rte_spinlock_unlock (&(heap->lock)); + +return ret; +} + +int +malloc_heap_resize (struct malloc_elem *elem,size_t size) +{ +int ret; + +if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) +return -1 ; + +rte_spinlock_lock (&(elem->heap->lock)); + + ret =malloc_elem_resize (elem, size); + +rte_spinlock_unlock (&(elem->heap->lock)); + +return ret; +} +/* * Function to retrieve data for heap on given socket */
lib/librte_eal/common/malloc_heap.h +6 -0
@@ -28,6 +28,12 @@ malloc_heap_alloc(struct malloc_heap *heap, const char *type, size_t size, unsigned flags, size_t align, size_t bound);int +malloc_heap_free (struct malloc_elem *elem); + +int +malloc_heap_resize (struct malloc_elem *elem,size_t size); + +int malloc_heap_get_stats (struct malloc_heap *heap,struct rte_malloc_socket_stats *socket_stats);
lib/librte_eal/common/rte_malloc.c +2 -2
@@ -29,7 +29,7 @@void rte_free (void *addr) {if (addr ==NULL )return ; -if (malloc_elem_free (malloc_elem_from_data (addr)) <0 ) +if (malloc_heap_free (malloc_elem_from_data (addr)) <0 )rte_panic ("Fatal error: Invalid memory\n" ); }
@@ -140,7 +140,7 @@ rte_realloc(void *ptr, size_t size, unsigned align) size =RTE_CACHE_LINE_ROUNDUP (size), align =RTE_CACHE_LINE_ROUNDUP (align);/* check alignment matches first, and if ok, see if we can resize block */ if (RTE_PTR_ALIGN (ptr,align) == ptr && -malloc_elem_resize (elem, size) ==0 ) +malloc_heap_resize (elem, size) ==0 )return ptr;/* either alignment is off, or we have no room to expand,
Signature · 1 line
2.7.4
PATCH v4 3/70 eal: make malloc heap a doubly-linked list
In reply to Anatoly BurakovAs we are preparing for dynamic memory allocation, we need to be able to handle holes in our malloc heap, hence we're switching to doubly linked list, and prepare infrastructure to support it.
Since our heap is now aware where are our first and last elements, there is no longer any need to have a dummy element at the end of each heap, so get rid of that as well. Instead, let insert/remove/ join/split operations handle end-of-list conditions automatically.
---
Notes:
v3:
- Make first/last element pointers volatile
lib/librte_eal/common/include/rte_malloc_heap.h | 6 + lib/librte_eal/common/malloc_elem.c | 200 +++++++++++++++++++----- lib/librte_eal/common/malloc_elem.h | 14 +- lib/librte_eal/common/malloc_heap.c | 8 +- 4 files changed, 179 insertions(+), 49 deletions(-)
lib/librte_eal/common/include/rte_malloc_heap.h +6 -0
@@ -13,12 +13,18 @@/* Number of free lists per heap, grouped by size. */ #define RTE_HEAP_NUM_FREELISTS 13 +/* dummy definition, for pointers */ +struct malloc_elem ; +/** * Structure to hold malloc heap */ struct malloc_heap {rte_spinlock_t lock; LIST_HEAD(, malloc_elem) free_head[RTE_HEAP_NUM_FREELISTS]; +struct malloc_elem *volatile first; +struct malloc_elem *volatile last; +unsigned alloc_count;size_t total_size; } __rte_cache_aligned;
lib/librte_eal/common/malloc_elem.c +164 -36
271 lines not on this page · raw message
lib/librte_eal/common/malloc_elem.h +7 -7
@@ -18,8 +18,12 @@ enum elem_state {struct malloc_elem {struct malloc_heap *heap; -struct malloc_elem *volatile prev;/* points to prev elem in memseg */ -LIST_ENTRY (malloc_elem) free_list;/* list of free elements in heap */ +struct malloc_elem *volatile prev; +/**< points to prev elem in memseg */ +struct malloc_elem *volatile next; +/**< points to next elem in memseg */ +LIST_ENTRY (malloc_elem) free_list; +/**< list of free elements in heap */ const struct rte_memseg *ms;volatile enum elem_state state;uint32_t pad;
@@ -110,12 +114,8 @@ malloc_elem_init(struct malloc_elem *elem,const struct rte_memseg *ms, size_t size); -/* -* initialise a dummy malloc_elem header for the end-of-memseg marker -*/ void -malloc_elem_mkend (struct malloc_elem *elem, -struct malloc_elem *prev_free); +malloc_elem_insert (struct malloc_elem *elem);/* * return true if the current malloc_elem can hold a block of data
lib/librte_eal/common/malloc_heap.c +2 -6
@@ -70,15 +70,11 @@ check_hugepage_sz(unsigned flags, uint64_t hugepage_sz)static void malloc_heap_add_memseg (struct malloc_heap *heap,struct rte_memseg *ms) { -/* allocate the memory block headers, one at end, one at start */ struct malloc_elem *start_elem = (struct malloc_elem *)ms->addr; -struct malloc_elem *end_elem =RTE_PTR_ADD (ms->addr, - ms->len -MALLOC_ELEM_OVERHEAD ); - end_elem =RTE_PTR_ALIGN_FLOOR (end_elem,RTE_CACHE_LINE_SIZE ); -const size_t elem_size = (uintptr_t )end_elem - (uintptr_t )start_elem; +const size_t elem_size = ms->len -MALLOC_ELEM_OVERHEAD ;malloc_elem_init (start_elem, heap, ms, elem_size); -malloc_elem_mkend (end_elem, start_elem); +malloc_elem_insert (start_elem);malloc_elem_free_list_insert (start_elem); heap->total_size += elem_size;
Signature · 1 line
2.7.4
PATCH v4 4/70 eal: add function to dump malloc heap contents
In reply to Anatoly BurakovMalloc heap is now a doubly linked list, so it's now possible to iterate over each malloc element regardless of its state.
---
Notes:
v3: mark function as experimental
lib/librte_eal/common/include/rte_malloc.h | 10 ++++++++++ lib/librte_eal/common/malloc_elem.c | 24 ++++++++++++++++++++++++ lib/librte_eal/common/malloc_elem.h | 6 ++++++ lib/librte_eal/common/malloc_heap.c | 22 ++++++++++++++++++++++ lib/librte_eal/common/malloc_heap.h | 3 +++ lib/librte_eal/common/rte_malloc.c | 17 +++++++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 7 files changed, 83 insertions(+)
lib/librte_eal/common/include/rte_malloc.h +10 -0
@@ -13,6 +13,7 @@#include <stdio.h> #include <stddef.h> +#include <rte_compat.h> #include <rte_memory.h> #ifdef __cplusplus
@@ -278,6 +279,15 @@ void rte_malloc_dump_stats(FILE *f, const char *type);/** +* Dump contents of all malloc heaps to a file. +* +* @param f +* A pointer to a file for output +*/ +void __rte_experimental +rte_malloc_dump_heaps (FILE *f); + +/** * Set the maximum amount of allocated memory for this type. * * This is not yet implemented
lib/librte_eal/common/malloc_elem.c +24 -0
@@ -1,6 +1,7 @@/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2014 Intel Corporation */ +#include <inttypes.h> #include <stdint.h> #include <stddef.h> #include <stdio.h>
@@ -434,3 +435,26 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size) }return 0 ; } + +static inline const char * +elem_state_to_str (enum elem_state state) +{ +switch (state) { +case ELEM_PAD : +return "PAD" ; +case ELEM_BUSY : +return "BUSY" ; +case ELEM_FREE : +return "FREE" ; + } +return "ERROR" ; +} + +void +malloc_elem_dump (const struct malloc_elem *elem,FILE *f) +{ +fprintf (f,"Malloc element at %p (%s)\n" , elem, +elem_state_to_str (elem->state)); +fprintf (f," len: 0x%zx pad: 0x%" PRIx32"\n" , elem->size, elem->pad); +fprintf (f," prev: %p next: %p\n" , elem->prev, elem->next); +}
lib/librte_eal/common/malloc_elem.h +6 -0
@@ -149,6 +149,12 @@ int malloc_elem_resize(struct malloc_elem *elem, size_t size);/* +* dump contents of malloc elem to a file. +*/ +void +malloc_elem_dump (const struct malloc_elem *elem,FILE *f); + +/* * Given an element size, compute its freelist index. */ size_t
lib/librte_eal/common/malloc_heap.c +22 -0
@@ -217,6 +217,28 @@ malloc_heap_get_stats(struct malloc_heap *heap,return 0 ; } +/* +* Function to retrieve data for heap on given socket +*/ +void +malloc_heap_dump (struct malloc_heap *heap,FILE *f) +{ +struct malloc_elem *elem; + +rte_spinlock_lock (&heap->lock); + +fprintf (f,"Heap size: 0x%zx\n" , heap->total_size); +fprintf (f,"Heap alloc count: %u\n" , heap->alloc_count); + + elem = heap->first; +while (elem) { +malloc_elem_dump (elem, f); + elem = elem->next; + } + +rte_spinlock_unlock (&heap->lock); +} +int rte_eal_malloc_heap_init (void ) {
lib/librte_eal/common/malloc_heap.h +3 -0
@@ -37,6 +37,9 @@ int malloc_heap_get_stats(struct malloc_heap *heap, struct rte_malloc_socket_stats *socket_stats); +void +malloc_heap_dump (struct malloc_heap *heap,FILE *f); +int rte_eal_malloc_heap_init (void );
lib/librte_eal/common/rte_malloc.c +17 -0
@@ -182,6 +182,23 @@ rte_malloc_get_socket_stats(int socket, }/* +* Function to dump contents of all heaps +*/ +void __rte_experimental +rte_malloc_dump_heaps (FILE *f) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +unsigned int idx; + +for (idx =0 ; idx <rte_socket_count (); idx++) { +unsigned int socket =rte_socket_id_by_idx (idx); +fprintf (f,"Heap on socket %i:\n" , socket); +malloc_heap_dump (&mcfg->malloc_heaps[socket], f); + } + +} + +/* * Print stats on memory type. If type is NULL, info on all types is printed */ void
lib/librte_eal/rte_eal_version.map +1 -0
@@ -222,6 +222,7 @@ EXPERIMENTAL { rte_eal_hotplug_remove; rte_eal_mbuf_user_pool_ops; rte_log_register_type_and_pick_level; + rte_malloc_dump_heaps; rte_mp_action_register; rte_mp_action_unregister; rte_mp_reply;
Signature · 1 line
2.7.4
PATCH v4 5/70 test: add command to dump malloc heap contents
In reply to Anatoly Burakov--- test/test/commands.c | 3 +++ 1 file changed, 3 insertions(+)
test/test/commands.c +3 -0
@@ -137,6 +137,8 @@ static void cmd_dump_parsed(void *parsed_result,rte_log_dump (stdout); else if (!strcmp(res->dump, "dump_malloc_stats"))rte_malloc_dump_stats (stdout,NULL ); + else if (!strcmp(res->dump, "dump_malloc_heaps")) +rte_malloc_dump_heaps (stdout); } cmdline_parse_token_string_t cmd_dump_dump =
@@ -147,6 +149,7 @@ cmdline_parse_token_string_t cmd_dump_dump ="dump_ring#" "dump_mempool#" "dump_malloc_stats#" +"dump_malloc_heaps#" "dump_devargs#" "dump_log_types");
Signature · 1 line
2.7.4
PATCH v4 6/70 eal: make malloc_elem_join_adjacent_free public
In reply to Anatoly BurakovDown the line, we will need to join free segments to determine whether the resulting contiguous free space is bigger than a page size, allowing to free some memory back to the system.
--- lib/librte_eal/common/malloc_elem.c | 6 +++--- lib/librte_eal/common/malloc_elem.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-)
lib/librte_eal/common/malloc_elem.c +3 -3
@@ -325,8 +325,8 @@ join_elem(struct malloc_elem *elem1, struct malloc_elem *elem2) elem1->next = next; } -static struct malloc_elem * -elem_join_adjacent_free (struct malloc_elem *elem) +struct malloc_elem * +malloc_elem_join_adjacent_free (struct malloc_elem *elem) {/* * check if next element exists, is adjacent and is free, if so join
@@ -388,7 +388,7 @@ malloc_elem_free(struct malloc_elem *elem) ptr =RTE_PTR_ADD (elem,sizeof (*elem)); data_len = elem->size -MALLOC_ELEM_OVERHEAD ; - elem =elem_join_adjacent_free (elem); + elem =malloc_elem_join_adjacent_free (elem);malloc_elem_free_list_insert (elem);
lib/librte_eal/common/malloc_elem.h +3 -0
@@ -141,6 +141,9 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size,int malloc_elem_free (struct malloc_elem *elem); +struct malloc_elem * +malloc_elem_join_adjacent_free (struct malloc_elem *elem); +/* * attempt to resize a malloc_elem by expanding into any free space * immediately after it in memory.
Signature · 1 line
2.7.4
PATCH v4 7/70 eal: make malloc free list remove public
In reply to Anatoly BurakovWe will need to be able to remove entries from free lists from heaps during certain events, such as rollbacks, or when freeing memory to the system (where a previously element disappears and thus can no longer be in the free list).
--- lib/librte_eal/common/malloc_elem.c | 12 ++++++------ lib/librte_eal/common/malloc_elem.h | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-)
lib/librte_eal/common/malloc_elem.c +6 -6
@@ -245,8 +245,8 @@ malloc_elem_free_list_insert(struct malloc_elem *elem)/* * Remove the specified element from its heap's free list. */ -static void -elem_free_list_remove (struct malloc_elem *elem) +void +malloc_elem_free_list_remove (struct malloc_elem *elem) {LIST_REMOVE (elem, free_list); }
@@ -266,7 +266,7 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align,const size_t trailer_size = elem->size - old_elem_size - size -MALLOC_ELEM_OVERHEAD ; -elem_free_list_remove (elem); +malloc_elem_free_list_remove (elem);if (trailer_size >MALLOC_ELEM_OVERHEAD +MIN_DATA_SIZE ) {/* split it, too much free space after elem */
@@ -340,7 +340,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase =RTE_PTR_SUB (elem->next,MALLOC_ELEM_TRAILER_LEN );/* remove from free list, join to this one */ -elem_free_list_remove (elem->next); +malloc_elem_free_list_remove (elem->next);join_elem (elem, elem->next);/* erase header and trailer */
@@ -360,7 +360,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase =RTE_PTR_SUB (elem,MALLOC_ELEM_TRAILER_LEN );/* remove from free list, join to this one */ -elem_free_list_remove (elem->prev); +malloc_elem_free_list_remove (elem->prev); new_elem = elem->prev;join_elem (new_elem, elem);
@@ -423,7 +423,7 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)/* we now know the element fits, so remove from free list, * join the two */ -elem_free_list_remove (elem->next); +malloc_elem_free_list_remove (elem->next);join_elem (elem, elem->next);if (elem->size - new_size >=MIN_DATA_SIZE +MALLOC_ELEM_OVERHEAD ) {
lib/librte_eal/common/malloc_elem.h +3 -0
@@ -151,6 +151,9 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem);int malloc_elem_resize (struct malloc_elem *elem,size_t size); +void +malloc_elem_free_list_remove (struct malloc_elem *elem); +/* * dump contents of malloc elem to a file. */
Signature · 1 line
2.7.4
PATCH v4 8/70 eal: make malloc free return resulting malloc element
In reply to Anatoly BurakovThis will be needed because we need to know how big is the new empty space, to check whether we can free some pages as a result.
---
Notes:
v3: clarified commit message
lib/librte_eal/common/malloc_elem.c | 4 ++-- lib/librte_eal/common/malloc_elem.h | 2 +- lib/librte_eal/common/malloc_heap.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-)
lib/librte_eal/common/malloc_elem.c +2 -2
@@ -379,7 +379,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem)* blocks either immediately before or immediately after newly freed block * are also free, the blocks are merged together. */ -int +struct malloc_elem *malloc_elem_free (struct malloc_elem *elem) {void *ptr;
@@ -397,7 +397,7 @@ malloc_elem_free(struct malloc_elem *elem)memset (ptr,0 , data_len); -return 0 ; +return elem; }/*
lib/librte_eal/common/malloc_elem.h +1 -1
@@ -138,7 +138,7 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size,* blocks either immediately before or immediately after newly freed block * are also free, the blocks are merged together. */ -int +struct malloc_elem *malloc_elem_free (struct malloc_elem *elem); struct malloc_elem *
lib/librte_eal/common/malloc_heap.c +2 -2
@@ -145,7 +145,7 @@ int malloc_heap_free(struct malloc_elem *elem) {struct malloc_heap *heap; -int ret; +struct malloc_elem *ret;if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY )return -1 ;
@@ -159,7 +159,7 @@ malloc_heap_free(struct malloc_elem *elem)rte_spinlock_unlock (&(heap->lock)); -return ret; +return ret !=NULL ?0 :-1 ; }int
Signature · 1 line
2.7.4
PATCH v4 9/70 eal: replace panics with error messages in malloc
In reply to Anatoly BurakovWe shouldn't ever panic in system libraries, let alone in such core ones as EAL, so replace all panic messages with error messages.
--- lib/librte_eal/common/rte_malloc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
lib/librte_eal/common/rte_malloc.c +5 -3
@@ -30,7 +30,7 @@ void rte_free(void *addr) {if (addr ==NULL )return ;if (malloc_heap_free (malloc_elem_from_data (addr)) <0 ) -rte_panic ("Fatal error: Invalid memory\n" ); +RTE_LOG (ERR ,EAL ,"Error: Invalid memory\n" ); }/*
@@ -134,8 +134,10 @@ rte_realloc(void *ptr, size_t size, unsigned align)return rte_malloc (NULL , size, align);struct malloc_elem *elem =malloc_elem_from_data (ptr); -if (elem ==NULL ) -rte_panic ("Fatal error: memory corruption detected\n" ); +if (elem ==NULL ) { +RTE_LOG (ERR ,EAL ,"Error: memory corruption detected\n" ); +return NULL ; + } size =RTE_CACHE_LINE_ROUNDUP (size), align =RTE_CACHE_LINE_ROUNDUP (align);/* check alignment matches first, and if ok, see if we can resize block */
Signature · 1 line
2.7.4
PATCH v4 10/70 eal: add backend support for contiguous allocation
In reply to Anatoly BurakovNo major changes, just add some checks in a few key places, and a new parameter to pass around.
Also, add a function to check malloc element for physical contiguousness. For now, assume hugepage memory is always contiguous, while non-hugepage memory will be checked.
---
Notes:
v3:
- Moved this patch earlier
- Added physical contiguousness checking function
lib/librte_eal/common/eal_common_memzone.c | 23 +++--- lib/librte_eal/common/malloc_elem.c | 125 ++++++++++++++++++++++++----- lib/librte_eal/common/malloc_elem.h | 6 +- lib/librte_eal/common/malloc_heap.c | 11 +-- lib/librte_eal/common/malloc_heap.h | 4 +- lib/librte_eal/common/rte_malloc.c | 7 +- 6 files changed, 133 insertions(+), 43 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +13 -10
@@ -98,7 +98,8 @@ find_heap_max_free_elem(int *s, unsigned align)static const struct rte_memzone *memzone_reserve_aligned_thread_unsafe (const char *name,size_t len, -int socket_id,unsigned flags,unsigned align,unsigned bound) +int socket_id,unsigned int flags,unsigned int align, +unsigned int bound,bool contig) {struct rte_memzone *mz;struct rte_mem_config *mcfg;
@@ -188,7 +189,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,/* allocate memory on heap */ void *mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[socket],NULL , - requested_len, flags, align, bound); + requested_len, flags, align, bound, contig);if ((mz_addr ==NULL ) && (socket_id ==SOCKET_ID_ANY )) {/* try other heaps */
@@ -197,7 +198,8 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,continue ; mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[i], -NULL , requested_len, flags, align, bound); +NULL , requested_len, flags, align, + bound, contig);if (mz_addr !=NULL )break ; }
@@ -235,9 +237,9 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, }static const struct rte_memzone * -rte_memzone_reserve_thread_safe (const char *name,size_t len, -int socket_id,unsigned flags,unsigned align, -unsigned bound) +rte_memzone_reserve_thread_safe (const char *name,size_t len,int socket_id, +unsigned int flags,unsigned int align,unsigned int bound, +bool contig) {struct rte_mem_config *mcfg;const struct rte_memzone *mz =NULL ;
@@ -248,7 +250,7 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len,rte_rwlock_write_lock (&mcfg->mlock); mz =memzone_reserve_aligned_thread_unsafe ( - name, len, socket_id, flags, align, bound); + name, len, socket_id, flags, align, bound, contig);rte_rwlock_write_unlock (&mcfg->mlock);
@@ -265,7 +267,7 @@ rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id, unsigned flags, unsigned align, unsigned bound) { return rte_memzone_reserve_thread_safe(name, len, socket_id, flags, -align ,bound ); +align ,bound ,false ); }/*
@@ -277,7 +279,7 @@ rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id, unsigned flags, unsigned align) {return rte_memzone_reserve_thread_safe (name, len, socket_id, flags, - align,0 ); + align,0 , false); }/*
@@ -289,7 +291,8 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) {return rte_memzone_reserve_thread_safe (name, len, socket_id, - flags,RTE_CACHE_LINE_SIZE ,0 ); + flags,RTE_CACHE_LINE_SIZE ,0 , + false); }int
lib/librte_eal/common/malloc_elem.c +103 -22
160 lines not on this page · raw message
lib/librte_eal/common/malloc_elem.h +4 -2
@@ -5,6 +5,8 @@#ifndef MALLOC_ELEM_H_ #define MALLOC_ELEM_H_ +#include <stdbool.h> +#include <rte_memory.h> /* dummy definition of struct so we can use pointers to it in malloc_elem struct */
@@ -123,7 +125,7 @@ malloc_elem_insert(struct malloc_elem *elem);*/ int malloc_elem_can_hold (struct malloc_elem *elem,size_t size, -unsigned align,size_t bound); +unsigned int align,size_t bound,bool contig);/* * reserve a block of data in an existing malloc_elem. If the malloc_elem
@@ -131,7 +133,7 @@ malloc_elem_can_hold(struct malloc_elem *elem, size_t size,*/ struct malloc_elem *malloc_elem_alloc (struct malloc_elem *elem,size_t size, -unsigned align,size_t bound); +unsigned int align,size_t bound,bool contig);/* * free a malloc_elem block by adding it to the free list. If the
lib/librte_eal/common/malloc_heap.c +6 -5
@@ -88,7 +88,7 @@ malloc_heap_add_memseg(struct malloc_heap *heap, struct rte_memseg *ms)*/ static struct malloc_elem *find_suitable_element (struct malloc_heap *heap,size_t size, -unsigned flags,size_t align,size_t bound) +unsigned int flags,size_t align,size_t bound,bool contig) {size_t idx;struct malloc_elem *elem, *alt_elem =NULL ;
@@ -97,7 +97,8 @@ find_suitable_element(struct malloc_heap *heap, size_t size, idx < RTE_HEAP_NUM_FREELISTS; idx++) {for (elem =LIST_FIRST (&heap->free_head[idx]); !!elem; elem =LIST_NEXT (elem, free_list)) { -if (malloc_elem_can_hold (elem, size, align, bound)) { +if (malloc_elem_can_hold (elem, size, align, bound, + contig)) {if (check_hugepage_sz (flags, elem->ms->hugepage_sz))return elem;if (alt_elem ==NULL )
@@ -121,7 +122,7 @@ find_suitable_element(struct malloc_heap *heap, size_t size,void *malloc_heap_alloc (struct malloc_heap *heap,const char *type __attribute__((unused)),size_t size,unsigned flags, -size_t align,size_t bound) +size_t align,size_t bound,bool contig) {struct malloc_elem *elem;
@@ -130,9 +131,9 @@ malloc_heap_alloc(struct malloc_heap *heap,rte_spinlock_lock (&heap->lock); - elem =find_suitable_element (heap, size, flags, align, bound); + elem =find_suitable_element (heap, size, flags, align, bound, contig);if (elem !=NULL ) { - elem =malloc_elem_alloc (elem, size, align, bound); + elem =malloc_elem_alloc (elem, size, align, bound, contig);/* increase heap's count of allocated elements */ heap->alloc_count++; }
lib/librte_eal/common/malloc_heap.h +3 -1
@@ -5,6 +5,8 @@#ifndef MALLOC_HEAP_H_ #define MALLOC_HEAP_H_ +#include <stdbool.h> +#include <rte_malloc.h> #include <rte_malloc_heap.h>
@@ -25,7 +27,7 @@ malloc_get_numa_socket(void)void *malloc_heap_alloc (struct malloc_heap *heap,const char *type,size_t size, -unsigned flags,size_t align,size_t bound); +unsigned int flags,size_t align,size_t bound,bool contig);int malloc_heap_free (struct malloc_elem *elem);
lib/librte_eal/common/rte_malloc.c +4 -3
@@ -37,7 +37,8 @@ void rte_free(void *addr)* Allocate memory on specified heap. */ void * -rte_malloc_socket (const char *type,size_t size,unsigned align,int socket_arg) +rte_malloc_socket (const char *type,size_t size,unsigned int align, +int socket_arg) {struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config;int socket, i;
@@ -60,7 +61,7 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket_arg)return NULL ; ret =malloc_heap_alloc (&mcfg->malloc_heaps[socket], type, - size,0 , align ==0 ?1 : align,0 ); + size,0 , align ==0 ?1 : align,0 , false);if (ret !=NULL || socket_arg !=SOCKET_ID_ANY )return ret;
@@ -71,7 +72,7 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket_arg)continue ; ret =malloc_heap_alloc (&mcfg->malloc_heaps[i], type, - size,0 , align ==0 ?1 : align,0 ); + size,0 , align ==0 ?1 : align,0 , false);if (ret !=NULL )return ret; }
Signature · 1 line
2.7.4
PATCH v4 11/70 eal: enable reserving physically contiguous memzones
In reply to Anatoly BurakovThis adds a new flag to request reserved memzone to be IOVA contiguous. This is useful for allocating hardware resources like NIC rings/queues etc.For now, hugepage memory is always contiguous, but we need to prepare the drivers for the switch.
---
Notes:
v4:
- Replaced a new API with a memzone flag
v3:
- Moved this patch earlier
v3:
- Moved this patch earlier
lib/librte_eal/common/eal_common_memzone.c | 25 +++++++++++++++++-------- lib/librte_eal/common/include/rte_memzone.h | 11 +++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +17 -8
@@ -99,12 +99,13 @@ find_heap_max_free_elem(int *s, unsigned align)static const struct rte_memzone *memzone_reserve_aligned_thread_unsafe (const char *name,size_t len,int socket_id,unsigned int flags,unsigned int align, -unsigned int bound,bool contig) +unsigned int bound) {struct rte_memzone *mz;struct rte_mem_config *mcfg;size_t requested_len;int socket, i; +bool contig;/* get pointer to global configuration */ mcfg =rte_eal_get_configuration ()->mem_config;
@@ -170,7 +171,17 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,if (!rte_eal_has_hugepages ()) socket_id =SOCKET_ID_ANY ; + contig = (flags &RTE_MEMZONE_IOVA_CONTIG ) !=0 ; +/* malloc only cares about size flags, remove contig flag from flags */ + flags &= ~RTE_MEMZONE_IOVA_CONTIG ; +if (len ==0 ) { +/* len == 0 is only allowed for non-contiguous zones */ +if (contig) { +RTE_LOG (DEBUG ,EAL ,"Reserving zero-length contiguous memzones is not supported\n" ); + rte_errno =EINVAL ; +return NULL ; + }if (bound !=0 ) requested_len = bound;else {
@@ -238,8 +249,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,static const struct rte_memzone *rte_memzone_reserve_thread_safe (const char *name,size_t len,int socket_id, -unsigned int flags,unsigned int align,unsigned int bound, -bool contig) +unsigned int flags,unsigned int align,unsigned int bound) {struct rte_mem_config *mcfg;const struct rte_memzone *mz =NULL ;
@@ -250,7 +260,7 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len, int socket_id,rte_rwlock_write_lock (&mcfg->mlock); mz =memzone_reserve_aligned_thread_unsafe ( - name, len, socket_id, flags, align, bound, contig); + name, len, socket_id, flags, align, bound);rte_rwlock_write_unlock (&mcfg->mlock);
@@ -267,7 +277,7 @@ rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id, unsigned flags, unsigned align, unsigned bound) { return rte_memzone_reserve_thread_safe(name, len, socket_id, flags, -align ,bound ,false ); +align ,bound ); }/*
@@ -279,7 +289,7 @@ rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id, unsigned flags, unsigned align) {return rte_memzone_reserve_thread_safe (name, len, socket_id, flags, - align,0 , false); + align,0 ); }/*
@@ -291,8 +301,7 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) {return rte_memzone_reserve_thread_safe (name, len, socket_id, - flags,RTE_CACHE_LINE_SIZE ,0 , - false); + flags,RTE_CACHE_LINE_SIZE ,0 ); }int
lib/librte_eal/common/include/rte_memzone.h +11 -0
@@ -23,6 +23,7 @@*/ #include <stdio.h> +#include <rte_compat.h> #include <rte_memory.h> #include <rte_common.h>
@@ -39,6 +40,7 @@ extern "C" {#define RTE_MEMZONE_512MB 0x00040000/**< Use 512MB pages. */ #define RTE_MEMZONE_4GB 0x00080000/**< Use 4GB pages. */ #define RTE_MEMZONE_SIZE_HINT_ONLY 0x00000004/**< Use available page size */ +#define RTE_MEMZONE_IOVA_CONTIG 0x00100000/**< Ask for IOVA-contiguous memzone. */ /** * A structure describing a memzone, which is a contiguous portion of
@@ -102,6 +104,9 @@ struct rte_memzone {* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @return * A pointer to a correctly-filled read-only memzone descriptor, or NULL * on error.
@@ -152,6 +157,9 @@ const struct rte_memzone *rte_memzone_reserve(const char *name,* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @param align * Alignment for resulting memzone. Must be a power of 2. * @return
@@ -207,6 +215,9 @@ const struct rte_memzone *rte_memzone_reserve_aligned(const char *name,* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @param align * Alignment for resulting memzone. Must be a power of 2. * @param bound
Signature · 1 line
2.7.4
PATCH v4 12/70 ethdev: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
This fixes the following drivers in one go:
grep -Rl rte_eth_dma_zone_reserve drivers/
drivers/net/avf/avf_rxtx.cdrivers/net/thunderx/nicvf_ethdev.cdrivers/net/e1000/igb_rxtx.cdrivers/net/e1000/em_rxtx.cdrivers/net/fm10k/fm10k_ethdev.cdrivers/net/vmxnet3/vmxnet3_rxtx.cdrivers/net/liquidio/lio_rxtx.cdrivers/net/i40e/i40e_rxtx.cdrivers/net/sfc/sfc.cdrivers/net/ixgbe/ixgbe_rxtx.cdrivers/net/nfp/nfp_net.c
---
Notes:
v4: replaced use of new API with additional memzone flag
v3: moved this patch earlier in the patchset
lib/librte_ether/rte_ethdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
@@ -3403,7 +3403,8 @@ rte_eth_dma_zone_reserve(const struct rte_eth_dev *dev, const char *ring_name,if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, size, socket_id,0 , align); +return rte_memzone_reserve_aligned (z_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align); }int
Signature · 1 line
2.7.4
PATCH v4 13/70 crypto/qat: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
Also, remove the weird page alignment code.
---
Notes:
v4:
- Replace new API with new memzone flag
v3:
- Move the patch earlier in the patchset
- Fix build system files to allow experimental API's
- Removed non-sensical memzone flags code
v3:
- Move the patch earlier in the patchset
- Fix build system files to allow experimental API's
- Removed non-sensical memzone flags code
drivers/crypto/qat/qat_qp.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-)
drivers/crypto/qat/qat_qp.c +2 -21
@@ -54,8 +54,6 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size, int socket_id) {const struct rte_memzone *mz; -unsigned memzone_flags =0 ; -const struct rte_memseg *ms;PMD_INIT_FUNC_TRACE (); mz =rte_memzone_lookup (queue_name);
@@ -78,25 +76,8 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size,PMD_DRV_LOG (DEBUG ,"Allocate memzone for %s, size %u on socket %u" , queue_name, queue_size, socket_id); - ms =rte_eal_get_physmem_layout (); -switch (ms[0 ].hugepage_sz) { -case (RTE_PGSIZE_2M ): - memzone_flags =RTE_MEMZONE_2MB ; -break ; -case (RTE_PGSIZE_1G ): - memzone_flags =RTE_MEMZONE_1GB ; -break ; -case (RTE_PGSIZE_16M ): - memzone_flags =RTE_MEMZONE_16MB ; -break ; -case (RTE_PGSIZE_16G ): - memzone_flags =RTE_MEMZONE_16GB ; -break ; -default : - memzone_flags =RTE_MEMZONE_SIZE_HINT_ONLY ; - } -return rte_memzone_reserve_aligned (queue_name, queue_size, socket_id, - memzone_flags, queue_size); +return rte_memzone_reserve_aligned (queue_name, queue_size, + socket_id,RTE_MEMZONE_IOVA_CONTIG , queue_size); } int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
Signature · 1 line
2.7.4
PATCH v4 14/70 net/avf: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile
drivers/net/avf/avf_ethdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/avf/avf_ethdev.c +2 -2
@@ -1365,8 +1365,8 @@ avf_allocate_dma_mem_d(__rte_unused struct avf_hw *hw,return AVF_ERR_PARAM ;snprintf (z_name,sizeof (z_name),"avf_dma_%" PRIu64,rte_rand ()); - mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY ,0 , - alignment,RTE_PGSIZE_2M ); + mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG , alignment,RTE_PGSIZE_2M );if (!mz)return AVF_ERR_NO_MEMORY ;
Signature · 1 line
2.7.4
PATCH v4 15/70 net/bnx2x: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile
drivers/net/bnx2x/bnx2x.c | 2 +- drivers/net/bnx2x/bnx2x_rxtx.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
drivers/net/bnx2x/bnx2x.c +1 -1
@@ -177,7 +177,7 @@ bnx2x_dma_alloc(struct bnx2x_softc *sc, size_t size, struct bnx2x_dma *dma, rte_get_timer_cycles());/* Caller must take care that strlen(mz_name) < RTE_MEMZONE_NAMESIZE */ - z =rte_memzone_reserve_aligned (mz_name, (uint64_t ) (size), + z =rte_memzone_reserve_aligned_contig (mz_name, (uint64_t )size,SOCKET_ID_ANY ,0 , align);if (z ==NULL ) {
drivers/net/bnx2x/bnx2x_rxtx.c +2 -1
@@ -26,7 +26,8 @@ ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, ring_size, socket_id,0 ,BNX2X_PAGE_SIZE ); +return rte_memzone_reserve_aligned (z_name, ring_size, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,BNX2X_PAGE_SIZE ); } static void
Signature · 1 line
2.7.4
PATCH v4 16/70 net/bnxt: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Added this driver to the list of modified drivers
- Add experimental API to build files
v3:
- Added this patch
All memzone reserve calls then check physical addresses, so this looks like they're reserving DMA memory. Corrections welcome.
drivers/net/bnxt/bnxt_ethdev.c | 17 ++++++++++------- drivers/net/bnxt/bnxt_ring.c | 9 +++++---- drivers/net/bnxt/bnxt_vnic.c | 8 ++++---- 3 files changed, 19 insertions(+), 15 deletions(-)
drivers/net/bnxt/bnxt_ethdev.c +10 -7
@@ -3147,9 +3147,10 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev) sizeof(struct rx_port_stats) + 512);if (!mz) { mz =rte_memzone_reserve (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (mz ==NULL )return -ENOMEM ; }
@@ -3181,10 +3182,12 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev) total_alloc_len =RTE_CACHE_LINE_ROUNDUP (sizeof (struct tx_port_stats ) +512 );if (!mz) { - mz =rte_memzone_reserve (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); + mz =rte_memzone_reserve (mz_name, + total_alloc_len, +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (mz ==NULL )return -ENOMEM ; }
drivers/net/bnxt/bnxt_ring.c +5 -4
@@ -166,10 +166,11 @@ int bnxt_alloc_rings(struct bnxt *bp, uint16_t qidx, mz =rte_memzone_lookup (mz_name);if (!mz) { mz =rte_memzone_reserve_aligned (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY , -getpagesize ()); +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG , +getpagesize ());if (mz ==NULL )return -ENOMEM ; }
drivers/net/bnxt/bnxt_vnic.c +4 -4
@@ -185,10 +185,10 @@ int bnxt_alloc_vnic_attributes(struct bnxt *bp) mz =rte_memzone_lookup (mz_name);if (!mz) { mz =rte_memzone_reserve (mz_name, - entry_length * max_vnics, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); + entry_length * max_vnics,SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (!mz)return -ENOMEM ; }
Signature · 1 line
2.7.4
PATCH v4 17/70 net/cxgbe: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile
drivers/net/cxgbe/sge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/cxgbe/sge.c +2 -1
@@ -1344,7 +1344,8 @@ static void *alloc_ring(size_t nelem, size_t elem_size,* handle the maximum ring size is allocated in order to allow for * resizing in later calls to the queue setup function. */ - tz =rte_memzone_reserve_aligned (z_name, len, socket_id,0 ,4096 ); + tz =rte_memzone_reserve_aligned (z_name, len, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,4096 );if (!tz)return NULL ;
Signature · 1 line
2.7.4
PATCH v4 18/70 net/ena: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the Makefile
drivers/net/ena/base/ena_plat_dpdk.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/ena/base/ena_plat_dpdk.h +6 -3
@@ -188,7 +188,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (handle); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size,SOCKET_ID_ANY ,0 ); \ + mz =rte_memzone_reserve (z_name, size,SOCKET_ID_ANY , \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ phys = mz->iova; \
@@ -206,7 +207,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (dev_node); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size, node,0 ); \ + mz =rte_memzone_reserve (z_name, size, node, \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ phys = mz->iova; \
@@ -219,7 +221,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (dev_node); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size, node,0 ); \ + mz =rte_memzone_reserve (z_name, size, node, \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ }while (0 )
Signature · 1 line
2.7.4
PATCH v4 19/70 net/enic: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in Makefile
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in the build system
drivers/net/enic/enic_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/enic/enic_main.c +4 -5
@@ -343,8 +343,8 @@ enic_alloc_consistent(void *priv, size_t size,struct enic *enic = (struct enic *)priv;struct enic_memzone_entry *mze; - rz =rte_memzone_reserve_aligned ((const char *)name, - size,SOCKET_ID_ANY ,0 ,ENIC_ALIGN ); + rz =rte_memzone_reserve_aligned ((const char *)name, size, +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG ,ENIC_ALIGN );if (!rz) {pr_err ("%s : Failed to allocate memory requested for %s\n" , __func__, name);
@@ -888,9 +888,8 @@ int enic_alloc_wq(struct enic *enic, uint16_t queue_idx, instance++); wq->cqmsg_rz =rte_memzone_reserve_aligned ((const char *)name, -sizeof (uint32_t ), -SOCKET_ID_ANY ,0 , -ENIC_ALIGN ); +sizeof (uint32_t ),SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG ,ENIC_ALIGN );if (!wq->cqmsg_rz)return -ENOMEM ;
Signature · 1 line
2.7.4
PATCH v4 20/70 net/i40e: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in the build system
drivers/net/i40e/i40e_ethdev.c | 4 ++-- drivers/net/i40e/i40e_rxtx.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/net/i40e/i40e_ethdev.c +2 -2
@@ -4053,8 +4053,8 @@ i40e_allocate_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,return I40E_ERR_PARAM ;snprintf (z_name,sizeof (z_name),"i40e_dma_%" PRIu64,rte_rand ()); - mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY ,0 , - alignment,RTE_PGSIZE_2M ); + mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG , alignment,RTE_PGSIZE_2M );if (!mz)return I40E_ERR_NO_MEMORY ;
drivers/net/i40e/i40e_rxtx.c +2 -2
@@ -2189,8 +2189,8 @@ i40e_memzone_reserve(const char *name, uint32_t len, int socket_id)if (mz)return mz; - mz =rte_memzone_reserve_aligned (name, len, - socket_id,0 ,I40E_RING_BASE_ALIGN ); + mz =rte_memzone_reserve_aligned (name, len, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,I40E_RING_BASE_ALIGN );return mz; }
Signature · 1 line
2.7.4
PATCH v4 21/70 net/qede: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved the patch earlier in the patchset
- Allowed experimental API in Makefile
drivers/net/qede/base/bcm_osal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/qede/base/bcm_osal.c +4 -3
@@ -135,8 +135,8 @@ void *osal_dma_alloc_coherent(struct ecore_dev *p_dev,if (core_id == (unsigned int )LCORE_ID_ANY ) core_id =rte_get_master_lcore (); socket_id =rte_lcore_to_socket_id (core_id); - mz =rte_memzone_reserve_aligned (mz_name, size, - socket_id,0 ,RTE_CACHE_LINE_SIZE ); + mz =rte_memzone_reserve_aligned (mz_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,RTE_CACHE_LINE_SIZE );if (!mz) { DP_ERR(p_dev, "Unable to allocate DMA memory " "of size %zu bytes - %s\n",
@@ -174,7 +174,8 @@ void *osal_dma_alloc_coherent_aligned(struct ecore_dev *p_dev,if (core_id == (unsigned int )LCORE_ID_ANY ) core_id =rte_get_master_lcore (); socket_id =rte_lcore_to_socket_id (core_id); - mz =rte_memzone_reserve_aligned (mz_name, size, socket_id,0 , align); + mz =rte_memzone_reserve_aligned (mz_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align);if (!mz) { DP_ERR(p_dev, "Unable to allocate DMA memory " "of size %zu bytes - %s\n",
Signature · 1 line
2.7.4
PATCH v4 22/70 net/virtio: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
v3:
- Moved patch earlier in the patchset
drivers/net/virtio/virtio_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/virtio/virtio_ethdev.c +4 -4
@@ -391,8 +391,8 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx) size, vq->vq_ring_size); mz =rte_memzone_reserve_aligned (vq_name, vq->vq_ring_size, -SOCKET_ID_ANY , -0 ,VIRTIO_PCI_VRING_ALIGN ); +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG , +VIRTIO_PCI_VRING_ALIGN );if (mz ==NULL ) {if (rte_errno ==EEXIST ) mz =rte_memzone_lookup (vq_name);
@@ -417,8 +417,8 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)snprintf (vq_hdr_name,sizeof (vq_hdr_name),"port%d_vq%d_hdr" , dev->data->port_id, vtpci_queue_idx); hdr_mz =rte_memzone_reserve_aligned (vq_hdr_name, sz_hdr_mz, -SOCKET_ID_ANY ,0 , -RTE_CACHE_LINE_SIZE ); +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG , +RTE_CACHE_LINE_SIZE );if (hdr_mz ==NULL ) {if (rte_errno ==EEXIST ) hdr_mz =rte_memzone_lookup (vq_hdr_name);
Signature · 1 line
2.7.4
PATCH v4 23/70 net/vmxnet3: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in Makefile
drivers/net/vmxnet3/vmxnet3_ethdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/vmxnet3/vmxnet3_ethdev.c +3 -2
@@ -150,13 +150,14 @@ gpa_zone_reserve(struct rte_eth_dev *dev, uint32_t size,if (mz)rte_memzone_free (mz);return rte_memzone_reserve_aligned (z_name, size, socket_id, -0 , align); +RTE_MEMZONE_IOVA_CONTIG , align); }if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, size, socket_id,0 , align); +return rte_memzone_reserve_aligned (z_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align); }/*
Signature · 1 line
2.7.4
PATCH v4 24/70 mempool: add support for the new allocation methods
In reply to Anatoly BurakovIf a user has specified that the zone should have contiguous memory, use the new _contig allocation API's instead of normal ones. Otherwise, account for the fact that unless we're in IOVA_AS_VA mode, we cannot guarantee that the pages would be physically contiguous, so we calculate the memzone size and alignments as if we were getting the smallest page size available.
However, for the non-IOVA contiguous case, existing mempool size calculation function doesn't give us expected results, because it will return memzone sizes aligned to page size (e.g. a 1MB mempool may use an entire 1GB page), therefore in cases where we weren't specifically asked to reserve non-contiguous memory, first try reserving a memzone as IOVA-contiguous, and if that fails, then try reserving with page-aligned size/alignment.
---
Notes:
v3:
- Fixed mempool size calculation
- Fixed handling of contiguous memzones
- Moved earlier in the patchset
lib/librte_mempool/rte_mempool.c | 149 +++++++++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 22 deletions(-)
lib/librte_mempool/rte_mempool.c +127 -22
@@ -3,6 +3,7 @@* Copyright(c) 2016 6WIND S.A. */ +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <stdint.h>
@@ -98,6 +99,27 @@ static unsigned optimize_object_size(unsigned obj_size)return new_obj_size *RTE_MEMPOOL_ALIGN ; } +static size_t +get_min_page_size (void ) +{ +const struct rte_mem_config *mcfg = +rte_eal_get_configuration ()->mem_config; +int i; +size_t min_pagesz =SIZE_MAX ; + +for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { +const struct rte_memseg *ms = &mcfg->memseg[i]; + +if (ms->addr ==NULL ) +continue ; + +if (ms->hugepage_sz < min_pagesz) + min_pagesz = ms->hugepage_sz; + } + +return min_pagesz ==SIZE_MAX ? (size_t )getpagesize () : min_pagesz; +} +static void mempool_add_elem (struct rte_mempool *mp,void *obj,rte_iova_t iova) {
@@ -204,7 +226,6 @@ rte_mempool_calc_obj_size(uint32_t elt_size, uint32_t flags,return sz->total_size; } -/* * Calculate maximum amount of memory required to store given number of objects. */
@@ -367,16 +388,6 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char *vaddr,/* update mempool capabilities */ mp->flags |= mp_capa_flags; -/* Detect pool area has sufficient space for elements */ -if (mp_capa_flags &MEMPOOL_F_CAPA_PHYS_CONTIG ) { -if (len < total_elt_sz * mp->size) { -RTE_LOG (ERR ,MEMPOOL , -"pool area %" PRIx64" not enough\n" , - (uint64_t )len); -return -ENOSPC ; - } - } - memhdr =rte_zmalloc ("MEMPOOL_MEMHDR" ,sizeof (*memhdr),0 );if (memhdr ==NULL )return -ENOMEM ;
@@ -549,6 +560,7 @@ rte_mempool_populate_default(struct rte_mempool *mp)unsigned mz_id, n;unsigned int mp_flags;int ret; +bool force_contig, no_contig, try_contig, no_pageshift;/* mempool must not be populated */ if (mp->nb_mem_chunks !=0 )
@@ -563,9 +575,68 @@ rte_mempool_populate_default(struct rte_mempool *mp)/* update mempool capabilities */ mp->flags |= mp_flags; -if (rte_eal_has_hugepages ()) { - pg_shift =0 ;/* not needed, zone is physically contiguous */ + no_contig = mp->flags &MEMPOOL_F_NO_PHYS_CONTIG ; + force_contig = mp->flags &MEMPOOL_F_CAPA_PHYS_CONTIG ; + +/* +* the following section calculates page shift and page size values. +* +* these values impact the result of rte_mempool_xmem_size(), which +* returns the amount of memory that should be allocated to store the +* desired number of objects. when not zero, it allocates more memory +* for the padding between objects, to ensure that an object does not +* cross a page boundary. in other words, page size/shift are to be set +* to zero if mempool elements won't care about page boundaries. +* there are several considerations for page size and page shift here. +* +* if we don't need our mempools to have physically contiguous objects, +* then just set page shift and page size to 0, because the user has +* indicated that there's no need to care about anything. +* +* if we do need contiguous objects, there is also an option to reserve +* the entire mempool memory as one contiguous block of memory, in +* which case the page shift and alignment wouldn't matter as well. +* +* if we require contiguous objects, but not necessarily the entire +* mempool reserved space to be contiguous, then there are two options. +* +* if our IO addresses are virtual, not actual physical (IOVA as VA +* case), then no page shift needed - our memory allocation will give us +* contiguous physical memory as far as the hardware is concerned, so +* act as if we're getting contiguous memory. +* +* if our IO addresses are physical, we may get memory from bigger +* pages, or we might get memory from smaller pages, and how much of it +* we require depends on whether we want bigger or smaller pages. +* However, requesting each and every memory size is too much work, so +* what we'll do instead is walk through the page sizes available, pick +* the smallest one and set up page shift to match that one. We will be +* wasting some space this way, but it's much nicer than looping around +* trying to reserve each and every page size. +* +* However, since size calculation will produce page-aligned sizes, it +* makes sense to first try and see if we can reserve the entire memzone +* in one contiguous chunk as well (otherwise we might end up wasting a +* 1G page on a 10MB memzone). If we fail to get enough contiguous +* memory, then we'll go and reserve space page-by-page. +*/ + no_pageshift = no_contig || force_contig || +rte_eal_iova_mode () ==RTE_IOVA_VA ; + try_contig = !no_contig && !no_pageshift &&rte_eal_has_hugepages (); +if (force_contig) + mz_flags |=RTE_MEMZONE_IOVA_CONTIG ; + +if (no_pageshift) { pg_sz =0 ; + pg_shift =0 ; + align =RTE_CACHE_LINE_SIZE ; + }else if (try_contig) { + pg_sz =get_min_page_size (); + pg_shift =rte_bsf32 (pg_sz); +/* we're trying to reserve contiguous memzone first, so try +* align to cache line; if we fail to reserve a contiguous +* memzone, we'll adjust alignment to equal pagesize later. +*/ align =RTE_CACHE_LINE_SIZE ; }else { pg_sz =getpagesize ();
@@ -575,8 +646,13 @@ rte_mempool_populate_default(struct rte_mempool *mp) total_elt_sz = mp->header_size + mp->elt_size + mp->trailer_size;for (mz_id =0 , n = mp->size; n >0 ; mz_id++, n -= ret) { - size =rte_mempool_xmem_size (n, total_elt_sz, pg_shift, - mp->flags); +unsigned int flags; +if (try_contig || no_pageshift) + size =rte_mempool_xmem_size (n, total_elt_sz,0 , + mp->flags); +else + size =rte_mempool_xmem_size (n, total_elt_sz, pg_shift, + mp->flags); ret =snprintf (mz_name,sizeof (mz_name),RTE_MEMPOOL_MZ_FORMAT "_%d" , mp->name, mz_id);
@@ -585,23 +661,52 @@ rte_mempool_populate_default(struct rte_mempool *mp) goto fail; } - mz =rte_memzone_reserve_aligned (mz_name, size, - mp->socket_id, mz_flags, align); -/* not enough memory, retry with the biggest zone we have */ -if (mz ==NULL ) + flags = mz_flags; + +/* if we're trying to reserve contiguous memory, add appropriate +* memzone flag. +*/ +if (try_contig) + flags |=RTE_MEMZONE_IOVA_CONTIG ; + + mz =rte_memzone_reserve_aligned (mz_name, size, mp->socket_id, + flags, align); + +/* if we were trying to allocate contiguous memory, adjust +* memzone size and page size to fit smaller page sizes, and +* try again. +*/ +if (mz ==NULL && try_contig) { + try_contig = false; + flags &= ~RTE_MEMZONE_IOVA_CONTIG ; + align = pg_sz; + size =rte_mempool_xmem_size (n, total_elt_sz, + pg_shift, mp->flags); + + mz =rte_memzone_reserve_aligned (mz_name, size, + mp->socket_id, flags, align); + } +/* don't try reserving with 0 size if we were asked to reserve +* IOVA-contiguous memory. +*/ +if (!force_contig && mz ==NULL ) { +/* not enough memory, retry with the biggest zone we +* have +*/ mz =rte_memzone_reserve_aligned (mz_name,0 , - mp->socket_id, mz_flags, align); + mp->socket_id, flags, align); + }if (mz ==NULL ) { ret = -rte_errno; goto fail; } -if (mp->flags &MEMPOOL_F_NO_PHYS_CONTIG ) +if (no_contig) iova =RTE_BAD_IOVA ;else iova = mz->iova; -if (rte_eal_has_hugepages ()) +if (no_pageshift || try_contig) ret = rte_mempool_populate_iova(mp, mz->addr, iova, mz->len, rte_mempool_memchunk_mz_free,
Signature · 1 line
2.7.4
PATCH v4 25/70 eal: add function to walk all memsegs
In reply to Anatoly BurakovFor code that might need to iterate over list of allocated segments, using this API will make it more resilient to internal API changes and will prevent copying the same iteration code over and over again.
Additionally, down the line there will be locking implemented, so users of this API will not need to care about locking either.
--- lib/librte_eal/common/eal_common_memory.c | 21 +++++++++++++++++++++ lib/librte_eal/common/include/rte_memory.h | 25 +++++++++++++++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 47 insertions(+)
lib/librte_eal/common/eal_common_memory.c +21 -0
@@ -218,6 +218,27 @@ rte_mem_lock_page(const void *virt)return mlock ((void *)aligned, page_size); } +int __rte_experimental +rte_memseg_walk (rte_memseg_walk_t func,void *arg) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +int i, ret; + +for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { +const struct rte_memseg *ms = &mcfg->memseg[i]; + +if (ms->addr ==NULL ) +continue ; + + ret =func (ms, arg); +if (ret <0 ) +return -1 ; +if (ret >0 ) +return 1 ; + } +return 0 ; +} +/* init memory subsystem */ int rte_eal_memory_init (void )
lib/librte_eal/common/include/rte_memory.h +25 -0
@@ -20,6 +20,7 @@ extern "C" {#endif #include <rte_common.h> +#include <rte_compat.h> #include <rte_config.h> __extension__
@@ -130,6 +131,30 @@ phys_addr_t rte_mem_virt2phy(const void *virt);rte_iova_t rte_mem_virt2iova (const void *virt);/** +* Memseg walk function prototype. +* +* Returning 0 will continue walk +* Returning 1 will stop the walk +* Returning -1 will stop the walk and report error +*/ +typedef int (*rte_memseg_walk_t )(const struct rte_memseg *ms,void *arg); + +/** +* Walk list of all memsegs. +* +* @param func +* Iterator function +* @param arg +* Argument passed to iterator +* @return +* 0 if walked over the entire list +* 1 if stopped by the user +* -1 if user function reported error +*/ +int __rte_experimental +rte_memseg_walk (rte_memseg_walk_t func,void *arg); + +/** * Get the layout of the available physical memory. * * It can be useful for an application to have the full physical
lib/librte_eal/rte_eal_version.map +1 -0
@@ -223,6 +223,7 @@ EXPERIMENTAL { rte_eal_mbuf_user_pool_ops; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; + rte_memseg_walk; rte_mp_action_register; rte_mp_action_unregister; rte_mp_reply;
Signature · 1 line
2.7.4
PATCH v4 26/70 bus/fslmc: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/bus/fslmc/fslmc_vfio.c | 78 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 37 deletions(-)
drivers/bus/fslmc/fslmc_vfio.c +41 -37
@@ -189,17 +189,51 @@ static int vfio_map_irq_region(struct fslmc_vfio_group *group)return -errno; } -int rte_fslmc_vfio_dmamap (void ) +static int +fslmc_vfio_map (const struct rte_memseg *ms,void *arg) { -int ret; +int *n_segs = arg;struct fslmc_vfio_group *group;struct vfio_iommu_type1_dma_map dma_map = { .argsz =sizeof (struct vfio_iommu_type1_dma_map ), .flags =VFIO_DMA_MAP_FLAG_READ |VFIO_DMA_MAP_FLAG_WRITE , }; +int ret; + + dma_map.size = ms->len; + dma_map.vaddr = ms->addr_64; +#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA + dma_map.iova = ms->iova; +#else + dma_map.iova = dma_map.vaddr; +#endif + +/* SET DMA MAP for IOMMU */ + group = &vfio_group; + +if (!group->container) { +DPAA2_BUS_ERR ("Container is not connected " ); +return -1 ; + } + +DPAA2_BUS_DEBUG ("-->Initial SHM Virtual ADDR %llX" , + dma_map.vaddr); +DPAA2_BUS_DEBUG ("-----> DMA size 0x%llX" , dma_map.size); + ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , + &dma_map); +if (ret) { +DPAA2_BUS_ERR ("VFIO_IOMMU_MAP_DMA API(errno = %d)" , + errno); +return -1 ; + } + (*n_segs)++; +return 0 ; +} -int i; +int rte_fslmc_vfio_dmamap (void ) +{const struct rte_memseg *memseg; +int i =0 ;if (is_dma_done)return 0 ;
@@ -210,51 +244,21 @@ int rte_fslmc_vfio_dmamap(void)return -ENODEV ; } -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -if (memseg[i].addr ==NULL && memseg[i].len ==0 ) { -DPAA2_BUS_DEBUG ("Total %d segments found" , i); -break ; - } - - dma_map.size = memseg[i].len; - dma_map.vaddr = memseg[i].addr_64; -#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA - dma_map.iova = memseg[i].iova; -#else - dma_map.iova = dma_map.vaddr; -#endif - -/* SET DMA MAP for IOMMU */ - group = &vfio_group; - -if (!group->container) { -DPAA2_BUS_ERR ("Container is not connected" ); -return -1 ; - } - -DPAA2_BUS_DEBUG ("-->Initial SHM Virtual ADDR %llX" , - dma_map.vaddr); -DPAA2_BUS_DEBUG ("-----> DMA size 0x%llX" , dma_map.size); - ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , - &dma_map); -if (ret) { -DPAA2_BUS_ERR ("Unable to map DMA address (errno = %d)" , - errno); -return ret; - } - } +if (rte_memseg_walk (fslmc_vfio_map, &i) <0 ) +return -1 ;/* Verifying that at least single segment is available */ if (i <=0 ) {DPAA2_BUS_ERR ("No Segments found for VFIO Mapping" );return -1 ; } +DPAA2_BUS_DEBUG ("Total %d segments found." , i);/* TODO - This is a W.A. as VFIO currently does not add the mapping of * the interrupt region to SMMU. This should be removed once the * support is added in the Kernel. */ -vfio_map_irq_region (group); +vfio_map_irq_region (&vfio_group); is_dma_done =1 ;
Signature · 1 line
2.7.4
PATCH v4 27/70 bus/pci: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/bus/pci/Makefile | 3 +++ drivers/bus/pci/linux/pci.c | 26 ++++++++++++++------------ drivers/bus/pci/meson.build | 3 +++ 3 files changed, 20 insertions(+), 12 deletions(-)
drivers/bus/pci/Makefile +3 -0
@@ -49,6 +49,9 @@ CFLAGS += -I$(RTE_SDK)/drivers/bus/pci/$(SYSTEM) CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal +# memseg walk is not part of stable API yet +CFLAGS += -DALLOW_EXPERIMENTAL_API + LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring LDLIBS += -lrte_ethdev -lrte_pci
drivers/bus/pci/linux/pci.c +14 -12
@@ -116,22 +116,24 @@ rte_pci_unmap_device(struct rte_pci_device *dev) } } -void * -pci_find_max_end_va (void ) +static int +find_max_end_va (const struct rte_memseg *ms,void *arg) { -const struct rte_memseg *seg =rte_eal_get_physmem_layout (); -const struct rte_memseg *last = seg; -unsigned i =0 ; +void *end_va =RTE_PTR_ADD (ms->addr, ms->len); +void **max_va = arg; -for (i =0 ; i <RTE_MAX_MEMSEG ; i++, seg++) { -if (seg->addr ==NULL ) -break ; +if (*max_va < end_va) + *max_va = end_va; +return 0 ; +} -if (seg->addr > last->addr) - last = seg; +void * +pci_find_max_end_va (void ) +{ +void *va =NULL ; - } -return RTE_PTR_ADD (last->addr, last->len); +rte_memseg_walk (find_max_end_va, &va); +return va; }/* parse one line of the "resource" sysfs file (note that the 'line'
drivers/bus/pci/meson.build +3 -0
@@ -14,3 +14,6 @@ else sources += files('bsd/pci.c') includes += include_directories('bsd') endif + +# memseg walk is not part of stable API yet +allow_experimental_apis = true
Signature · 1 line
2.7.4
PATCH v4 28/70 net/mlx5: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/net/mlx5/Makefile | 3 +++ drivers/net/mlx5/mlx5.c | 24 +++++++++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-)
drivers/net/mlx5/Makefile +3 -0
@@ -92,6 +92,9 @@ CFLAGS += -Wno-error=cast-qual EXPORT_MAP := rte_pmd_mlx5_version.map LIBABIVER := 1 +# memseg walk is not part of stable API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # DEBUG which is usually provided on the command-line may enable # CONFIG_RTE_LIBRTE_MLX5_DEBUG. ifeq ($(DEBUG),1)
drivers/net/mlx5/mlx5.c +15 -9
@@ -477,6 +477,19 @@ static struct rte_pci_driver mlx5_driver;*/ static void *uar_base; +static int +find_lower_va_bound (const struct rte_memseg *ms,void *arg) +{ +void **addr = arg; + +if (*addr ==NULL ) + *addr = ms->addr; +else + *addr =RTE_MIN (*addr, ms->addr); + +return 0 ; +} +/** * Reserve UAR address space for primary process. *
@@ -491,21 +504,14 @@ mlx5_uar_init_primary(struct rte_eth_dev *dev) {struct priv *priv = dev->data->dev_private;void *addr = (void *)0 ; -int i; -const struct rte_mem_config *mcfg;if (uar_base) {/* UAR address space mapped. */ priv->uar_base = uar_base;return 0 ; }/* find out lower bound of hugepage segments */ - mcfg =rte_eal_get_configuration ()->mem_config; -for (i =0 ; i <RTE_MAX_MEMSEG && mcfg->memseg[i].addr; i++) { -if (addr) - addr =RTE_MIN (addr, mcfg->memseg[i].addr); -else - addr = mcfg->memseg[i].addr; - } +rte_memseg_walk (find_lower_va_bound, &addr); +/* keep distance to hugepages to minimize potential conflicts. */ addr =RTE_PTR_SUB (addr,MLX5_UAR_OFFSET +MLX5_UAR_SIZE );/* anonymous mmap, no real memory consumption. */
Signature · 1 line
2.7.4
PATCH v4 29/70 eal: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- lib/librte_eal/bsdapp/eal/eal.c | 25 +++++++----- lib/librte_eal/common/eal_common_memory.c | 67 ++++++++++++++++--------------- lib/librte_eal/common/malloc_heap.c | 33 +++++++++------ lib/librte_eal/linuxapp/eal/eal.c | 22 +++++----- 4 files changed, 81 insertions(+), 66 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +14 -11
@@ -429,23 +429,26 @@ eal_parse_args(int argc, char **argv)return ret; } +static int +check_socket (const struct rte_memseg *ms,void *arg) +{ +int *socket_id = arg; + +if (ms->socket_id == *socket_id) +return 1 ; + +return 0 ; +} +static void eal_check_mem_on_local_socket (void ) { -const struct rte_memseg *ms; -int i, socket_id; +int socket_id; socket_id =rte_lcore_to_socket_id (rte_config.master_lcore); - ms =rte_eal_get_physmem_layout (); - -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) -if (ms[i].socket_id == socket_id && - ms[i].len >0 ) -return ; - -RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no " -"memory on local socket!\n" ); +if (rte_memseg_walk (check_socket, &socket_id) ==0 ) +RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no memory on local socket!\n" ); } static int
lib/librte_eal/common/eal_common_memory.c +35 -32
89 lines not on this page · raw message
lib/librte_eal/common/malloc_heap.c +21 -12
@@ -67,17 +67,32 @@ check_hugepage_sz(unsigned flags, uint64_t hugepage_sz)* to prevent overflow. The rest of the zone is added to free list as a single * large free block */ -static void -malloc_heap_add_memseg (struct malloc_heap *heap,struct rte_memseg *ms) +static int +malloc_heap_add_memseg(const struct rte_memseg *ms, void *arg __rte_unused) { -struct malloc_elem *start_elem = (struct malloc_elem *)ms->addr; -const size_t elem_size = ms->len -MALLOC_ELEM_OVERHEAD ; +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +struct malloc_elem *start_elem; +struct rte_memseg *found_ms; +struct malloc_heap *heap; +size_t elem_size; +int ms_idx; + + heap = &mcfg->malloc_heaps[ms->socket_id]; + +/* ms is const, so find it */ + ms_idx = ms - mcfg->memseg; + found_ms = &mcfg->memseg[ms_idx]; -malloc_elem_init (start_elem, heap, ms, elem_size); + start_elem = (struct malloc_elem *)found_ms->addr; + elem_size = ms->len -MALLOC_ELEM_OVERHEAD ; + +malloc_elem_init (start_elem, heap, found_ms, elem_size);malloc_elem_insert (start_elem);malloc_elem_free_list_insert (start_elem); heap->total_size += elem_size; + +return 0 ; }/*
@@ -244,17 +259,11 @@ intrte_eal_malloc_heap_init (void) {struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; -unsigned ms_cnt; -struct rte_memseg *ms;if (mcfg ==NULL )return -1 ; -for (ms = &mcfg->memseg[0 ], ms_cnt =0 ; - (ms_cnt <RTE_MAX_MEMSEG ) && (ms->len >0 ); - ms_cnt++, ms++) { -malloc_heap_add_memseg (&mcfg->malloc_heaps[ms->socket_id], ms); - } +rte_memseg_walk (malloc_heap_add_memseg,NULL );return 0 ; }
lib/librte_eal/linuxapp/eal/eal.c +11 -11
@@ -638,23 +638,23 @@ eal_parse_args(int argc, char **argv)return ret; } +static int +check_mem (const struct rte_memseg *ms,void *arg) +{ +int *socket = arg; + +return ms->socket_id == *socket; +} +static void eal_check_mem_on_local_socket (void ) { -const struct rte_memseg *ms; -int i, socket_id; +int socket_id; socket_id =rte_lcore_to_socket_id (rte_config.master_lcore); - ms =rte_eal_get_physmem_layout (); - -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) -if (ms[i].socket_id == socket_id && - ms[i].len >0 ) -return ; - -RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no " -"memory on local socket!\n" ); +if (rte_memseg_walk (check_mem, &socket_id) ==0 ) +RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no memory on local socket!\n" ); } static int
Signature · 1 line
2.7.4
PATCH v4 30/70 mempool: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- lib/librte_mempool/Makefile | 3 +++ lib/librte_mempool/meson.build | 3 +++ lib/librte_mempool/rte_mempool.c | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 12 deletions(-)
lib/librte_mempool/Makefile +3 -0
@@ -13,6 +13,9 @@ EXPORT_MAP := rte_mempool_version.map LIBABIVER := 3 +# memseg walk is not yet part of stable API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # all source are stored in SRCS-y SRCS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += rte_mempool.c SRCS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += rte_mempool_ops.c
lib/librte_mempool/meson.build +3 -0
@@ -5,3 +5,6 @@ version = 3 sources = files('rte_mempool.c', 'rte_mempool_ops.c') headers = files('rte_mempool.h') deps += ['ring'] + +# memseg walk is not yet part of stable API +allow_experimental_apis = true
lib/librte_mempool/rte_mempool.c +12 -12
@@ -99,23 +99,23 @@ static unsigned optimize_object_size(unsigned obj_size)return new_obj_size *RTE_MEMPOOL_ALIGN ; } +static int +find_min_pagesz (const struct rte_memseg *ms,void *arg) +{ +size_t *min = arg; + +if (ms->hugepage_sz < *min) + *min = ms->hugepage_sz; + +return 0 ; +} +static size_t get_min_page_size (void ) { -const struct rte_mem_config *mcfg = -rte_eal_get_configuration ()->mem_config; -int i;size_t min_pagesz =SIZE_MAX ; -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -const struct rte_memseg *ms = &mcfg->memseg[i]; - -if (ms->addr ==NULL ) -continue ; - -if (ms->hugepage_sz < min_pagesz) - min_pagesz = ms->hugepage_sz; - } +rte_memseg_walk (find_min_pagesz, &min_pagesz);return min_pagesz ==SIZE_MAX ? (size_t )getpagesize () : min_pagesz; }
Signature · 1 line
2.7.4
PATCH v4 31/70 test: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- test/test/test_malloc.c | 40 +++++++++++++++++++++++------------- test/test/test_memory.c | 23 +++++++++++---------- test/test/test_memzone.c | 53 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 74 insertions(+), 42 deletions(-)
test/test/test_malloc.c +26 -14
@@ -705,16 +705,34 @@ test_malloc_bad_params(void)return -1 ; } +static int +check_socket_mem (const struct rte_memseg *ms,void *arg) +{ +int32_t *socket = arg; + +return *socket == ms->socket_id; +} +/* Check if memory is available on a specific socket */ static int is_mem_on_socket (int32_t socket) { -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); -unsigned i; +return rte_memseg_walk (check_socket_mem, &socket); +} -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -if (socket == ms[i].socket_id) -return 1 ; +struct walk_param { +void *addr; +int32_t socket; +}; +static int +find_socket (const struct rte_memseg *ms,void *arg) +{ +struct walk_param *param = arg; + +if (param->addr >= ms->addr && + param->addr <RTE_PTR_ADD (ms->addr, ms->len)) { + param->socket = ms->socket_id; +return 1 ; }return 0 ; }
@@ -726,15 +744,9 @@ is_mem_on_socket(int32_t socket)static int32_t addr_to_socket (void * addr) { -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); -unsigned i; - -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -if ((ms[i].addr <= addr) && - ((uintptr_t )addr < - ((uintptr_t )ms[i].addr + (uintptr_t )ms[i].len))) -return ms[i].socket_id; - } +struct walk_param param = {.addr = addr, .socket =0 }; +if (rte_memseg_walk (find_socket, ¶m) >0 ) +return param.socket;return -1 ; }
test/test/test_memory.c +12 -11
@@ -23,12 +23,20 @@*/ static int +check_mem(const struct rte_memseg *ms, void *arg __rte_unused) +{ +volatile uint8_t *mem = (volatile uint8_t *) ms->addr; +size_t i; + +for (i =0 ; i < ms->len; i++, mem++) + *mem; +return 0 ; +} + +static int test_memory (void ) {uint64_t s; -unsigned i; -size_t j; -const struct rte_memseg *mem;/* * dump the mapped memory: the python-expect script checks
@@ -45,14 +53,7 @@ test_memory(void) }/* try to read memory (should not segfault) */ - mem =rte_eal_get_physmem_layout (); -for (i =0 ; i <RTE_MAX_MEMSEG && mem[i].addr !=NULL ; i++) { - -/* check memory */ -for (j =0 ; j<mem[i].len; j++) { - *((volatile uint8_t *) mem[i].addr + j); - } - } +rte_memseg_walk (check_mem,NULL );return 0 ; }
test/test/test_memzone.c +36 -17
64 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 32/70 vfio/type1: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- lib/librte_eal/linuxapp/eal/eal_vfio.c | 45 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 24 deletions(-)
lib/librte_eal/linuxapp/eal/eal_vfio.c +21 -24
@@ -665,39 +665,36 @@ vfio_get_group_no(const char *sysfs_base, }static int -vfio_type1_dma_map (int vfio_container_fd) +type1_map (const struct rte_memseg *ms,void *arg) { -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); -int i, ret; +int *vfio_container_fd = arg; +struct vfio_iommu_type1_dma_map dma_map; +int ret; -/* map all DPDK segments for DMA. use 1:1 PA to IOVA mapping */ -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -struct vfio_iommu_type1_dma_map dma_map; +memset (&dma_map,0 ,sizeof (dma_map)); + dma_map.argsz =sizeof (struct vfio_iommu_type1_dma_map ); + dma_map.vaddr = ms->addr_64; + dma_map.size = ms->len; + dma_map.iova = ms->iova; + dma_map.flags =VFIO_DMA_MAP_FLAG_READ |VFIO_DMA_MAP_FLAG_WRITE ; -if (ms[i].addr ==NULL ) -break ; - -memset (&dma_map,0 ,sizeof (dma_map)); - dma_map.argsz =sizeof (struct vfio_iommu_type1_dma_map ); - dma_map.vaddr = ms[i].addr_64; - dma_map.size = ms[i].len; - dma_map.iova = ms[i].iova; - dma_map.flags =VFIO_DMA_MAP_FLAG_READ |VFIO_DMA_MAP_FLAG_WRITE ; + ret =ioctl (*vfio_container_fd,VFIO_IOMMU_MAP_DMA , &dma_map); - ret =ioctl (vfio_container_fd,VFIO_IOMMU_MAP_DMA , &dma_map); - -if (ret) { -RTE_LOG (ERR ,EAL ," cannot set up DMA remapping, " -"error %i (%s)\n" , errno, -strerror (errno)); -return -1 ; - } +if (ret) { +RTE_LOG (ERR ,EAL ," cannot set up DMA remapping, error %i (%s)\n" , + errno,strerror (errno)); +return -1 ; } -return 0 ; }static int +vfio_type1_dma_map (int vfio_container_fd) +{ +return rte_memseg_walk (type1_map, &vfio_container_fd); +} + +static int vfio_spapr_dma_map (int vfio_container_fd) {const struct rte_memseg *ms =rte_eal_get_physmem_layout ();
Signature · 1 line
2.7.4
PATCH v4 33/70 vfio/spapr: use memseg walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- lib/librte_eal/linuxapp/eal/eal_vfio.c | 108 +++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 45 deletions(-)
lib/librte_eal/linuxapp/eal/eal_vfio.c +63 -45
@@ -694,16 +694,69 @@ vfio_type1_dma_map(int vfio_container_fd)return rte_memseg_walk (type1_map, &vfio_container_fd); } +struct spapr_walk_param { +uint64_t window_size; +uint64_t hugepage_sz; +};static int -vfio_spapr_dma_map (int vfio_container_fd) +spapr_window_size (const struct rte_memseg *ms,void *arg) { -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); -int i, ret; +struct spapr_walk_param *param = arg; +uint64_t max = ms->iova + ms->len; + +if (max > param->window_size) { + param->hugepage_sz = ms->hugepage_sz; + param->window_size = max; + } +return 0 ; +} + +static int +spapr_map (const struct rte_memseg *ms,void *arg) +{ +struct vfio_iommu_type1_dma_map dma_map;struct vfio_iommu_spapr_register_memory reg = { .argsz =sizeof (reg), .flags =0 }; +int *vfio_container_fd = arg; +int ret; + + reg.vaddr = (uintptr_t ) ms->addr; + reg.size = ms->len; + ret =ioctl (*vfio_container_fd, +VFIO_IOMMU_SPAPR_REGISTER_MEMORY , ®); +if (ret) { +RTE_LOG (ERR ,EAL ," cannot register vaddr for IOMMU, error %i (%s)\n" , + errno,strerror (errno)); +return -1 ; + } + +memset (&dma_map,0 ,sizeof (dma_map)); + dma_map.argsz =sizeof (struct vfio_iommu_type1_dma_map ); + dma_map.vaddr = ms->addr_64; + dma_map.size = ms->len; + dma_map.iova = ms->iova; + dma_map.flags =VFIO_DMA_MAP_FLAG_READ | +VFIO_DMA_MAP_FLAG_WRITE ; + + ret =ioctl (*vfio_container_fd,VFIO_IOMMU_MAP_DMA , &dma_map); + +if (ret) { +RTE_LOG (ERR ,EAL ," cannot set up DMA remapping, error %i (%s)\n" , + errno,strerror (errno)); +return -1 ; + } + +return 0 ; +} + +static int +vfio_spapr_dma_map (int vfio_container_fd) +{ +struct spapr_walk_param param; +int ret;struct vfio_iommu_spapr_tce_info info = { .argsz =sizeof (info), };
@@ -714,6 +767,8 @@ vfio_spapr_dma_map(int vfio_container_fd) .argsz = sizeof(remove), }; +memset (¶m,0 ,sizeof (param)); +/* query spapr iommu info */ ret =ioctl (vfio_container_fd,VFIO_IOMMU_SPAPR_TCE_GET_INFO , &info);if (ret) {
@@ -732,17 +787,11 @@ vfio_spapr_dma_map(int vfio_container_fd) }/* create DMA window from 0 to max(phys_addr + len) */ -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -if (ms[i].addr ==NULL ) -break ; - - create.window_size =RTE_MAX (create.window_size, - ms[i].iova + ms[i].len); - } +rte_memseg_walk (spapr_window_size, ¶m);/* sPAPR requires window size to be a power of 2 */ - create.window_size =rte_align64pow2 (create.window_size); - create.page_shift =__builtin_ctzll (ms->hugepage_sz); + create.window_size =rte_align64pow2 (param.window_size); + create.page_shift =__builtin_ctzll (param.hugepage_sz); create.levels =1 ; ret =ioctl (vfio_container_fd,VFIO_IOMMU_SPAPR_TCE_CREATE , &create);
@@ -758,39 +807,8 @@ vfio_spapr_dma_map(int vfio_container_fd) }/* map all DPDK segments for DMA. use 1:1 PA to IOVA mapping */ -for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { -struct vfio_iommu_type1_dma_map dma_map; - -if (ms[i].addr ==NULL ) -break ; - - reg.vaddr = (uintptr_t ) ms[i].addr; - reg.size = ms[i].len; - ret =ioctl (vfio_container_fd, -VFIO_IOMMU_SPAPR_REGISTER_MEMORY , ®); -if (ret) { -RTE_LOG (ERR ,EAL ," cannot register vaddr for IOMMU, " -"error %i (%s)\n" , errno,strerror (errno)); -return -1 ; - } - -memset (&dma_map,0 ,sizeof (dma_map)); - dma_map.argsz =sizeof (struct vfio_iommu_type1_dma_map ); - dma_map.vaddr = ms[i].addr_64; - dma_map.size = ms[i].len; - dma_map.iova = ms[i].iova; - dma_map.flags =VFIO_DMA_MAP_FLAG_READ | -VFIO_DMA_MAP_FLAG_WRITE ; - - ret =ioctl (vfio_container_fd,VFIO_IOMMU_MAP_DMA , &dma_map); - -if (ret) { -RTE_LOG (ERR ,EAL ," cannot set up DMA remapping, " -"error %i (%s)\n" , errno,strerror (errno)); -return -1 ; - } - - } +if (rte_memseg_walk (spapr_map, &vfio_container_fd) <0 ) +return -1 ;return 0 ; }
Signature · 1 line
2.7.4
PATCH v4 34/70 eal: add contig walk function
In reply to Anatoly BurakovThis function is meant to walk over first segment of each VA-contiguous group of memsegs.
For future users of this function, this is done so that there is less dependency on internals of mem API and less noise later change sets.
--- lib/librte_eal/common/eal_common_memory.c | 37 ++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_memory.h | 27 ++++++++++++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 65 insertions(+)
lib/librte_eal/common/eal_common_memory.c +37 -0
@@ -242,6 +242,43 @@ rte_memseg_walk(rte_memseg_walk_t func, void *arg)return 0 ; } +int __rte_experimental +rte_memseg_contig_walk (rte_memseg_contig_walk_t func,void *arg) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +int i, j, ret; + +for (i =0 ; i <RTE_MAX_MEMSEG ; i++) { +const struct rte_memseg *ms = &mcfg->memseg[i]; +size_t total_len; +void *end_addr; + +if (ms->addr ==NULL ) +continue ; + + end_addr =RTE_PTR_ADD (ms->addr, ms->len); + +/* check how many more segments are contiguous to this one */ +for (j = i +1 ; j <RTE_MAX_MEMSEG ; j++) { +const struct rte_memseg *next = &mcfg->memseg[j]; + +if (next->addr != end_addr) +break ; + + end_addr =RTE_PTR_ADD (next->addr, next->len); + i++; + } + total_len =RTE_PTR_DIFF (end_addr, ms->addr); + + ret =func (ms, total_len, arg); +if (ret <0 ) +return -1 ; +if (ret >0 ) +return 1 ; + } +return 0 ; +} +/* init memory subsystem */ int rte_eal_memory_init (void )
lib/librte_eal/common/include/rte_memory.h +27 -0
@@ -140,6 +140,18 @@ rte_iova_t rte_mem_virt2iova(const void *virt);typedef int (*rte_memseg_walk_t )(const struct rte_memseg *ms,void *arg);/** +* Memseg contig walk function prototype. This will trigger a callback on every +* VA-contiguous are starting at memseg ``ms``, so total valid VA space at each +* callback call will be [``ms->addr``, ``ms->addr + len``). +* +* Returning 0 will continue walk +* Returning 1 will stop the walk +* Returning -1 will stop the walk and report error +*/ +typedef int (*rte_memseg_contig_walk_t )(const struct rte_memseg *ms, +size_t len,void *arg); + +/** * Walk list of all memsegs. * * @param func
@@ -155,6 +167,21 @@ int __rte_experimental rte_memseg_walk(rte_memseg_walk_t func, void *arg);/** +* Walk each VA-contiguous area. +* +* @param func +* Iterator function +* @param arg +* Argument passed to iterator +* @return +* 0 if walked over the entire list +* 1 if stopped by the user +* -1 if user function reported error +*/ +int __rte_experimental +rte_memseg_contig_walk (rte_memseg_contig_walk_t func,void *arg); + +/** * Get the layout of the available physical memory. * * It can be useful for an application to have the full physical
lib/librte_eal/rte_eal_version.map +1 -0
@@ -223,6 +223,7 @@ EXPERIMENTAL { rte_eal_mbuf_user_pool_ops; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; + rte_memseg_contig_walk; rte_memseg_walk; rte_mp_action_register; rte_mp_action_unregister;
Signature · 1 line
2.7.4
PATCH v4 35/70 virtio: use memseg contig walk instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/net/virtio/virtio_user/vhost_kernel.c | 83 +++++++++++---------------- 1 file changed, 35 insertions(+), 48 deletions(-)
drivers/net/virtio/virtio_user/vhost_kernel.c +35 -48
@@ -70,6 +70,32 @@ static uint64_t vhost_req_user_to_kernel[] = { [VHOST_USER_SET_MEM_TABLE] = VHOST_SET_MEM_TABLE, }; +struct walk_arg { +struct vhost_memory_kernel *vm; +uint32_t region_nr; +}; +static int +add_memory_region (const struct rte_memseg *ms,size_t len,void *arg) +{ +struct walk_arg *wa = arg; +struct vhost_memory_region *mr; +void *start_addr; + +if (wa->region_nr >= max_regions) +return -1 ; + + mr = &wa->vm->regions[wa->region_nr++]; + start_addr = ms->addr; + + mr->guest_phys_addr = (uint64_t )(uintptr_t )start_addr; + mr->userspace_addr = (uint64_t )(uintptr_t )start_addr; + mr->memory_size = len; + mr->mmap_offset =0 ; + +return 0 ; +} + +/* By default, vhost kernel module allows 64 regions, but DPDK allows * 256 segments. As a relief, below function merges those virtually * adjacent memsegs into one region.
@@ -77,63 +103,24 @@ static uint64_t vhost_req_user_to_kernel[] = {static struct vhost_memory_kernel *prepare_vhost_memory_kernel (void ) { -uint32_t i, j, k =0 ; -struct rte_memseg *seg; -struct vhost_memory_region *mr;struct vhost_memory_kernel *vm; +struct walk_arg wa; vm =malloc (sizeof (struct vhost_memory_kernel ) + - max_regions * -sizeof (struct vhost_memory_region )); + max_regions * +sizeof (struct vhost_memory_region ));if (!vm)return NULL ; -for (i =0 ; i <RTE_MAX_MEMSEG ; ++i) { - seg = &rte_eal_get_configuration ()->mem_config->memseg[i]; -if (!seg->addr) -break ; - -int new_region =1 ; - -for (j =0 ; j < k; ++j) { - mr = &vm->regions[j]; + wa.region_nr =0 ; + wa.vm = vm; -if (mr->userspace_addr + mr->memory_size == - (uint64_t )(uintptr_t )seg->addr) { - mr->memory_size += seg->len; - new_region =0 ; -break ; - } - -if ((uint64_t )(uintptr_t )seg->addr + seg->len == - mr->userspace_addr) { - mr->guest_phys_addr = - (uint64_t )(uintptr_t )seg->addr; - mr->userspace_addr = - (uint64_t )(uintptr_t )seg->addr; - mr->memory_size += seg->len; - new_region =0 ; -break ; - } - } - -if (new_region ==0 ) -continue ; - - mr = &vm->regions[k++]; -/* use vaddr here! */ - mr->guest_phys_addr = (uint64_t )(uintptr_t )seg->addr; - mr->userspace_addr = (uint64_t )(uintptr_t )seg->addr; - mr->memory_size = seg->len; - mr->mmap_offset =0 ; - -if (k >= max_regions) { -free (vm); -return NULL ; - } +if (rte_memseg_contig_walk (add_memory_region, &wa) <0 ) { +free (vm); +return NULL ; } - vm->nregions = k; + vm->nregions = wa.region_nr; vm->padding =0 ;return vm; }
Signature · 1 line
2.7.4
PATCH v4 36/70 eal: add iova2virt function
In reply to Anatoly BurakovThis is reverse lookup of PA to VA. Using this will make other code less dependent on internals of mem API.
--- lib/librte_eal/common/eal_common_memory.c | 30 ++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_memory.h | 12 ++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 43 insertions(+)
lib/librte_eal/common/eal_common_memory.c +30 -0
@@ -131,6 +131,36 @@ rte_eal_get_physmem_layout(void)return rte_eal_get_configuration ()->mem_config->memseg; } +struct virtiova { +rte_iova_t iova; +void *virt; +}; +static int +find_virt (const struct rte_memseg *ms,void *arg) +{ +struct virtiova *vi = arg; +if (vi->iova >= ms->iova && vi->iova < (ms->iova + ms->len)) { +size_t offset = vi->iova - ms->iova; + vi->virt =RTE_PTR_ADD (ms->addr, offset); +/* stop the walk */ +return 1 ; + } +return 0 ; +} + +__rte_experimental void * +rte_mem_iova2virt (rte_iova_t iova) +{ +struct virtiova vi; + +memset (&vi,0 ,sizeof (vi)); + + vi.iova = iova; +rte_memseg_walk (find_virt, &vi); + +return vi.virt; +} +static int physmem_size (const struct rte_memseg *ms,void *arg) {
lib/librte_eal/common/include/rte_memory.h +12 -0
@@ -131,6 +131,18 @@ phys_addr_t rte_mem_virt2phy(const void *virt);rte_iova_t rte_mem_virt2iova (const void *virt);/** +* Get virtual memory address corresponding to iova address. +* +* @param iova +* The iova address. +* @return +* Virtual address corresponding to iova address (or NULL if address does not +* exist within DPDK memory map). +*/ +__rte_experimental void * +rte_mem_iova2virt (rte_iova_t iova); + +/** * Memseg walk function prototype. * * Returning 0 will continue walk
lib/librte_eal/rte_eal_version.map +1 -0
@@ -223,6 +223,7 @@ EXPERIMENTAL { rte_eal_mbuf_user_pool_ops; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; + rte_mem_iova2virt; rte_memseg_contig_walk; rte_memseg_walk; rte_mp_action_register;
Signature · 1 line
2.7.4
PATCH v4 37/70 bus/dpaa: use iova2virt instead of memseg iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
---
Notes:
v4:
- Fixed usage of experimental API's
v3:
- Added this patch
drivers/bus/dpaa/rte_dpaa_bus.h | 12 +----------- drivers/mempool/dpaa/Makefile | 3 +++ drivers/mempool/dpaa/meson.build | 3 +++ drivers/net/dpaa/Makefile | 3 +++ 4 files changed, 10 insertions(+), 11 deletions(-)
drivers/bus/dpaa/rte_dpaa_bus.h +1 -11
@@ -98,17 +98,7 @@ struct dpaa_portal {/* TODO - this is costly, need to write a fast coversion routine */ static inline void *rte_dpaa_mem_ptov (phys_addr_t paddr) { -const struct rte_memseg *memseg =rte_eal_get_physmem_layout (); -int i; - -for (i =0 ; i <RTE_MAX_MEMSEG && memseg[i].addr !=NULL ; i++) { -if (paddr >= memseg[i].iova && paddr < - memseg[i].iova + memseg[i].len) -return (uint8_t *)(memseg[i].addr) + - (paddr - memseg[i].iova); - } - -return NULL ; +return rte_mem_iova2virt (paddr); }/**
drivers/mempool/dpaa/Makefile +3 -0
@@ -22,6 +22,9 @@ EXPORT_MAP := rte_mempool_dpaa_version.map # Lbrary version LIBABIVER := 1 +# depends on dpaa bus which uses experimental API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # all source are stored in SRCS-y # SRCS-$(CONFIG_RTE_LIBRTE_DPAA_MEMPOOL) += dpaa_mempool.c
drivers/mempool/dpaa/meson.build +3 -0
@@ -7,3 +7,6 @@ endif deps += ['bus_dpaa'] sources = files('dpaa_mempool.c') + +# depends on dpaa bus which uses experimental API +allow_experimental_apis = true
drivers/net/dpaa/Makefile +3 -0
@@ -27,6 +27,9 @@ EXPORT_MAP := rte_pmd_dpaa_version.map LIBABIVER := 1 +# depends on dpaa bus which uses experimental API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # Interfaces with DPDK SRCS-$(CONFIG_RTE_LIBRTE_DPAA_PMD) += dpaa_ethdev.c SRCS-$(CONFIG_RTE_LIBRTE_DPAA_PMD) += dpaa_rxtx.c
Signature · 1 line
2.7.4
PATCH v4 38/70 bus/fslmc: use iova2virt instead of memseg iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
---
Notes:
v4:
- Fixed usage of experimental API's
v3:
- Added this patch
drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 13 +------------ drivers/event/dpaa2/Makefile | 3 +++ drivers/mempool/dpaa2/Makefile | 3 +++ drivers/mempool/dpaa2/meson.build | 3 +++ drivers/net/dpaa2/Makefile | 3 +++ drivers/net/dpaa2/meson.build | 3 +++ 6 files changed, 16 insertions(+), 12 deletions(-)
drivers/bus/fslmc/portal/dpaa2_hw_pvt.h +1 -12
@@ -260,21 +260,10 @@ static void *dpaa2_mem_ptov(phys_addr_t paddr) __attribute__((unused));/* todo - this is costly, need to write a fast coversion routine */ static void *dpaa2_mem_ptov (phys_addr_t paddr) { -const struct rte_memseg *memseg; -int i; -if (dpaa2_virt_mode)return (void *)(size_t )paddr; - memseg =rte_eal_get_physmem_layout (); - -for (i =0 ; i <RTE_MAX_MEMSEG && memseg[i].addr_64 !=0 ; i++) { -if (paddr >= memseg[i].iova && - paddr < memseg[i].iova + memseg[i].len) -return (void *)(size_t )(memseg[i].addr_64 - + (paddr - memseg[i].iova)); - } -return NULL ; +return rte_mem_iova2virt (paddr); }static phys_addr_t dpaa2_mem_vtop (uint64_t vaddr) __attribute__((unused));
drivers/event/dpaa2/Makefile +3 -0
@@ -28,6 +28,9 @@ EXPORT_MAP := rte_pmd_dpaa2_event_version.map LIBABIVER := 1 +# depends on fslmc bus which uses experimental API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # # all source are stored in SRCS-y #
drivers/mempool/dpaa2/Makefile +3 -0
@@ -21,6 +21,9 @@ EXPORT_MAP := rte_mempool_dpaa2_version.map # Lbrary version LIBABIVER := 1 +# depends on fslmc bus which uses experimental API +CFLAGS += -DALLOW_EXPERIMENTAL_API + # all source are stored in SRCS-y # SRCS-$(CONFIG_RTE_LIBRTE_DPAA2_MEMPOOL) += dpaa2_hw_mempool.c
drivers/mempool/dpaa2/meson.build +3 -0
@@ -7,3 +7,6 @@ endif deps += ['mbuf', 'bus_fslmc'] sources = files('dpaa2_hw_mempool.c') + +# depends on fslmc bus which uses experimental API +allow_experimental_apis = true
drivers/net/dpaa2/Makefile +3 -0
@@ -27,6 +27,9 @@ EXPORT_MAP := rte_pmd_dpaa2_version.map # library version LIBABIVER := 1 +# depends on fslmc bus which uses experimental API +CFLAGS += -DALLOW_EXPERIMENTAL_API + SRCS-$(CONFIG_RTE_LIBRTE_DPAA2_PMD) += base/dpaa2_hw_dpni.c SRCS-$(CONFIG_RTE_LIBRTE_DPAA2_PMD) += dpaa2_rxtx.c SRCS-$(CONFIG_RTE_LIBRTE_DPAA2_PMD) += dpaa2_ethdev.c
drivers/net/dpaa2/meson.build +3 -0
@@ -13,3 +13,6 @@ sources = files('base/dpaa2_hw_dpni.c', 'mc/dpni.c') includes += include_directories('base', 'mc') + +# depends on fslmc bus which uses experimental API +allow_experimental_apis = true
Signature · 1 line
2.7.4
PATCH v4 39/70 crypto/dpaa_sec: use iova2virt instead of memseg iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/crypto/dpaa_sec/dpaa_sec.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
drivers/crypto/dpaa_sec/dpaa_sec.c +1 -10
@@ -120,16 +120,7 @@ dpaa_mem_vtop_ctx(struct dpaa_sec_op_ctx *ctx, void *vaddr)static inline void *dpaa_mem_ptov (rte_iova_t paddr) { -const struct rte_memseg *memseg =rte_eal_get_physmem_layout (); -int i; - -for (i =0 ; i <RTE_MAX_MEMSEG && memseg[i].addr_64 !=0 ; i++) { -if (paddr >= memseg[i].iova && - paddr < memseg[i].iova + memseg[i].len) -return (void *)(size_t )(memseg[i].addr_64 + - (paddr - memseg[i].iova)); - } -return NULL ; +return rte_mem_iova2virt (paddr); } static void
Signature · 1 line
2.7.4
PATCH v4 40/70 eal: add virt2memseg function
In reply to Anatoly BurakovThis can be used as a virt2iova function that only looks up memory that is owned by DPDK (as opposed to doing pagemap walks). Using this will result in less dependency on internals of mem API.
--- lib/librte_eal/common/eal_common_memory.c | 37 ++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_memory.h | 11 +++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 49 insertions(+)
lib/librte_eal/common/eal_common_memory.c +37 -0
@@ -161,6 +161,43 @@ rte_mem_iova2virt(rte_iova_t iova)return vi.virt; } +struct virtms { +const void *virt; +struct rte_memseg *ms; +}; +static int +find_memseg (const struct rte_memseg *ms,void *arg) +{ +struct virtms *vm = arg; + +if (arg >= ms->addr && arg <RTE_PTR_ADD (ms->addr, ms->len)) { +struct rte_memseg *memseg, *found_ms; +int idx; + + memseg =rte_eal_get_configuration ()->mem_config->memseg; + idx = ms - memseg; + found_ms = &memseg[idx]; + + vm->ms = found_ms; +return 1 ; + } +return 0 ; +} + +__rte_experimental struct rte_memseg * +rte_mem_virt2memseg (const void *addr) +{ +struct virtms vm; + +memset (&vm,0 ,sizeof (vm)); + + vm.virt = addr; + +rte_memseg_walk (find_memseg, &vm); + +return vm.ms; +} +static int physmem_size (const struct rte_memseg *ms,void *arg) {
lib/librte_eal/common/include/rte_memory.h +11 -0
@@ -143,6 +143,17 @@ __rte_experimental void * rte_mem_iova2virt(rte_iova_t iova);/** +* Get memseg to which a particular virtual address belongs. +* +* @param virt +* The virtual address. +* @return +* Memseg pointer on success, or NULL on error. +*/ +__rte_experimental struct rte_memseg * +rte_mem_virt2memseg (const void *virt); + +/** * Memseg walk function prototype. * * Returning 0 will continue walk
lib/librte_eal/rte_eal_version.map +1 -0
@@ -224,6 +224,7 @@ EXPERIMENTAL { rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; rte_mem_iova2virt; + rte_mem_virt2memseg; rte_memseg_contig_walk; rte_memseg_walk; rte_mp_action_register;
Signature · 1 line
2.7.4
PATCH v4 41/70 bus/fslmc: use virt2memseg instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-)
drivers/bus/fslmc/portal/dpaa2_hw_pvt.h +4 -10
@@ -270,20 +270,14 @@ static phys_addr_t dpaa2_mem_vtop(uint64_t vaddr) __attribute__((unused));static phys_addr_t dpaa2_mem_vtop (uint64_t vaddr) {const struct rte_memseg *memseg; -int i;if (dpaa2_virt_mode)return vaddr; - memseg =rte_eal_get_physmem_layout (); - -for (i =0 ; i <RTE_MAX_MEMSEG && memseg[i].addr_64 !=0 ; i++) { -if (vaddr >= memseg[i].addr_64 && - vaddr < memseg[i].addr_64 + memseg[i].len) -return memseg[i].iova - + (vaddr - memseg[i].addr_64); - } -return (size_t )(NULL ); + memseg =rte_mem_virt2memseg ((void *)(uintptr_t )vaddr); +if (memseg) +return memseg->phys_addr +RTE_PTR_DIFF (vaddr, memseg->addr); +return (size_t )NULL ; }/**
Signature · 1 line
2.7.4
PATCH v4 42/70 crypto/dpaa_sec: use virt2memseg instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/crypto/dpaa_sec/dpaa_sec.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-)
drivers/crypto/dpaa_sec/dpaa_sec.c +5 -14
@@ -93,20 +93,11 @@ dpaa_sec_alloc_ctx(dpaa_sec_session *ses)static inline rte_iova_t dpaa_mem_vtop (void *vaddr) { -const struct rte_memseg *memseg =rte_eal_get_physmem_layout (); -uint64_t vaddr_64, paddr; -int i; - - vaddr_64 = (size_t )vaddr; -for (i =0 ; i <RTE_MAX_MEMSEG && memseg[i].addr_64 !=0 ; i++) { -if (vaddr_64 >= memseg[i].addr_64 && - vaddr_64 < memseg[i].addr_64 + memseg[i].len) { - paddr = memseg[i].iova + - (vaddr_64 - memseg[i].addr_64); - -return (rte_iova_t )paddr; - } - } +const struct rte_memseg *ms; + + ms =rte_mem_virt2memseg (vaddr); +if (ms) +return ms->iova +RTE_PTR_DIFF (vaddr, ms->addr);return (size_t )NULL ; }
Signature · 1 line
2.7.4
PATCH v4 43/70 net/mlx4: use virt2memseg instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/net/mlx4/mlx4_mr.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/net/mlx4/mlx4_mr.c +7 -10
@@ -126,7 +126,7 @@ mlx4_check_mempool(struct rte_mempool *mp, uintptr_t *start, uintptr_t *end)struct mlx4_mr *mlx4_mr_get (struct priv *priv,struct rte_mempool *mp) { -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); +const struct rte_memseg *ms;uintptr_t start;uintptr_t end;unsigned int i;
@@ -142,16 +142,13 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp) (void *)mp, (void *)start, (void *)end, (size_t)(end - start));/* Round start and end to page boundary if found in memory segments. */ -for (i =0 ; (i <RTE_MAX_MEMSEG ) && (ms[i].addr !=NULL ); ++i) { -uintptr_t addr = (uintptr_t )ms[i].addr; -size_t len = ms[i].len; -unsigned int align = ms[i].hugepage_sz; + ms =rte_mem_virt2memseg ((void *)start); +if (ms !=NULL ) + start =RTE_ALIGN_FLOOR (start, ms->hugepage_sz); + ms =rte_mem_virt2memseg ((void *)end); +if (ms !=NULL ) + end =RTE_ALIGN_CEIL (end, ms->hugepage_sz); -if ((start > addr) && (start < addr + len)) - start =RTE_ALIGN_FLOOR (start, align); -if ((end > addr) && (end < addr + len)) - end =RTE_ALIGN_CEIL (end, align); - }DEBUG ("mempool %p using start=%p end=%p size=%zu for MR" , (void *)mp, (void *)start, (void *)end, (size_t )(end - start));
Signature · 1 line
2.7.4
PATCH v4 44/70 net/mlx5: use virt2memseg instead of iteration
In reply to Anatoly BurakovReduce dependency on internal details of EAL memory subsystem, and simplify code.
--- drivers/net/mlx5/mlx5_mr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/net/mlx5/mlx5_mr.c +8 -10
@@ -234,7 +234,7 @@ struct mlx5_mr * mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp) { struct priv *priv = dev->data->dev_private; -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); +const struct rte_memseg *ms;uintptr_t start;uintptr_t end;unsigned int i;
@@ -261,17 +261,15 @@ mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp)/* Save original addresses for exact MR lookup. */ mr->start = start; mr->end = end; +/* Round start and end to page boundary if found in memory segments. */ -for (i =0 ; (i <RTE_MAX_MEMSEG ) && (ms[i].addr !=NULL ); ++i) { -uintptr_t addr = (uintptr_t )ms[i].addr; -size_t len = ms[i].len; -unsigned int align = ms[i].hugepage_sz; + ms =rte_mem_virt2memseg ((void *)start); +if (ms !=NULL ) + start =RTE_ALIGN_FLOOR (start, ms->hugepage_sz); + ms =rte_mem_virt2memseg ((void *)end); +if (ms !=NULL ) + end =RTE_ALIGN_CEIL (end, ms->hugepage_sz); -if ((start > addr) && (start < addr + len)) - start =RTE_ALIGN_FLOOR (start, align); -if ((end > addr) && (end < addr + len)) - end =RTE_ALIGN_CEIL (end, align); - } DRV_LOG(DEBUG, "port %u mempool %p using start=%p end=%p size=%zu for memory" " region",
Signature · 1 line
2.7.4
Re: [PATCH v4 44/70] net/mlx5: use virt2memseg instead of iteration
Quoted 13 lines · Anatoly Burakov
Reduce dependency on internal details of EAL memory subsystem, and simplify code.
Signed-off-by Anatoly Burakov <[email protected]>--- drivers/net/mlx5/mlx5_mr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)drivers/net/mlx5/mlx5_mr.c +0
-0
drivers/net/mlx5/mlx5_mr.c struct mlx5_mr * · line 240
Quoted 8 lines
drivers/net/mlx5/mlx5_mr.c +1
-1@@ -234,7 +234,7 @@ struct mlx5_mr * mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp) { struct priv *priv = dev->data->dev_private; -const struct rte_memseg *ms =rte_eal_get_physmem_layout (); +const struct rte_memseg *ms;uintptr_t start;uintptr_t end;unsigned int i;
Unused variable 'i' to be removed.
Thanks,
Gowrishankar
Quoted 25 lines
drivers/net/mlx5/mlx5_mr.c +7
-9@@ -261,17 +261,15 @@ mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp)/* Save original addresses for exact MR lookup. */ mr->start = start; mr->end = end; +/* Round start and end to page boundary if found in memory segments. */ -for (i =0 ; (i <RTE_MAX_MEMSEG ) && (ms[i].addr !=NULL ); ++i) { -uintptr_t addr = (uintptr_t )ms[i].addr; -size_t len = ms[i].len; -unsigned int align = ms[i].hugepage_sz; + ms =rte_mem_virt2memseg ((void *)start); +if (ms !=NULL ) + start =RTE_ALIGN_FLOOR (start, ms->hugepage_sz); + ms =rte_mem_virt2memseg ((void *)end); +if (ms !=NULL ) + end =RTE_ALIGN_CEIL (end, ms->hugepage_sz); -if ((start > addr) && (start < addr + len)) - start =RTE_ALIGN_FLOOR (start, align); -if ((end > addr) && (end < addr + len)) - end =RTE_ALIGN_CEIL (end, align); - } DRV_LOG(DEBUG, "port %u mempool %p using start=%p end=%p size=%zu for memory" " region",
PATCH v4 45/70 eal: use memzone walk instead of iteration
In reply to Anatoly BurakovSimplify memzone dump code to use memzone walk, to not maintain the same memzone iteration code twice.
--- lib/librte_eal/common/eal_common_memzone.c | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +21 -21
@@ -360,31 +360,31 @@ rte_memzone_lookup(const char *name)return memzone; } +static void +dump_memzone (const struct rte_memzone *mz,void *arg) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +FILE *f = arg; +int mz_idx; + + mz_idx = mz - mcfg->memzone; + +fprintf (f,"Zone %u: name:<%s>, IO:0x%" PRIx64", len:0x%zx, virt:%p, " +"socket_id:%" PRId32", flags:%" PRIx32"\n" , + mz_idx, + mz->name, + mz->iova, + mz->len, + mz->addr, + mz->socket_id, + mz->flags); +} +/* Dump all reserved memory zones on console */ void rte_memzone_dump (FILE *f) { -struct rte_mem_config *mcfg; -unsigned i =0 ; - -/* get pointer to global configuration */ - mcfg =rte_eal_get_configuration ()->mem_config; - -rte_rwlock_read_lock (&mcfg->mlock); -/* dump all zones */ -for (i=0 ; i<RTE_MAX_MEMZONE ; i++) { -if (mcfg->memzone[i].addr ==NULL ) -break ; -fprintf (f,"Zone %u: name:<%s>, IO:0x%" PRIx64", len:0x%zx" -", virt:%p, socket_id:%" PRId32", flags:%" PRIx32"\n" , i, - mcfg->memzone[i].name, - mcfg->memzone[i].iova, - mcfg->memzone[i].len, - mcfg->memzone[i].addr, - mcfg->memzone[i].socket_id, - mcfg->memzone[i].flags); - } -rte_rwlock_read_unlock (&mcfg->mlock); +rte_memzone_walk (dump_memzone, f); }/*
Signature · 1 line
2.7.4
PATCH v4 46/70 vfio: allow to map other memory regions
In reply to Anatoly BurakovCurrently it is not possible to use memory that is not owned by DPDK to perform DMA. This scenarion might be used in vhost applications (like SPDK) where guest send its own memory table. To fill this gap provide API to allow registering arbitrary address in VFIO container.
---
Notes:
v3:
- Added PPC64, courtesy of Gowrishankar
v3:
- Moved to earlier in the patchset
- Made API experimental
- Do not print out error message if init isn't finished
- SPAPR code provided by Gowrishankar
lib/librte_eal/bsdapp/eal/eal.c | 16 ++ lib/librte_eal/common/include/rte_vfio.h | 39 ++++ lib/librte_eal/linuxapp/eal/eal_vfio.c | 347 ++++++++++++++++++++++++------- lib/librte_eal/linuxapp/eal/eal_vfio.h | 12 ++ lib/librte_eal/rte_eal_version.map | 2 + 5 files changed, 341 insertions(+), 75 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +16 -0
@@ -749,6 +749,8 @@ int rte_vfio_enable(const char *modname);int rte_vfio_is_enabled (const char *modname);int rte_vfio_noiommu_is_enabled (void );int rte_vfio_clear_group (int vfio_group_fd); +int rte_vfio_dma_map (uint64_t vaddr,uint64_t iova,uint64_t len); +int rte_vfio_dma_unmap (uint64_t vaddr,uint64_t iova,uint64_t len); int rte_vfio_setup_device(__rte_unused const char *sysfs_base, __rte_unused const char *dev_addr,
@@ -784,3 +786,17 @@ int rte_vfio_clear_group(__rte_unused int vfio_group_fd) {return 0 ; } + +int __rte_experimental +rte_vfio_dma_map(uint64_t __rte_unused vaddr, __rte_unused uint64_t iova, + __rte_unused uint64_t len) +{ +return -1 ; +} + +int __rte_experimental +rte_vfio_dma_unmap(uint64_t __rte_unused vaddr, uint64_t __rte_unused iova, + __rte_unused uint64_t len) +{ +return -1 ; +}
lib/librte_eal/common/include/rte_vfio.h +39 -0
@@ -127,6 +127,45 @@ int rte_vfio_noiommu_is_enabled(void);int rte_vfio_clear_group (int vfio_group_fd); +/** +* Map memory region for use with VFIO. +* +* @param vaddr +* Starting virtual address of memory to be mapped. +* +* @param iova +* Starting IOVA address of memory to be mapped. +* +* @param len +* Length of memory segment being mapped. +* +* @return +* 0 if success. +* -1 on error. +*/ +int __rte_experimental +rte_vfio_dma_map (uint64_t vaddr,uint64_t iova,uint64_t len); + + +/** +* Unmap memory region from VFIO. +* +* @param vaddr +* Starting virtual address of memory to be unmapped. +* +* @param iova +* Starting IOVA address of memory to be unmapped. +* +* @param len +* Length of memory segment being unmapped. +* +* @return +* 0 if success. +* -1 on error. +*/ +int __rte_experimental +rte_vfio_dma_unmap (uint64_t vaddr,uint64_t iova,uint64_t len); + #ifdef __cplusplus }#endif
lib/librte_eal/linuxapp/eal/eal_vfio.c +272 -75
449 lines not on this page · raw message
lib/librte_eal/linuxapp/eal/eal_vfio.h +12 -0
@@ -19,6 +19,7 @@#ifdef VFIO_PRESENT +#include <stdint.h> #include <linux/vfio.h> #define RTE_VFIO_TYPE1 VFIO_TYPE1_IOMMU
@@ -26,6 +27,7 @@#ifndef VFIO_SPAPR_TCE_v2_IOMMU#define RTE_VFIO_SPAPR 7#define VFIO_IOMMU_SPAPR_REGISTER_MEMORY _IO(VFIO_TYPE, VFIO_BASE + 17) +#define VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY _IO(VFIO_TYPE, VFIO_BASE + 18)#define VFIO_IOMMU_SPAPR_TCE_CREATE _IO(VFIO_TYPE, VFIO_BASE + 19)#define VFIO_IOMMU_SPAPR_TCE_REMOVE _IO(VFIO_TYPE, VFIO_BASE + 20)
@@ -110,6 +112,7 @@ struct vfio_config {int vfio_enabled;int vfio_container_fd;int vfio_active_groups; +const struct vfio_iommu_type *vfio_iommu_type;struct vfio_group vfio_groups[VFIO_MAX_GROUPS ]; };
@@ -119,9 +122,18 @@ struct vfio_config {* */ typedef int (*vfio_dma_func_t )(int ); +/* Custom memory region DMA mapping function prototype. +* Takes VFIO container fd, virtual address, phisical address, length and +* operation type (0 to unmap 1 for map) as a parameters. +* Returns 0 on success, -1 on error. +**/ +typedef int (*vfio_dma_user_func_t )(int fd,uint64_t vaddr,uint64_t iova, +uint64_t len,int do_map); +struct vfio_iommu_type {int type_id;const char *name; +vfio_dma_user_func_t dma_user_map_func;vfio_dma_func_t dma_map_func; };
lib/librte_eal/rte_eal_version.map +2 -0
@@ -263,5 +263,7 @@ EXPERIMENTAL { rte_service_start_with_defaults; rte_socket_count; rte_socket_id_by_idx; + rte_vfio_dma_map; + rte_vfio_dma_unmap; } DPDK_18.02;
Signature · 1 line
2.7.4
PATCH v4 47/70 eal: add "legacy memory" option
In reply to Anatoly BurakovThis adds a "--legacy-mem" command-line switch. It will be used to go back to the old memory behavior, one where we can't dynamically allocate/free memory (the downside), but one where the user can get physically contiguous memory, like before (the upside).
For now, nothing but the legacy behavior exists, non-legacy memory init sequence will be added later. For FreeBSD, non-legacy memory init will never be enabled, while for Linux, it is disabled in this patch to avoid breaking bisect, but will be enabled once non-legacy mode will be fully operational.
---
Notes:
v3:
- Move to earlier in the patchset
- Make Linuxapp always load in legacy mode
lib/librte_eal/bsdapp/eal/eal.c | 3 +++ lib/librte_eal/common/eal_common_options.c | 4 ++++ lib/librte_eal/common/eal_internal_cfg.h | 4 ++++ lib/librte_eal/common/eal_options.h | 2 ++ lib/librte_eal/linuxapp/eal/eal.c | 3 +++ lib/librte_eal/linuxapp/eal/eal_memory.c | 24 ++++++++++++++++++++---- 6 files changed, 36 insertions(+), 4 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +3 -0
@@ -534,6 +534,9 @@ rte_eal_init(int argc, char **argv)return -1 ; } +/* FreeBSD always uses legacy memory model */ + internal_config.legacy_mem = true; +if (eal_plugins_init () <0 ) {rte_eal_init_alert ("Cannot init plugins\n" ); rte_errno =EINVAL ;
lib/librte_eal/common/eal_common_options.c +4 -0
@@ -73,6 +73,7 @@ eal_long_options[] = { {OPT_VDEV, 1, NULL, OPT_VDEV_NUM }, {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, + {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM }, {0, 0, NULL, 0 } };
@@ -1184,6 +1185,9 @@ eal_parse_common_option(int opt, const char *optarg, core_parsed =LCORE_OPT_MAP ;break ; +case OPT_LEGACY_MEM_NUM : + conf->legacy_mem =1 ; +break ;/* don't know what to do, leave this to caller */ default :
lib/librte_eal/common/eal_internal_cfg.h +4 -0
@@ -47,6 +47,10 @@ struct internal_config {volatile unsigned force_sockets;volatile uint64_t socket_mem[RTE_MAX_NUMA_NODES ];/**< amount of memory per socket */ uintptr_t base_virtaddr;/**< base address to try and reserve memory from */ +volatile unsigned legacy_mem; +/**< true to enable legacy memory behavior (no dynamic allocation, +* IOVA-contiguous segments). +*/ volatile int syslog_facility;/**< facility passed to openlog() */ /** default interrupt mode for VFIO */ volatile enum rte_intr_mode vfio_intr_mode;
lib/librte_eal/common/eal_options.h +2 -0
@@ -55,6 +55,8 @@ enum {OPT_VFIO_INTR_NUM , #define OPT_VMWARE_TSC_MAP "vmware-tsc-map"OPT_VMWARE_TSC_MAP_NUM , +#define OPT_LEGACY_MEM "legacy-mem" +OPT_LEGACY_MEM_NUM , OPT_LONG_MAX_NUM };
lib/librte_eal/linuxapp/eal/eal.c +3 -0
@@ -348,6 +348,7 @@ eal_usage(const char *prgname)" --" OPT_BASE_VIRTADDR " Base virtual address\n" " --" OPT_CREATE_UIO_DEV " Create /dev/uioX (usually done by hotplug)\n" " --" OPT_VFIO_INTR " Interrupt mode for VFIO (legacy|msi|msix)\n" +" --" OPT_LEGACY_MEM " Legacy memory mode (no dynamic allocation, contiguous segments)\n" "\n");/* Allow the application to print its usage message too if hook is set */ if ( rte_application_usage_hook ) {
@@ -767,6 +768,8 @@ rte_eal_init(int argc, char **argv)rte_atomic32_clear (&run_once);return -1 ; } +/* for now, always set legacy mem */ + internal_config.legacy_mem =1 ;if (eal_plugins_init () <0 ) {rte_eal_init_alert ("Cannot init plugins\n" );
lib/librte_eal/linuxapp/eal/eal_memory.c +20 -4
@@ -922,8 +922,8 @@ huge_recover_sigbus(void)* 6. unmap the first mapping * 7. fill memsegs in configuration with contiguous zones */ -int -rte_eal_hugepage_init (void ) +static int +eal_legacy_hugepage_init (void ) {struct rte_mem_config *mcfg;struct hugepage_file *hugepage =NULL , *tmp_hp =NULL ;
@@ -1266,8 +1266,8 @@ getFileSize(int fd)* configuration and finds the hugepages which form that segment, mapping them * in order to form a contiguous block in the virtual memory space */ -int -rte_eal_hugepage_attach (void ) +static int +eal_legacy_hugepage_attach (void ) {const struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config;struct hugepage_file *hp =NULL ;
@@ -1403,6 +1403,22 @@ rte_eal_hugepage_attach(void) }int +rte_eal_hugepage_init (void ) +{ +if (internal_config.legacy_mem) +return eal_legacy_hugepage_init (); +return -1 ; +} + +int +rte_eal_hugepage_attach (void ) +{ +if (internal_config.legacy_mem) +return eal_legacy_hugepage_attach (); +return -1 ; +} + +int rte_eal_using_phys_addrs (void ) {return phys_addrs_available;
Signature · 1 line
2.7.4
PATCH v4 48/70 eal: add rte_fbarray
In reply to Anatoly Burakovrte_fbarray is a simple indexed array stored in shared memory via mapping files into memory. Rationale for its existence is the
following: since we are going to map memory page-by-page, there could be quite a lot of memory segments to keep track of (for smaller page sizes, page count can easily reach thousands). We can't really make page lists truly dynamic and infinitely expandable, because that involves reallocating memory (which is a big no-no in multiprocess). What we can do instead is have a maximum capacity as something really, really large, and decide at allocation time how big the array is going to be. We map the entire file into memory, which makes it possible to use fbarray as shared memory, provided the structure itself is allocated in shared memory. Per-fbarray locking is also used to avoid index data races (but not contents data races - that is up to user application to synchronize).
In addition, in understanding that we will frequently need to scan this array for free space and iterating over array linearly can become slow, rte_fbarray provides facilities to index array's usage. The following use cases are covered:
- find next free/used slot (useful either for adding new elements to fbarray, or walking the list)
- find starting index for next N free/used slots (useful for when we want to allocate chunk of VA-contiguous memory composed of several pages)
- find how many contiguous free/used slots there are, starting from specified index (useful for when we want to figure out how many pages we have until next hole in allocated memory, to speed up some bulk operations where we would otherwise have to walk the array and add pages one by one)
This is accomplished by storing a usage mask in-memory, right after the data section of the array, and using some bit-level magic to figure out the info we need.
---
Notes:
v3:
- Fixed index alignment bug
- Fixed compile issues
v3:
- MAP_POPULATE not supported on FreeBSD, removed it
- Bugfix for index size when it is unaligned
- Replace uint64_t with size_t for mapping sizes
- Make API experimental
Initial version of this had resizing capability, however it was removed due to the fact that in multiprocess scenario, each fbarray would have its own view of mapped memory, which might not correspond with others due to some other process performing a resize that current process didn't know about.
It was therefore decided that to avoid cost of synchronization on each and every operation (to make sure the array wasn't resized), resizing feature should be dropped.
lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_fbarray.c | 859 ++++++++++++++++++++++++++++ lib/librte_eal/common/eal_filesystem.h | 13 + lib/librte_eal/common/include/rte_fbarray.h | 353 ++++++++++++ lib/librte_eal/common/meson.build | 2 + lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 16 + 8 files changed, 1246 insertions(+), 1 deletion(-) create mode 100644 lib/librte_eal/common/eal_common_fbarray.c create mode 100644 lib/librte_eal/common/include/rte_fbarray.h
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -53,6 +53,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_proc.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_fbarray.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c
lib/librte_eal/common/Makefile +1 -1
@@ -16,7 +16,7 @@ INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h INC += rte_malloc.h rte_keepalive.h rte_time.h INC += rte_service.h rte_service_component.h INC += rte_bitmap.h rte_vfio.h rte_hypervisor.h rte_test.h -INC += rte_reciprocal.h +INC += rte_reciprocal.h rte_fbarray.h GENERIC_INC := rte_atomic.h rte_byteorder.h rte_cycles.h rte_prefetch.h GENERIC_INC += rte_spinlock.h rte_memcpy.h rte_cpuflags.h rte_rwlock.h
lib/librte_eal/common/eal_common_fbarray.c new file +859 -0
859 lines not on this page · raw message
lib/librte_eal/common/eal_filesystem.h +13 -0
@@ -13,6 +13,7 @@/** Path of rte config file. */ #define RUNTIME_CONFIG_FMT "%s/.%s_config" +#define FBARRAY_FMT "%s/%s_%s"#include <stdint.h> #include <limits.h>
@@ -55,6 +56,18 @@ eal_mp_socket_path(void)return buffer; } +static inline const char * +eal_get_fbarray_path (char *buffer,size_t buflen,const char *name) { +const char *directory ="/tmp" ; +const char *home_dir =getenv ("HOME" ); + +if (getuid () !=0 && home_dir !=NULL ) + directory = home_dir; +snprintf (buffer, buflen -1 ,FBARRAY_FMT , directory, + internal_config.hugefile_prefix, name); +return buffer; +} +/** Path of hugepage info file. */ #define HUGEPAGE_INFO_FMT "%s/.%s_hugepage_info"
lib/librte_eal/common/include/rte_fbarray.h new file +353 -0
353 lines not on this page · raw message
lib/librte_eal/common/meson.build +2 -0
@@ -11,6 +11,7 @@ common_sources = files( 'eal_common_devargs.c', 'eal_common_dev.c', 'eal_common_errno.c', + 'eal_common_fbarray.c', 'eal_common_hexdump.c', 'eal_common_launch.c', 'eal_common_lcore.c',
@@ -51,6 +52,7 @@ common_headers = files( 'include/rte_eal_memconfig.h', 'include/rte_eal_interrupts.h', 'include/rte_errno.h', + 'include/rte_fbarray.h', 'include/rte_hexdump.h', 'include/rte_interrupts.h', 'include/rte_keepalive.h',
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -61,6 +61,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_proc.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_fbarray.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c
lib/librte_eal/rte_eal_version.map +16 -0
@@ -221,6 +221,22 @@ EXPERIMENTAL { rte_eal_hotplug_add; rte_eal_hotplug_remove; rte_eal_mbuf_user_pool_ops; + rte_fbarray_attach; + rte_fbarray_destroy; + rte_fbarray_detach; + rte_fbarray_dump_metadata; + rte_fbarray_find_idx; + rte_fbarray_find_next_free; + rte_fbarray_find_next_used; + rte_fbarray_find_next_n_free; + rte_fbarray_find_next_n_used; + rte_fbarray_find_contig_free; + rte_fbarray_find_contig_used; + rte_fbarray_get; + rte_fbarray_init; + rte_fbarray_is_used; + rte_fbarray_set_free; + rte_fbarray_set_used; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; rte_mem_iova2virt;
Signature · 1 line
2.7.4
PATCH v4 49/70 eal: replace memseg with memseg lists
In reply to Anatoly BurakovBefore, we were aggregating multiple pages into one memseg, so the number of memsegs was small. Now, each page gets its own memseg, so the list of memsegs is huge. To accommodate the new memseg list size and to keep the under-the-hood workings sane, the memseg list is now not just a single list, but multiple lists. To be precise, each hugepage size available on the system gets one or more memseg lists, per socket.
In order to support dynamic memory allocation, we reserve all memory in advance (unless we're in 32-bit legacy mode, in which case we do not preallocate memory). As in, we do an anonymous mmap() of the entire maximum size of memory per hugepage size, per socket (which is limited to either RTE_MAX_MEMSEG_PER_TYPE pages or RTE_MAX_MEM_MB_PER_TYPE megabytes worth of memory, whichever is the smaller one), split over multiple lists (which are limited to either RTE_MAX_MEMSEG_PER_LIST memsegs or RTE_MAX_MEM_MB_PER_LIST megabytes per list, whichever is the smaller one). There is also a global limit of CONFIG_RTE_MAX_MEM_MB megabytes, which is mainly used for 32-bit targets to limit amounts of preallocated memory, but can be used to place an upper limit on total amount of VA memory that can be allocated by DPDK application.
So, for each hugepage size, we get (by default) up to 128G worth of memory, per socket, split into chunks of up to 32G in size. The address space is claimed at the start, in eal_common_memory.c. The actual page allocation code is in eal_memalloc.c (Linux-only), and largely consists of copied EAL memory init code.
Pages in the list are also indexed by address. That is, in order to figure out where the page belongs, one can simply look at base address for a memseg list. Similarly, figuring out IOVA address of a memzone is a matter of finding the right memseg list, getting offset and dividing by page size to get the appropriate memseg.
This commit also removes rte_eal_dump_physmem_layout() call, according to deprecation notice [1], and removes that deprecation notice as well.
On 32-bit targets due to limited VA space, DPDK will no longer spread memory to different sockets like before. Instead, it will (by default) allocate all of the memory on socket where master lcore is. To override this behavior, --socket-mem must be used.
The rest of the changes are really ripple effects from the memseg change - heap changes, compile fixes, and rewrites to support fbarray-backed memseg lists. Due to earlier switch to _walk() functions, most of the changes are simple fixes, however some of the _walk() calls were switched to memseg list walk, where it made sense to do so.
Additionally, we are also switching locks from flock() to fcntl(). Down the line, we will be introducing single-file segments option, and we cannot use flock() locks to lock parts of the file. Therefore, we will use fcntl() locks for legacy mem as well, in case someone is unfortunate enough to accidentally start legacy mem primary process alongside an already working non-legacy mem-based primary process.
[1] http://dpdk.org/dev/patchwork/patch/34002/
---
Notes:
v4:
- Fixed bug in FreeBSD segment allocation
- Optimized iova2virt lookup for legacy mem case
v3:
- New and improved legacy mode, without (too much) crazy hacks
- 32-bit support
- FreeBSD support
- Compile fixes for all platforms
v3:
- New and improved legacy mode, without (too much) crazy hacks
- 32-bit support
- FreeBSD support
- Compile fixes for all platforms
config/common_base | 15 +- config/defconfig_i686-native-linuxapp-gcc | 3 + config/defconfig_i686-native-linuxapp-icc | 3 + config/defconfig_x86_x32-native-linuxapp-gcc | 3 + config/rte_config.h | 7 +- doc/guides/rel_notes/deprecation.rst | 9 - drivers/bus/fslmc/fslmc_vfio.c | 10 +- drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 2 +- drivers/bus/pci/linux/pci.c | 8 +- drivers/crypto/dpaa_sec/dpaa_sec.c | 2 +- drivers/net/mlx4/mlx4_mr.c | 4 +- drivers/net/mlx5/mlx5.c | 3 +- drivers/net/mlx5/mlx5_mr.c | 4 +- drivers/net/virtio/virtio_user/vhost_kernel.c | 4 +- lib/librte_eal/bsdapp/eal/eal.c | 12 +- lib/librte_eal/bsdapp/eal/eal_hugepage_info.c | 17 +- lib/librte_eal/bsdapp/eal/eal_memory.c | 207 ++++- lib/librte_eal/common/eal_common_memory.c | 602 +++++++++++--- lib/librte_eal/common/eal_common_memzone.c | 48 +- lib/librte_eal/common/eal_hugepages.h | 1 - lib/librte_eal/common/eal_internal_cfg.h | 2 +- lib/librte_eal/common/include/rte_eal_memconfig.h | 22 +- lib/librte_eal/common/include/rte_memory.h | 56 +- lib/librte_eal/common/include/rte_memzone.h | 1 - lib/librte_eal/common/malloc_elem.c | 12 +- lib/librte_eal/common/malloc_elem.h | 6 +- lib/librte_eal/common/malloc_heap.c | 62 +- lib/librte_eal/common/rte_malloc.c | 22 +- lib/librte_eal/linuxapp/eal/eal.c | 15 +- lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 25 +- lib/librte_eal/linuxapp/eal/eal_memory.c | 913 +++++++++++++++------- lib/librte_eal/linuxapp/eal/eal_vfio.c | 9 +- lib/librte_eal/rte_eal_version.map | 3 +- lib/librte_mempool/rte_mempool.c | 9 +- test/test/test_malloc.c | 30 +- test/test/test_memory.c | 10 +- test/test/test_memzone.c | 12 +- 37 files changed, 1583 insertions(+), 590 deletions(-)
config/common_base +14 -1
@@ -61,7 +61,20 @@ CONFIG_RTE_CACHE_LINE_SIZE=64 CONFIG_RTE_LIBRTE_EAL=y CONFIG_RTE_MAX_LCORE=128 CONFIG_RTE_MAX_NUMA_NODES=8 -CONFIG_RTE_MAX_MEMSEG=256 +CONFIG_RTE_MAX_MEMSEG_LISTS=64 +# each memseg list will be limited to either RTE_MAX_MEMSEG_PER_LIST pages +# or RTE_MAX_MEM_MB_PER_LIST megabytes worth of memory, whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_LIST=8192 +CONFIG_RTE_MAX_MEM_MB_PER_LIST=32768 +# a "type" is a combination of page size and NUMA node. total number of memseg +# lists per type will be limited to either RTE_MAX_MEMSEG_PER_TYPE pages (split +# over multiple lists of RTE_MAX_MEMSEG_PER_LIST pages), or +# RTE_MAX_MEM_MB_PER_TYPE megabytes of memory (split over multiple lists of +# RTE_MAX_MEM_MB_PER_LIST), whichever is smaller +CONFIG_RTE_MAX_MEMSEG_PER_TYPE=32768 +CONFIG_RTE_MAX_MEM_MB_PER_TYPE=131072 +# global maximum usable amount of VA, in megabytes +CONFIG_RTE_MAX_MEM_MB=524288 CONFIG_RTE_MAX_MEMZONE=2560 CONFIG_RTE_MAX_TAILQ=32 CONFIG_RTE_ENABLE_ASSERT=n
config/defconfig_i686-native-linuxapp-gcc +3 -0
@@ -46,3 +46,6 @@ CONFIG_RTE_LIBRTE_PMD_ZUC=n # AVP PMD is not supported on 32-bit # CONFIG_RTE_LIBRTE_AVP_PMD=n + +# 32-bit doesn't break up memory in lists, but does have VA allocation limit +CONFIG_RTE_MAX_MEM_MB=2048
config/defconfig_i686-native-linuxapp-icc +3 -0
@@ -51,3 +51,6 @@ CONFIG_RTE_LIBRTE_PMD_ZUC=n # AVP PMD is not supported on 32-bit # CONFIG_RTE_LIBRTE_AVP_PMD=n + +# 32-bit doesn't break up memory in lists, but does have VA allocation limit +CONFIG_RTE_MAX_MEM_MB=2048
config/defconfig_x86_x32-native-linuxapp-gcc +3 -0
@@ -26,3 +26,6 @@ CONFIG_RTE_LIBRTE_SFC_EFX_PMD=n # AVP PMD is not supported on 32-bit # CONFIG_RTE_LIBRTE_AVP_PMD=n + +# 32-bit doesn't break up memory in lists, but does have VA allocation limit +CONFIG_RTE_MAX_MEM_MB=2048
config/rte_config.h +6 -1
@@ -21,7 +21,12 @@/****** library defines ********/ /* EAL defines */ -#define RTE_MAX_MEMSEG 512 +#define RTE_MAX_MEMSEG_LISTS 128 +#define RTE_MAX_MEMSEG_PER_LIST 8192 +#define RTE_MAX_MEM_MB_PER_LIST 32768 +#define RTE_MAX_MEMSEG_PER_TYPE 32768 +#define RTE_MAX_MEM_MB_PER_TYPE 65536 +#define RTE_MAX_MEM_MB 524288#define RTE_MAX_MEMZONE 2560#define RTE_MAX_TAILQ 32#define RTE_LOG_DP_LEVEL RTE_LOG_INFO
doc/guides/rel_notes/deprecation.rst +0 -9
@@ -38,15 +38,6 @@ Deprecation Notices success and failure, respectively. This will change to 1 and 0 for true and false, respectively, to make use of the function more intuitive. -* eal: due to internal data layout reorganization, there will be changes to - several structures and functions as a result of coming changes to support - memory hotplug in v18.05. - ``rte_eal_get_physmem_layout`` will be deprecated and removed in subsequent - releases. - ``rte_mem_config`` contents will change due to switch to memseg lists. - ``rte_memzone`` member ``memseg_id`` will no longer serve any useful purpose - and will be removed. - * eal: a new set of mbuf mempool ops name APIs for user, platform and best mempool names have been defined in ``rte_mbuf`` in v18.02. The uses of ``rte_eal_mbuf_default_mempool_ops`` shall be replaced by
drivers/bus/fslmc/fslmc_vfio.c +2 -8
@@ -190,7 +190,8 @@ static int vfio_map_irq_region(struct fslmc_vfio_group *group) }static int -fslmc_vfio_map (const struct rte_memseg *ms,void *arg) +fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) {int *n_segs = arg;struct fslmc_vfio_group *group;
@@ -232,18 +233,11 @@ fslmc_vfio_map(const struct rte_memseg *ms, void *arg)int rte_fslmc_vfio_dmamap (void ) { -const struct rte_memseg *memseg;int i =0 ;if (is_dma_done)return 0 ; - memseg =rte_eal_get_physmem_layout (); -if (memseg ==NULL ) { -DPAA2_BUS_ERR ("Cannot get physical layout" ); -return -ENODEV ; - } -if (rte_memseg_walk (fslmc_vfio_map, &i) <0 )return -1 ;
drivers/bus/fslmc/portal/dpaa2_hw_pvt.h +1 -1
@@ -274,7 +274,7 @@ static phys_addr_t dpaa2_mem_vtop(uint64_t vaddr)if (dpaa2_virt_mode)return vaddr; - memseg =rte_mem_virt2memseg ((void *)(uintptr_t )vaddr); + memseg =rte_mem_virt2memseg ((void *)(uintptr_t )vaddr,NULL );if (memseg)return memseg->phys_addr +RTE_PTR_DIFF (vaddr, memseg->addr);return (size_t )NULL ;
drivers/bus/pci/linux/pci.c +5 -3
@@ -117,9 +117,10 @@ rte_pci_unmap_device(struct rte_pci_device *dev) }static int -find_max_end_va (const struct rte_memseg *ms,void *arg) +find_max_end_va (const struct rte_memseg_list *msl,void *arg) { -void *end_va =RTE_PTR_ADD (ms->addr, ms->len); +size_t sz = msl->memseg_arr.len * msl->page_sz; +void *end_va =RTE_PTR_ADD (msl->base_va, sz);void **max_va = arg;if (*max_va < end_va)
@@ -132,10 +133,11 @@ pci_find_max_end_va(void) {void *va =NULL ; -rte_memseg_walk (find_max_end_va, &va); +rte_memseg_list_walk (find_max_end_va, &va);return va; } +/* parse one line of the "resource" sysfs file (note that the 'line' * string is modified) */
drivers/crypto/dpaa_sec/dpaa_sec.c +1 -1
@@ -95,7 +95,7 @@ dpaa_mem_vtop(void *vaddr) {const struct rte_memseg *ms; - ms =rte_mem_virt2memseg (vaddr); + ms =rte_mem_virt2memseg (vaddr,NULL );if (ms)return ms->iova +RTE_PTR_DIFF (vaddr, ms->addr);return (size_t )NULL ;
drivers/net/mlx4/mlx4_mr.c +2 -2
@@ -142,10 +142,10 @@ mlx4_mr_get(struct priv *priv, struct rte_mempool *mp) (void *)mp, (void *)start, (void *)end, (size_t)(end - start));/* Round start and end to page boundary if found in memory segments. */ - ms =rte_mem_virt2memseg ((void *)start); + ms =rte_mem_virt2memseg ((void *)start,NULL );if (ms !=NULL ) start =RTE_ALIGN_FLOOR (start, ms->hugepage_sz); - ms =rte_mem_virt2memseg ((void *)end); + ms =rte_mem_virt2memseg ((void *)end,NULL );if (ms !=NULL ) end =RTE_ALIGN_CEIL (end, ms->hugepage_sz);
drivers/net/mlx5/mlx5.c +2 -1
@@ -478,7 +478,8 @@ static struct rte_pci_driver mlx5_driver;static void *uar_base;static int -find_lower_va_bound (const struct rte_memseg *ms,void *arg) +find_lower_va_bound(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) {void **addr = arg;
drivers/net/mlx5/mlx5_mr.c +2 -2
@@ -263,10 +263,10 @@ mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp) mr->end = end;/* Round start and end to page boundary if found in memory segments. */ - ms =rte_mem_virt2memseg ((void *)start); + ms =rte_mem_virt2memseg ((void *)start,NULL );if (ms !=NULL ) start =RTE_ALIGN_FLOOR (start, ms->hugepage_sz); - ms =rte_mem_virt2memseg ((void *)end); + ms =rte_mem_virt2memseg ((void *)end,NULL );if (ms !=NULL ) end =RTE_ALIGN_CEIL (end, ms->hugepage_sz);
drivers/net/virtio/virtio_user/vhost_kernel.c +2 -2
@@ -75,7 +75,8 @@ struct walk_arg {uint32_t region_nr; };static int -add_memory_region (const struct rte_memseg *ms,size_t len,void *arg) +add_memory_region(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,size_t len,void *arg) {struct walk_arg *wa = arg;struct vhost_memory_region *mr;
@@ -95,7 +96,6 @@ add_memory_region(const struct rte_memseg *ms, size_t len, void *arg)return 0 ; } -/* By default, vhost kernel module allows 64 regions, but DPDK allows * 256 segments. As a relief, below function merges those virtually * adjacent memsegs into one region.
lib/librte_eal/bsdapp/eal/eal.c +6 -6
@@ -64,8 +64,8 @@ static int mem_cfg_fd = -1;static struct flock wr_lock = { .l_type =F_WRLCK , .l_whence =SEEK_SET , - .l_start = offsetof(struct rte_mem_config , memseg), - .l_len =sizeof (early_mem_config.memseg), + .l_start = offsetof(struct rte_mem_config , memsegs), + .l_len =sizeof (early_mem_config.memsegs), };/* Address of global and public configuration */
@@ -430,11 +430,11 @@ eal_parse_args(int argc, char **argv) }static int -check_socket (const struct rte_memseg *ms,void *arg) +check_socket (const struct rte_memseg_list *msl,void *arg) {int *socket_id = arg; -if (ms->socket_id == *socket_id) +if (msl->socket_id == *socket_id && msl->memseg_arr.count !=0 )return 1 ;return 0 ;
@@ -447,10 +447,11 @@ eal_check_mem_on_local_socket(void) socket_id =rte_lcore_to_socket_id (rte_config.master_lcore); -if (rte_memseg_walk (check_socket, &socket_id) ==0 ) +if (rte_memseg_list_walk (check_socket, &socket_id) ==0 )RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no memory on local socket!\n" ); } +static int sync_func (__attribute__((unused))void *arg) {
@@ -561,7 +562,6 @@ rte_eal_init(int argc, char **argv)rte_eal_get_configuration ()->iova_mode =rte_bus_get_iommu_class ();if (internal_config.no_hugetlbfs ==0 && - internal_config.process_type !=RTE_PROC_SECONDARY &&eal_hugepage_info_init () <0 ) {rte_eal_init_alert ("Cannot get hugepage information." ); rte_errno =EACCES ;
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +11 -6
@@ -47,12 +47,18 @@ eal_hugepage_info_init(void)struct hugepage_info *hpi = &internal_config.hugepage_info[0 ];struct hugepage_info *tmp_hpi; + internal_config.num_hugepage_sizes =1 ; + +/* nothing more to be done for secondary */ +if (rte_eal_process_type () ==RTE_PROC_SECONDARY ) +return 0 ; + sysctl_size =sizeof (num_buffers); error =sysctlbyname ("hw.contigmem.num_buffers" , &num_buffers, &sysctl_size,NULL ,0 );if (error !=0 ) { -RTE_LOG (ERR ,EAL ,"could not read sysctl hw.contigmem.num_buffers" ); +RTE_LOG (ERR ,EAL ,"could not read sysctl hw.contigmem.num_buffers\n" );return -1 ; }
@@ -61,7 +67,7 @@ eal_hugepage_info_init(void) &sysctl_size, NULL, 0);if (error !=0 ) { -RTE_LOG (ERR ,EAL ,"could not read sysctl hw.contigmem.buffer_size" ); +RTE_LOG (ERR ,EAL ,"could not read sysctl hw.contigmem.buffer_size\n" );return -1 ; }
@@ -81,22 +87,21 @@ eal_hugepage_info_init(void)RTE_LOG (INFO ,EAL ,"Contigmem driver has %d buffers, each of size %dKB\n" , num_buffers, (int )(buffer_size>>10 )); - internal_config.num_hugepage_sizes =1 ; hpi->hugedir =CONTIGMEM_DEV ; hpi->hugepage_sz = buffer_size; hpi->num_pages[0 ] = num_buffers; hpi->lock_descriptor = fd; tmp_hpi =create_shared_memory (eal_hugepage_info_path (), -sizeof (struct hugepage_info )); +sizeof (internal_config.hugepage_info));if (tmp_hpi ==NULL ) {RTE_LOG (ERR ,EAL ,"Failed to create shared memory!\n" );return -1 ; } -memcpy (tmp_hpi, hpi,sizeof (struct hugepage_info )); +memcpy (tmp_hpi, hpi,sizeof (internal_config.hugepage_info)); -if (munmap (tmp_hpi,sizeof (struct hugepage_info )) <0 ) { +if (munmap (tmp_hpi,sizeof (internal_config.hugepage_info)) <0 ) {RTE_LOG (ERR ,EAL ,"Failed to unmap shared memory!\n" );return -1 ; }
lib/librte_eal/bsdapp/eal/eal_memory.c +168 -39
285 lines not on this page · raw message
lib/librte_eal/common/eal_common_memory.c +515 -87
705 lines not on this page · raw message
lib/librte_eal/common/eal_common_memzone.c +35 -13
84 lines not on this page · raw message
lib/librte_eal/common/eal_hugepages.h +0 -1
@@ -22,7 +22,6 @@ struct hugepage_file {size_t size;/**< the page size */ int socket_id;/**< NUMA socket ID */ int file_id;/**< the '%d' in HUGEFILE_FMT */ -int memseg_id;/**< the memory segment to which page belongs */ char filepath[MAX_HUGEPAGE_PATH ];/**< path to backing file on filesystem */ };
lib/librte_eal/common/eal_internal_cfg.h +1 -1
@@ -23,7 +23,7 @@ struct hugepage_info {uint64_t hugepage_sz;/**< size of a huge page */ const char *hugedir;/**< dir where hugetlbfs is mounted */ uint32_t num_pages[RTE_MAX_NUMA_NODES ]; -/**< number of hugepages of that size on each socket */ +/**< number of hugepages of that size on each socket */ int lock_descriptor;/**< file descriptor for hugepage dir */ };
lib/librte_eal/common/include/rte_eal_memconfig.h +21 -1
@@ -12,12 +12,30 @@#include <rte_malloc_heap.h> #include <rte_rwlock.h> #include <rte_pause.h> +#include <rte_fbarray.h> #ifdef __cplusplus extern "C" { #endif /** + * memseg list is a special case as we need to store a bunch of other data + * together with the array itself. + */ +struct rte_memseg_list { + RTE_STD_C11 + union { + void *base_va; + /**< Base virtual address for this memseg list. */ + uint64_t addr_64; + /**< Makes sure addr is always 64-bits */ + }; + int socket_id; /**< Socket ID for all memsegs in this list. */ + uint64_t page_sz; /**< Page size for all memsegs in this list. */ + struct rte_fbarray memseg_arr; +}; + +/** * the structure for the memory configuration for the RTE. * Used by the rte_config structure. It is separated out, as for multi-process * support, the memory details should be shared across instances
@@ -43,9 +61,11 @@ struct rte_mem_config {uint32_t memzone_cnt;/**< Number of allocated memzones */ /* memory segments and zones */ -struct rte_memseg memseg[RTE_MAX_MEMSEG ];/**< Physmem descriptors. */ struct rte_memzone memzone[RTE_MAX_MEMZONE ];/**< Memzone descriptors. */ +struct rte_memseg_list memsegs[RTE_MAX_MEMSEG_LISTS ]; +/**< list of dynamic arrays holding memsegs */ +struct rte_tailq_head tailq_head[RTE_MAX_TAILQ ];/**< Tailqs for objects */ /* Heaps of Malloc per socket */
lib/librte_eal/common/include/rte_memory.h +40 -16
89 lines not on this page · raw message
lib/librte_eal/common/include/rte_memzone.h +0 -1
@@ -68,7 +68,6 @@ struct rte_memzone {int32_t socket_id;/**< NUMA socket ID. */ uint32_t flags;/**< Characteristics of this memzone. */ -uint32_t memseg_id;/**< Memseg it belongs. */ } __attribute__((__packed__));/**
lib/librte_eal/common/malloc_elem.c +6 -6
@@ -27,11 +27,11 @@* Initialize a general malloc_elem header structure */ void -malloc_elem_init (struct malloc_elem *elem, -struct malloc_heap *heap,const struct rte_memseg *ms,size_t size) +malloc_elem_init (struct malloc_elem *elem,struct malloc_heap *heap, +struct rte_memseg_list *msl,size_t size) { elem->heap = heap; - elem->ms = ms; + elem->msl = msl; elem->prev =NULL ; elem->next =NULL ;memset (&elem->free_list,0 ,sizeof (elem->free_list));
@@ -100,7 +100,7 @@ malloc_elem_insert(struct malloc_elem *elem)* so we just check the page addresses. */ static bool -elem_check_phys_contig(const struct rte_memseg *ms __rte_unused, +elem_check_phys_contig(const struct rte_memseg_list *msl __rte_unused,void *start,size_t size) {rte_iova_t cur, expected;
@@ -191,7 +191,7 @@ elem_start_pt(struct malloc_elem *elem, size_t size, unsigned align,* couldn't fit all data into one physically contiguous * block, try again with lower addresses. */ -if (!elem_check_phys_contig (elem->ms, +if (!elem_check_phys_contig (elem->msl, (void *)new_data_start, new_data_size)) { elem_size -= align;
@@ -225,7 +225,7 @@ split_elem(struct malloc_elem *elem, struct malloc_elem *split_pt)const size_t old_elem_size = (uintptr_t )split_pt - (uintptr_t )elem;const size_t new_elem_size = elem->size - old_elem_size; -malloc_elem_init (split_pt, elem->heap, elem->ms, new_elem_size); +malloc_elem_init (split_pt, elem->heap, elem->msl, new_elem_size); split_pt->prev = elem; split_pt->next = next_elem;if (next_elem)
lib/librte_eal/common/malloc_elem.h +3 -3
@@ -7,7 +7,7 @@#include <stdbool.h> -#include <rte_memory.h> +#include <rte_eal_memconfig.h> /* dummy definition of struct so we can use pointers to it in malloc_elem struct */ struct malloc_heap ;
@@ -26,7 +26,7 @@ struct malloc_elem {/**< points to next elem in memseg */ LIST_ENTRY (malloc_elem) free_list;/**< list of free elements in heap */ -const struct rte_memseg *ms; +struct rte_memseg_list *msl;volatile enum elem_state state;uint32_t pad;size_t size;
@@ -113,7 +113,7 @@ malloc_elem_from_data(const void *data)void malloc_elem_init (struct malloc_elem *elem,struct malloc_heap *heap, -const struct rte_memseg *ms, +struct rte_memseg_list *msl,size_t size);void
lib/librte_eal/common/malloc_heap.c +38 -24
94 lines not on this page · raw message
lib/librte_eal/common/rte_malloc.c +13 -9
@@ -242,17 +242,21 @@ rte_malloc_set_limit(__rte_unused const char *type,rte_iova_t rte_malloc_virt2iova (const void *addr) { -rte_iova_t iova; -const struct malloc_elem *elem =malloc_elem_from_data (addr); +const struct rte_memseg *ms; +struct malloc_elem *elem =malloc_elem_from_data (addr); +if (elem ==NULL )return RTE_BAD_IOVA ; -if (elem->ms->iova ==RTE_BAD_IOVA ) -return RTE_BAD_IOVA ;if (rte_eal_iova_mode () ==RTE_IOVA_VA ) - iova = (uintptr_t )addr; -else - iova = elem->ms->iova + -RTE_PTR_DIFF (addr, elem->ms->addr); -return iova; +return (uintptr_t ) addr; + + ms =rte_mem_virt2memseg (addr, elem->msl); +if (ms ==NULL ) +return RTE_BAD_IOVA ; + +if (ms->iova ==RTE_BAD_IOVA ) +return RTE_BAD_IOVA ; + +return ms->iova +RTE_PTR_DIFF (addr, ms->addr); }
lib/librte_eal/linuxapp/eal/eal.c +9 -6
@@ -74,8 +74,8 @@ static int mem_cfg_fd = -1;static struct flock wr_lock = { .l_type =F_WRLCK , .l_whence =SEEK_SET , - .l_start = offsetof(struct rte_mem_config , memseg), - .l_len =sizeof (early_mem_config.memseg), + .l_start = offsetof(struct rte_mem_config , memsegs), + .l_len =sizeof (early_mem_config.memsegs), };/* Address of global and public configuration */
@@ -640,11 +640,14 @@ eal_parse_args(int argc, char **argv) }static int -check_mem (const struct rte_memseg *ms,void *arg) +check_socket (const struct rte_memseg_list *msl,void *arg) { -int *socket = arg; +int *socket_id = arg; -return ms->socket_id == *socket; +if (msl->socket_id == *socket_id && msl->memseg_arr.count !=0 ) +return 1 ; + +return 0 ; } static void
@@ -654,7 +657,7 @@ eal_check_mem_on_local_socket(void) socket_id =rte_lcore_to_socket_id (rte_config.master_lcore); -if (rte_memseg_walk (check_mem, &socket_id) ==0 ) +if (rte_memseg_list_walk (check_socket, &socket_id) ==0 )RTE_LOG (WARNING ,EAL ,"WARNING: Master core has no memory on local socket!\n" ); }
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +23 -2
@@ -15,6 +15,7 @@#include <unistd.h> #include <errno.h> #include <sys/queue.h> +#include <sys/stat.h> #include <rte_memory.h> #include <rte_eal.h>
@@ -160,6 +161,18 @@ get_hugepage_dir(uint64_t hugepage_sz) }/* +* uses fstat to report the size of a file on disk +*/ +static off_t +get_file_size (int fd) +{ +struct stat st; +if (fstat (fd, &st) <0 ) +return 0 ; +return st.st_size; +} + +/* * Clear the hugepage directory of whatever hugepage files * there are. Checks if the file is locked (i.e. * if it's in use by another DPDK process).
@@ -189,6 +202,8 @@ clear_hugedir(const char * hugedir) }while (dirent !=NULL ){ +struct flock lck = {0 }; +/* skip files that don't match the hugepage pattern */ if (fnmatch (filter, dirent->d_name,0 ) >0 ) { dirent =readdir (dir);
@@ -205,11 +220,17 @@ clear_hugedir(const char * hugedir) }/* non-blocking lock */ - lck_result =flock (fd,LOCK_EX |LOCK_NB ); + lck.l_type =F_RDLCK ; + lck.l_whence =SEEK_SET ; + lck.l_start =0 ; + lck.l_len =get_file_size (fd); + + lck_result =fcntl (fd,F_SETLK , &lck);/* if lock succeeds, unlock and remove the file */ if (lck_result !=-1 ) { -flock (fd,LOCK_UN ); + lck.l_type =F_UNLCK ; +fcntl (fd,F_SETLK , &lck);unlinkat (dir_fd, dirent->d_name,0 ); }close (fd);
lib/librte_eal/linuxapp/eal/eal_memory.c +615 -298
1,111 lines not on this page · raw message
lib/librte_eal/linuxapp/eal/eal_vfio.c +6 -3
@@ -686,7 +686,8 @@ vfio_get_group_no(const char *sysfs_base, }static int -type1_map (const struct rte_memseg *ms,void *arg) +type1_map(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) {int *vfio_container_fd = arg;
@@ -799,7 +800,8 @@ vfio_spapr_dma_do_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova, }static int -vfio_spapr_map_walk (const struct rte_memseg *ms,void *arg) +vfio_spapr_map_walk(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) {int *vfio_container_fd = arg;
@@ -812,7 +814,8 @@ struct spapr_walk_param {uint64_t hugepage_sz; };static int -vfio_spapr_window_size_walk (const struct rte_memseg *ms,void *arg) +vfio_spapr_window_size_walk(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) {struct spapr_walk_param *param = arg;uint64_t max = ms->iova + ms->len;
lib/librte_eal/rte_eal_version.map +2 -1
@@ -25,7 +25,6 @@ DPDK_2.0 { rte_eal_devargs_type_count; rte_eal_get_configuration; rte_eal_get_lcore_state; - rte_eal_get_physmem_layout; rte_eal_get_physmem_size; rte_eal_has_hugepages; rte_eal_hpet_init;
@@ -241,7 +240,9 @@ EXPERIMENTAL { rte_malloc_dump_heaps; rte_mem_iova2virt; rte_mem_virt2memseg; + rte_mem_virt2memseg_list; rte_memseg_contig_walk; + rte_memseg_list_walk; rte_memseg_walk; rte_mp_action_register; rte_mp_action_unregister;
lib/librte_mempool/rte_mempool.c +5 -4
@@ -100,12 +100,12 @@ static unsigned optimize_object_size(unsigned obj_size) }static int -find_min_pagesz (const struct rte_memseg *ms,void *arg) +find_min_pagesz (const struct rte_memseg_list *msl,void *arg) {size_t *min = arg; -if (ms->hugepage_sz < *min) - *min = ms->hugepage_sz; +if (msl->page_sz < *min) + *min = msl->page_sz;return 0 ; }
@@ -115,11 +115,12 @@ get_min_page_size(void) {size_t min_pagesz =SIZE_MAX ; -rte_memseg_walk (find_min_pagesz, &min_pagesz); +rte_memseg_list_walk (find_min_pagesz, &min_pagesz);return min_pagesz ==SIZE_MAX ? (size_t )getpagesize () : min_pagesz; } +static void mempool_add_elem (struct rte_mempool *mp,void *obj,rte_iova_t iova) {
test/test/test_malloc.c +7 -23
@@ -12,6 +12,7 @@#include <rte_common.h> #include <rte_memory.h> +#include <rte_eal_memconfig.h> #include <rte_per_lcore.h> #include <rte_launch.h> #include <rte_eal.h>
@@ -706,36 +707,20 @@ test_malloc_bad_params(void) }static int -check_socket_mem (const struct rte_memseg *ms,void *arg) +check_socket_mem (const struct rte_memseg_list *msl,void *arg) {int32_t *socket = arg; -return *socket == ms->socket_id; +return *socket == msl->socket_id; }/* Check if memory is available on a specific socket */ static int is_mem_on_socket (int32_t socket) { -return rte_memseg_walk (check_socket_mem, &socket); +return rte_memseg_list_walk (check_socket_mem, &socket); } -struct walk_param { -void *addr; -int32_t socket; -}; -static int -find_socket (const struct rte_memseg *ms,void *arg) -{ -struct walk_param *param = arg; - -if (param->addr >= ms->addr && - param->addr <RTE_PTR_ADD (ms->addr, ms->len)) { - param->socket = ms->socket_id; -return 1 ; - }
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.7.4
Part of the diff is not shown here. View the raw message.
PATCH v4 50/70 eal: replace memzone array with fbarray
In reply to Anatoly BurakovIt's there, so we might as well use it. Some operations will be sped up by that.
Since we have to allocate an fbarray for memzones, we have to do it before we initialize memory subsystem, because that, in secondary processes, will (later) allocate more fbarrays than the primary process, which will result in inability to attach to memzone fbarray if we do it after the fact.
---
Notes:
v4:
- Fix bug in memzone lookup iteraion code
v4:
- Fix memzone lookup skipping over memzones
- Fix error message on failing to find space for memzone
v3:
- Moved earlier in patchset
- Fixed compiled issues
- Removed rte_panic() calls
drivers/net/ena/Makefile | 3 + drivers/net/ena/ena_ethdev.c | 10 +- lib/librte_eal/bsdapp/eal/eal.c | 14 ++- lib/librte_eal/common/eal_common_memzone.c | 113 ++++++++++++---------- lib/librte_eal/common/include/rte_eal_memconfig.h | 4 +- lib/librte_eal/common/malloc_heap.c | 4 + lib/librte_eal/linuxapp/eal/eal.c | 13 ++- test/test/test_memzone.c | 9 +- 8 files changed, 103 insertions(+), 67 deletions(-)
drivers/net/ena/Makefile +3 -0
@@ -43,6 +43,9 @@ INCLUDES :=-I$(SRCDIR) -I$(SRCDIR)/base/ena_defs -I$(SRCDIR)/base EXPORT_MAP := rte_pmd_ena_version.map LIBABIVER := 1 +# rte_fbarray is not yet part of stable API +CFLAGS += -DALLOW_EXPERIMENTAL_API + VPATH += $(SRCDIR)/base # # all source are stored in SRCS-y
drivers/net/ena/ena_ethdev.c +7 -3
@@ -264,11 +264,15 @@ static const struct eth_dev_ops ena_dev_ops = {static inline int ena_cpu_to_node (int cpu) {struct rte_config *config =rte_eal_get_configuration (); +struct rte_fbarray *arr = &config->mem_config->memzones; +const struct rte_memzone *mz; -if (likely (cpu <RTE_MAX_MEMZONE )) -return config->mem_config->memzone[cpu].socket_id; +if (unlikely (cpu >=RTE_MAX_MEMZONE )) +return NUMA_NO_NODE ; -return NUMA_NO_NODE ; + mz =rte_fbarray_get (arr, cpu); + +return mz->socket_id; } static inline void ena_rx_mbuf_prepare(struct rte_mbuf *mbuf,
lib/librte_eal/bsdapp/eal/eal.c +12 -2
@@ -599,14 +599,24 @@ rte_eal_init(int argc, char **argv) } } +/* in secondary processes, memory init may allocate additional fbarrays +* not present in primary processes, so to avoid any potential issues, +* initialize memzones first. +*/ +if (rte_eal_memzone_init () <0 ) { +rte_eal_init_alert ("Cannot init memzone\n" ); + rte_errno =ENODEV ; +return -1 ; + } +if (rte_eal_memory_init () <0 ) {rte_eal_init_alert ("Cannot init memory\n" ); rte_errno =ENOMEM ;return -1 ; } -if (rte_eal_memzone_init () <0 ) { -rte_eal_init_alert ("Cannot init memzone\n" ); +if (rte_eal_malloc_heap_init () <0 ) { +rte_eal_init_alert ("Cannot init malloc heap\n" ); rte_errno =ENODEV ;return -1 ; }
lib/librte_eal/common/eal_common_memzone.c +60 -53
208 lines not on this page · raw message
lib/librte_eal/common/include/rte_eal_memconfig.h +1 -3
@@ -58,10 +58,8 @@ struct rte_mem_config {rte_rwlock_t qlock;/**< used for tailq operation for thread safe. */ rte_rwlock_t mplock;/**< only used by mempool LIB for thread-safe. */ -uint32_t memzone_cnt;/**< Number of allocated memzones */ -/* memory segments and zones */ -struct rte_memzone memzone[RTE_MAX_MEMZONE ];/**< Memzone descriptors. */ +struct rte_fbarray memzones;/**< Memzone descriptors. */ struct rte_memseg_list memsegs[RTE_MAX_MEMSEG_LISTS ];/**< list of dynamic arrays holding memsegs */
lib/librte_eal/common/malloc_heap.c +4 -0
@@ -278,6 +278,10 @@ rte_eal_malloc_heap_init(void)if (mcfg ==NULL )return -1 ; +/* secondary process does not need to initialize anything */ +if (rte_eal_process_type () !=RTE_PROC_PRIMARY ) +return 0 ; +/* add all IOVA-contiguous areas to the heap */ return rte_memseg_contig_walk (malloc_add_seg,NULL ); }
lib/librte_eal/linuxapp/eal/eal.c +11 -2
@@ -858,6 +858,15 @@ rte_eal_init(int argc, char **argv) return -1; }#endif +/* in secondary processes, memory init may allocate additional fbarrays +* not present in primary processes, so to avoid any potential issues, +* initialize memzones first. +*/ +if (rte_eal_memzone_init () <0 ) { +rte_eal_init_alert ("Cannot init memzone\n" ); + rte_errno =ENODEV ; +return -1 ; + }if (rte_eal_memory_init () <0 ) {rte_eal_init_alert ("Cannot init memory\n" );
@@ -868,8 +877,8 @@ rte_eal_init(int argc, char **argv)/* the directories are locked during eal_hugepage_info_init */ eal_hugedirs_unlock (); -if (rte_eal_memzone_init () <0 ) { -rte_eal_init_alert ("Cannot init memzone\n" ); +if (rte_eal_malloc_heap_init () <0 ) { +rte_eal_init_alert ("Cannot init malloc heap\n" ); rte_errno =ENODEV ;return -1 ; }
test/test/test_memzone.c +5 -4
@@ -909,7 +909,7 @@ test_memzone_basic(void)const struct rte_memzone *mz;int memzone_cnt_after, memzone_cnt_expected;int memzone_cnt_before = -rte_eal_get_configuration ()->mem_config->memzone_cnt; +rte_eal_get_configuration ()->mem_config->memzones.count; memzone1 =rte_memzone_reserve (TEST_MEMZONE_NAME ("testzone1" ),100 ,SOCKET_ID_ANY ,0 );
@@ -933,7 +933,7 @@ test_memzone_basic(void) (memzone3 !=NULL ) + (memzone4 !=NULL ); memzone_cnt_after = -rte_eal_get_configuration ()->mem_config->memzone_cnt; +rte_eal_get_configuration ()->mem_config->memzones.count;if (memzone_cnt_after != memzone_cnt_expected)return -1 ;
@@ -1012,7 +1012,7 @@ test_memzone_basic(void) } memzone_cnt_after = -rte_eal_get_configuration ()->mem_config->memzone_cnt; +rte_eal_get_configuration ()->mem_config->memzones.count;if (memzone_cnt_after != memzone_cnt_before)return -1 ;
@@ -1033,7 +1033,8 @@ static inttest_memzone (void) {/* take note of how many memzones were allocated before running */ -int memzone_cnt =rte_eal_get_configuration ()->mem_config->memzone_cnt; +int memzone_cnt = +rte_eal_get_configuration ()->mem_config->memzones.count;printf ("test basic memzone API\n" );if (test_memzone_basic () <0 )
Signature · 1 line
2.7.4
PATCH v4 51/70 eal: add support for mapping hugepages at runtime
In reply to Anatoly BurakovNothing uses this code yet. The bulk of it is copied from old memory allocation code (linuxapp eal_memory.c). We provide an EAL-internal API to allocate either one page or multiple pages, guaranteeing that we'll get contiguous VA for all of the pages that we requested.
Not supported on FreeBSD.
Locking is done via fcntl() because that way, when it comes to taking out write locks or unlocking on deallocation, we don't have to keep original fd's around. Plus, using fcntl() gives us ability to lock parts of a file, which is useful for single-file segments, which are coming down the line.
---
Notes:
v3:
- Compile fixes for various platforms
- Split single file segments stuff into separate commit
v3:
- Split single file segments into separate patch
- Added missing FreeBSD implementation
- Removed rte_panic when unable to free page
v3:
- Added single file segments functionality in this commit, instead of later commits
lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/bsdapp/eal/eal_memalloc.c | 26 ++ lib/librte_eal/bsdapp/eal/meson.build | 1 + lib/librte_eal/common/eal_memalloc.h | 31 +++ lib/librte_eal/linuxapp/eal/Makefile | 2 + lib/librte_eal/linuxapp/eal/eal_memalloc.c | 429 +++++++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/meson.build | 1 + 7 files changed, 491 insertions(+) create mode 100644 lib/librte_eal/bsdapp/eal/eal_memalloc.c create mode 100644 lib/librte_eal/common/eal_memalloc.h create mode 100644 lib/librte_eal/linuxapp/eal/eal_memalloc.c
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -29,6 +29,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_memory.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_hugepage_info.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_debug.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_memalloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_lcore.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_timer.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_interrupts.c
lib/librte_eal/bsdapp/eal/eal_memalloc.c new file +26 -0
@@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2017-2018 Intel Corporation +*/ + +#include <inttypes.h> + +#include <rte_log.h> +#include <rte_memory.h> + +#include "eal_memalloc.h" + +int +eal_memalloc_alloc_seg_bulk(struct rte_memseg **ms __rte_unused, + int __rte_unused n_segs, size_t __rte_unused page_sz, + int __rte_unused socket, bool __rte_unused exact) +{ +RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" ); +return -1 ; +} + +struct rte_memseg * +eal_memalloc_alloc_seg(size_t __rte_unused page_sz, int __rte_unused socket) +{ +RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" ); +return NULL ; +}
lib/librte_eal/bsdapp/eal/meson.build +1 -0
@@ -8,6 +8,7 @@ env_sources = files('eal_alarm.c', 'eal_hugepage_info.c', 'eal_interrupts.c', 'eal_lcore.c', + 'eal_memalloc.c', 'eal_thread.c', 'eal_timer.c', 'eal.c',
lib/librte_eal/common/eal_memalloc.h new file +31 -0
@@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2017-2018 Intel Corporation +*/ + +#ifndef EAL_MEMALLOC_H +#define EAL_MEMALLOC_H + +#include <stdbool.h> + +#include <rte_memory.h> + +/* +* Allocate segment of specified page size. +*/ +struct rte_memseg * +eal_memalloc_alloc_seg (size_t page_sz,int socket); + +/* +* Allocate `n_segs` segments. +* +* Note: `ms` can be NULL. +* +* Note: it is possible to request best-effort allocation by setting `exact` to +* `false`, in which case allocator will return however many pages it managed to +* allocate successfully. +*/ +int +eal_memalloc_alloc_seg_bulk (struct rte_memseg **ms,int n_segs,size_t page_sz, +int socket,bool exact); + +#endif // EAL_MEMALLOC_H
lib/librte_eal/linuxapp/eal/Makefile +2 -0
@@ -36,6 +36,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_thread.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_log.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_vfio.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_vfio_mp_sync.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_memalloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_debug.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_lcore.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_timer.c
@@ -82,6 +83,7 @@ CFLAGS_eal_interrupts.o := -D_GNU_SOURCE CFLAGS_eal_vfio_mp_sync.o := -D_GNU_SOURCE CFLAGS_eal_timer.o := -D_GNU_SOURCE CFLAGS_eal_lcore.o := -D_GNU_SOURCE +CFLAGS_eal_memalloc.o := -D_GNU_SOURCE CFLAGS_eal_thread.o := -D_GNU_SOURCE CFLAGS_eal_log.o := -D_GNU_SOURCE CFLAGS_eal_common_log.o := -D_GNU_SOURCE
lib/librte_eal/linuxapp/eal/eal_memalloc.c new file +429 -0
429 lines not on this page · raw message
lib/librte_eal/linuxapp/eal/meson.build +1 -0
@@ -10,6 +10,7 @@ env_sources = files('eal_alarm.c', 'eal_debug.c', 'eal_hugepage_info.c', 'eal_interrupts.c', + 'eal_memalloc.c', 'eal_lcore.c', 'eal_log.c', 'eal_thread.c',
Signature · 1 line
2.7.4
PATCH v4 52/70 eal: add support for unmapping pages at runtime
In reply to Anatoly BurakovThis isn't used anywhere yet, but the support is now there. Also, adding cleanup to allocation procedures, so that if we fail to allocate everything we asked for, we can free all of it back.
--- lib/librte_eal/bsdapp/eal/eal_memalloc.c | 15 +++ lib/librte_eal/common/eal_memalloc.h | 14 +++ lib/librte_eal/linuxapp/eal/eal_memalloc.c | 149 ++++++++++++++++++++++++++++- 3 files changed, 177 insertions(+), 1 deletion(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +15 -0
@@ -24,3 +24,18 @@ eal_memalloc_alloc_seg(size_t __rte_unused page_sz, int __rte_unused socket)RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" );return NULL ; } + +int +eal_memalloc_free_seg(struct rte_memseg *ms __rte_unused) +{ +RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" ); +return -1 ; +} + +int +eal_memalloc_free_seg_bulk(struct rte_memseg **ms __rte_unused, + int n_segs __rte_unused) +{ +RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" ); +return -1 ; +}
lib/librte_eal/common/eal_memalloc.h +14 -0
@@ -28,4 +28,18 @@ int eal_memalloc_alloc_seg_bulk(struct rte_memseg **ms, int n_segs, size_t page_sz, int socket, bool exact); +/* +* Deallocate segment +*/ +int +eal_memalloc_free_seg (struct rte_memseg *ms); + +/* +* Deallocate `n_segs` segments. Returns 0 on successful deallocation of all +* segments, returns -1 on error. Any segments that could have been deallocated, +* will be deallocated even in case of error. +*/ +int +eal_memalloc_free_seg_bulk (struct rte_memseg **ms,int n_segs); +#endif // EAL_MEMALLOC_H
lib/librte_eal/linuxapp/eal/eal_memalloc.c +148 -1
183 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 53/70 eal: add "single file segments" command-line option
In reply to Anatoly BurakovCurrently, DPDK stores all pages as separate files in hugetlbfs. This option will allow storing all pages in one file (one file per memseg list).
We do this by using fallocate() calls on FreeBSD, however this is only supported on fairly recent (4.3+) kernels, so ftruncate() fallback is provided to grow (but not shrink) hugepage files. Naming scheme is deterministic, so both primary and secondary processes will be able to easily map needed files and offsets.
For multi-file segments, we can close fd's right away. For single-file segments, we can reuse the same fd and reduce the amount of fd's needed to map/use hugepages. However, we need to store the fd's somewhere, so we add a tailq.
---
Notes:
v3:
- Split this change into a separate patch
- Provide more explanation as to how it works
lib/librte_eal/common/eal_common_options.c | 4 + lib/librte_eal/common/eal_internal_cfg.h | 4 + lib/librte_eal/common/eal_options.h | 2 + lib/librte_eal/linuxapp/eal/eal.c | 1 + lib/librte_eal/linuxapp/eal/eal_memalloc.c | 337 ++++++++++++++++++++++++----- 5 files changed, 297 insertions(+), 51 deletions(-)
lib/librte_eal/common/eal_common_options.c +4 -0
@@ -74,6 +74,7 @@ eal_long_options[] = { {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, {OPT_LEGACY_MEM, 0, NULL, OPT_LEGACY_MEM_NUM }, + {OPT_SINGLE_FILE_SEGMENTS, 0, NULL, OPT_SINGLE_FILE_SEGMENTS_NUM}, {0, 0, NULL, 0 } };
@@ -1188,6 +1189,9 @@ eal_parse_common_option(int opt, const char *optarg,case OPT_LEGACY_MEM_NUM : conf->legacy_mem =1 ;break ; +case OPT_SINGLE_FILE_SEGMENTS_NUM : + conf->single_file_segments =1 ; +break ;/* don't know what to do, leave this to caller */ default :
lib/librte_eal/common/eal_internal_cfg.h +4 -0
@@ -51,6 +51,10 @@ struct internal_config {/**< true to enable legacy memory behavior (no dynamic allocation, * IOVA-contiguous segments). */ +volatile unsigned single_file_segments; +/**< true if storing all pages within single files (per-page-size, +* per-node) non-legacy mode only. +*/ volatile int syslog_facility;/**< facility passed to openlog() */ /** default interrupt mode for VFIO */ volatile enum rte_intr_mode vfio_intr_mode;
lib/librte_eal/common/eal_options.h +2 -0
@@ -57,6 +57,8 @@ enum {OPT_VMWARE_TSC_MAP_NUM , #define OPT_LEGACY_MEM "legacy-mem"OPT_LEGACY_MEM_NUM , +#define OPT_SINGLE_FILE_SEGMENTS "single-file-segments" +OPT_SINGLE_FILE_SEGMENTS_NUM , OPT_LONG_MAX_NUM };
lib/librte_eal/linuxapp/eal/eal.c +1 -0
@@ -349,6 +349,7 @@ eal_usage(const char *prgname)" --" OPT_CREATE_UIO_DEV " Create /dev/uioX (usually done by hotplug)\n" " --" OPT_VFIO_INTR " Interrupt mode for VFIO (legacy|msi|msix)\n" " --" OPT_LEGACY_MEM " Legacy memory mode (no dynamic allocation, contiguous segments)\n" +" --" OPT_SINGLE_FILE_SEGMENTS " Put all hugepage memory in single files\n" "\n");/* Allow the application to print its usage message too if hook is set */ if ( rte_application_usage_hook ) {
lib/librte_eal/linuxapp/eal/eal_memalloc.c +286 -51
392 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 54/70 eal: add API to check if memory is contiguous
In reply to Anatoly BurakovFor now, memory is always contiguous because legacy mem mode is enabled unconditionally, but this function will be helpful down the line when we implement support for allocating physically non-contiguous memory. We can no longer guarantee physically contiguous memory unless we're in legacy or IOVA_AS_VA mode, but we can certainly try and see if we succeed.
In addition, this would be useful for e.g. PMD's who may allocate chunks that are smaller than the pagesize, but they must not cross the page boundary, in which case we will be able to accommodate that request. This function will also support non-hugepage memory.
---
Notes:
v3:
- Moved this earlier in the patchset
- Add support for non-hugepage memory
- Fix handling of IOVA as VA mode
v3:
- Add support for non-hugepage memory
- Support non-page-sized segments
lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_memalloc.c | 90 +++++++++++++++++++++++++++++ lib/librte_eal/common/eal_memalloc.h | 10 ++++ lib/librte_eal/common/malloc_elem.c | 40 +------------ lib/librte_eal/common/meson.build | 1 + lib/librte_eal/linuxapp/eal/Makefile | 1 + 6 files changed, 106 insertions(+), 37 deletions(-) create mode 100644 lib/librte_eal/common/eal_common_memalloc.c
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -41,6 +41,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_timer.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memzone.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_log.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_launch.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memalloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_memory.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_tailqs.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_errno.c
lib/librte_eal/common/eal_common_memalloc.c new file +90 -0
90 lines not on this page · raw message
lib/librte_eal/common/eal_memalloc.h +10 -0
@@ -8,6 +8,7 @@#include <stdbool.h> #include <rte_memory.h> +#include <rte_eal_memconfig.h> /* * Allocate segment of specified page size.
@@ -42,4 +43,13 @@ eal_memalloc_free_seg(struct rte_memseg *ms);int eal_memalloc_free_seg_bulk (struct rte_memseg **ms,int n_segs); + +/* +* Check if memory pointed to by `start` and of `length` that resides in +* memseg list `msl` is IOVA-contiguous. +*/ +bool +eal_memalloc_is_contig (const struct rte_memseg_list *msl,void *start, +size_t len); +#endif // EAL_MEMALLOC_H
lib/librte_eal/common/malloc_elem.c +3 -37
@@ -18,6 +18,7 @@#include <rte_common.h> #include <rte_spinlock.h> +#include "eal_memalloc.h" #include "malloc_elem.h" #include "malloc_heap.h"
@@ -100,45 +101,10 @@ malloc_elem_insert(struct malloc_elem *elem)* so we just check the page addresses. */ static bool -elem_check_phys_contig(const struct rte_memseg_list *msl __rte_unused, +elem_check_phys_contig (const struct rte_memseg_list *msl,void *start,size_t size) { -rte_iova_t cur, expected; -void *start_page, *end_page, *cur_page; -size_t pagesz; - -/* for hugepage memory or IOVA as VA, it's always contiguous */ -if (rte_eal_has_hugepages () ||rte_eal_iova_mode () ==RTE_IOVA_VA ) -return true; - -/* otherwise, check if start and end are within the same page */ - pagesz =getpagesize (); - - start_page =RTE_PTR_ALIGN_FLOOR (start, pagesz); - end_page =RTE_PTR_ALIGN_FLOOR (RTE_PTR_ADD (start, size -1 ), pagesz); - -if (start_page == end_page) -return true; - -/* if they are from different pages, check if they are contiguous */ - -/* if we can't access physical addresses, assume non-contiguous */ -if (!rte_eal_using_phys_addrs ()) -return false; - -/* skip first iteration */ - cur =rte_mem_virt2iova (start_page); - expected = cur + pagesz; - cur_page =RTE_PTR_ADD (start_page, pagesz); - -while (cur_page <= end_page) { - cur =rte_mem_virt2iova (cur_page); -if (cur != expected) -return false; - cur_page =RTE_PTR_ADD (cur_page, pagesz); - expected += pagesz; - } -return true; +return eal_memalloc_is_contig (msl, start, size); }/*
lib/librte_eal/common/meson.build +1 -0
@@ -16,6 +16,7 @@ common_sources = files( 'eal_common_launch.c', 'eal_common_lcore.c', 'eal_common_log.c', + 'eal_common_memalloc.c', 'eal_common_memory.c', 'eal_common_memzone.c', 'eal_common_options.c',
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -49,6 +49,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_timer.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memzone.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_log.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_launch.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memalloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_memory.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_tailqs.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_errno.c
Signature · 1 line
2.7.4
PATCH v4 55/70 eal: prepare memseg lists for multiprocess sync
In reply to Anatoly BurakovIn preparation for implementing multiprocess support, we are adding a version number to memseg lists. We will not need any locks, because memory hotplug will have a global lock (so any time memory map and thus version number might change, we will already be holding a lock).
There are two ways of implementing multiprocess support for memory
hotplug: either all information about mapped memory is shared between processes, and secondary processes simply attempt to map/unmap memory based on requests from the primary, or secondary processes store their own maps and only check if they are in sync with the primary process' maps.
This implementation will opt for the latter option: primary process shared mappings will be authoritative, and each secondary process will use its own interal view of mapped memory, and will attempt to synchronize on these mappings using versioning.
Under this model, only primary process will decide which pages get mapped, and secondary processes will only copy primary's page maps and get notified of the changes via IPC mechanism (coming in later commits).
---
Notes:
v3:
- Make version volatile
v3:
- Removed per-list locks as we're using global hotplug lock
lib/librte_eal/bsdapp/eal/eal_memalloc.c | 7 + lib/librte_eal/common/eal_memalloc.h | 4 + lib/librte_eal/common/include/rte_eal_memconfig.h | 1 + lib/librte_eal/linuxapp/eal/eal_memalloc.c | 250 ++++++++++++++++++++++ 4 files changed, 262 insertions(+)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +7 -0
@@ -39,3 +39,10 @@ eal_memalloc_free_seg_bulk(struct rte_memseg **ms __rte_unused,RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" );return -1 ; } + +int +eal_memalloc_sync_with_primary (void ) +{ +RTE_LOG (ERR ,EAL ,"Memory hotplug not supported on FreeBSD\n" ); +return -1 ; +}
lib/librte_eal/common/eal_memalloc.h +4 -0
@@ -52,4 +52,8 @@ bool eal_memalloc_is_contig(const struct rte_memseg_list *msl, void *start, size_t len); +/* synchronize local memory map to primary process */ +int +eal_memalloc_sync_with_primary (void ); +#endif // EAL_MEMALLOC_H
lib/librte_eal/common/include/rte_eal_memconfig.h +1 -0
@@ -32,6 +32,7 @@ struct rte_memseg_list { };int socket_id;/**< Socket ID for all memsegs in this list. */ uint64_t page_sz;/**< Page size for all memsegs in this list. */ +volatile uint32_t version;/**< version number for multiprocess sync. */ struct rte_fbarray memseg_arr; };
lib/librte_eal/linuxapp/eal/eal_memalloc.c +250 -0
272 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 56/70 eal: read hugepage counts from node-specific sysfs path
In reply to Anatoly BurakovFor non-legacy memory init mode, instead of looking at generic sysfs path, look at sysfs paths pertaining to each NUMA node for hugepage counts. Note that per-NUMA node path does not provide information regarding reserved pages, so we might not get the best info from these paths, but this saves us from the whole mapping/remapping business before we're actually able to tell which page is on which socket, because we no longer require our memory to be physically contiguous.
Legacy memory init will not use this.
--- lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 80 +++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-)
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +74 -6
@@ -31,6 +31,7 @@#include "eal_filesystem.h" static const char sys_dir_path[] ="/sys/kernel/mm/hugepages" ; +static const char sys_pages_numa_dir_path[] ="/sys/devices/system/node" ;/* this function is only called from eal_hugepage_info_init which itself * is only called from a primary process */
@@ -71,6 +72,45 @@ get_num_hugepages(const char *subdir)return num_pages; } +static uint32_t +get_num_hugepages_on_node (const char *subdir,unsigned int socket) +{ +char path[PATH_MAX ], socketpath[PATH_MAX ]; +DIR *socketdir; +unsigned long num_pages =0 ; +const char *nr_hp_file ="free_hugepages" ; + +snprintf (socketpath,sizeof (socketpath),"%s/node%u/hugepages" , + sys_pages_numa_dir_path, socket); + + socketdir =opendir (socketpath); +if (socketdir) { +/* Keep calm and carry on */ +closedir (socketdir); + }else { +/* Can't find socket dir, so ignore it */ +return 0 ; + } + +snprintf (path,sizeof (path),"%s/%s/%s" , + socketpath, subdir, nr_hp_file); +if (eal_parse_sysfs_value (path, &num_pages) <0 ) +return 0 ; + +if (num_pages ==0 ) +RTE_LOG (WARNING ,EAL ,"No free hugepages reported in %s\n" , + subdir); + +/* +* we want to return a uint32_t and more than this looks suspicious +* anyway ... +*/ +if (num_pages >UINT32_MAX ) + num_pages =UINT32_MAX ; + +return num_pages; +} +static uint64_t get_default_hp_size (void ) {
@@ -269,7 +309,7 @@ eal_hugepage_info_init(void) {const char dirent_start_text[] ="hugepages-" ;const size_t dirent_start_len =sizeof (dirent_start_text) -1 ; -unsigned i, num_sizes =0 ; +unsigned int i, total_pages, num_sizes =0 ;DIR *dir;struct dirent *dirent;
@@ -323,9 +363,28 @@ eal_hugepage_info_init(void)if (clear_hugedir (hpi->hugedir) ==-1 )break ; -/* for now, put all pages into socket 0, -* later they will be sorted */ - hpi->num_pages[0 ] =get_num_hugepages (dirent->d_name); +/* +* first, try to put all hugepages into relevant sockets, but +* if first attempts fails, fall back to collecting all pages +* in one socket and sorting them later +*/ + total_pages =0 ; +/* we also don't want to do this for legacy init */ +if (!internal_config.legacy_mem) +for (i =0 ; i <rte_socket_count (); i++) { +int socket =rte_socket_id_by_idx (i); +unsigned int num_pages = +get_num_hugepages_on_node ( + dirent->d_name, socket); + hpi->num_pages[socket] = num_pages; + total_pages += num_pages; + } +/* +* we failed to sort memory from the get go, so fall +* back to old way +*/ +if (total_pages ==0 ) + hpi->num_pages[0 ] =get_num_hugepages (dirent->d_name);#ifndef RTE_ARCH_64 /* for 32-bit systems, limit number of hugepages to
@@ -349,10 +408,19 @@ eal_hugepage_info_init(void) sizeof(internal_config.hugepage_info[0]), compare_hpi);/* now we have all info, check we have at least one valid size */ -for (i =0 ; i < num_sizes; i++) +for (i =0 ; i < num_sizes; i++) { +/* pages may no longer all be on socket 0, so check all */ +unsigned int j, num_pages =0 ; + +for (j =0 ; j <RTE_MAX_NUMA_NODES ; j++) { +struct hugepage_info *hpi = + &internal_config.hugepage_info[i]; + num_pages += hpi->num_pages[j]; + }if (internal_config.hugepage_info[i].hugedir !=NULL && - internal_config.hugepage_info[i].num_pages[0 ] >0 ) + num_pages >0 )return 0 ; + }/* no valid hugepage mounts available, return error */ return -1 ;
Signature · 1 line
2.7.4
PATCH v4 57/70 eal: make use of memory hotplug for init
In reply to Anatoly BurakovAdd a new (non-legacy) memory init path for EAL. It uses the new memory hotplug facilities.
If no -m or --socket-mem switches were specified, the new init will not allocate anything, whereas if those switches were passed, appropriate amounts of pages would be requested, just like for legacy init.
Allocated pages will be physically discontiguous (or rather, they're not guaranteed to be physically contiguous - they may still be so by accident) unless RTE_IOVA_VA mode is used.
--- lib/librte_eal/linuxapp/eal/eal_memory.c | 62 ++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memory.c +59 -3
@@ -40,6 +40,7 @@#include <rte_string_fns.h> #include "eal_private.h" +#include "eal_memalloc.h" #include "eal_internal_cfg.h" #include "eal_filesystem.h" #include "eal_hugepages.h"
@@ -1600,6 +1601,61 @@ eal_legacy_hugepage_init(void)return -1 ; } +static int +eal_hugepage_init (void ) +{ +struct hugepage_info used_hp[MAX_HUGEPAGE_SIZES ]; +uint64_t memory[RTE_MAX_NUMA_NODES ]; +int hp_sz_idx, socket_id; + +test_phys_addrs_available (); + +memset (used_hp,0 ,sizeof (used_hp)); + +for (hp_sz_idx =0 ; + hp_sz_idx < (int ) internal_config.num_hugepage_sizes; + hp_sz_idx++) { +/* also initialize used_hp hugepage sizes in used_hp */ +struct hugepage_info *hpi; + hpi = &internal_config.hugepage_info[hp_sz_idx]; + used_hp[hp_sz_idx].hugepage_sz = hpi->hugepage_sz; + } + +/* make a copy of socket_mem, needed for balanced allocation. */ +for (hp_sz_idx =0 ; hp_sz_idx <RTE_MAX_NUMA_NODES ; hp_sz_idx++) + memory[hp_sz_idx] = internal_config.socket_mem[hp_sz_idx]; + +/* calculate final number of pages */ +if (calc_num_pages_per_socket (memory, + internal_config.hugepage_info, used_hp, + internal_config.num_hugepage_sizes) <0 ) +return -1 ; + +for (hp_sz_idx =0 ; + hp_sz_idx < (int )internal_config.num_hugepage_sizes; + hp_sz_idx++) { +for (socket_id =0 ; socket_id <RTE_MAX_NUMA_NODES ; + socket_id++) { +struct hugepage_info *hpi = &used_hp[hp_sz_idx]; +unsigned int num_pages = hpi->num_pages[socket_id]; +int num_pages_alloc; + +if (num_pages ==0 ) +continue ; + +RTE_LOG (DEBUG ,EAL ,"Allocating %u pages of size %" PRIu64"M on socket %i\n" , + num_pages, hpi->hugepage_sz >>20 , socket_id); + + num_pages_alloc =eal_memalloc_alloc_seg_bulk (NULL , + num_pages, hpi->hugepage_sz, + socket_id, true); +if (num_pages_alloc <0 ) +return -1 ; + } + } +return 0 ; +} +/* * uses fstat to report the size of a file on disk */
@@ -1722,9 +1778,9 @@ eal_legacy_hugepage_attach(void)int rte_eal_hugepage_init (void ) { -if (internal_config.legacy_mem) -return eal_legacy_hugepage_init (); -return -1 ; +return internal_config.legacy_mem ? +eal_legacy_hugepage_init () : +eal_hugepage_init (); }int
Signature · 1 line
2.7.4
PATCH v4 58/70 eal: share hugepage info primary and secondary
In reply to Anatoly BurakovSince we are going to need to map hugepages in both primary and secondary processes, we need to know where we should look for hugetlbfs mountpoints. So, share those with secondary processes, and map them on init.
--- lib/librte_eal/bsdapp/eal/eal.c | 19 ++-- lib/librte_eal/bsdapp/eal/eal_hugepage_info.c | 56 +++++++++-- lib/librte_eal/bsdapp/eal/eal_memory.c | 21 +--- lib/librte_eal/common/eal_common_options.c | 5 +- lib/librte_eal/common/eal_filesystem.h | 17 ++++ lib/librte_eal/common/eal_hugepages.h | 10 +- lib/librte_eal/common/eal_internal_cfg.h | 2 +- lib/librte_eal/linuxapp/eal/eal.c | 18 ++-- lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 121 ++++++++++++++++++++---- lib/librte_eal/linuxapp/eal/eal_memory.c | 15 +-- 10 files changed, 217 insertions(+), 67 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +12 -7
@@ -289,7 +289,7 @@ eal_get_hugepage_mem_size(void)for (i =0 ; i < internal_config.num_hugepage_sizes; i++) {struct hugepage_info *hpi = &internal_config.hugepage_info[i]; -if (hpi->hugedir !=NULL ) { +if (strnlen (hpi->hugedir,sizeof (hpi->hugedir)) !=0 ) {for (j =0 ; j <RTE_MAX_NUMA_NODES ; j++) { size += hpi->hugepage_sz * hpi->num_pages[j]; }
@@ -561,12 +561,17 @@ rte_eal_init(int argc, char **argv)/* autodetect the iova mapping mode (default is iova_pa) */ rte_eal_get_configuration ()->iova_mode =rte_bus_get_iommu_class (); -if (internal_config.no_hugetlbfs ==0 && -eal_hugepage_info_init () <0 ) { -rte_eal_init_alert ("Cannot get hugepage information." ); - rte_errno =EACCES ; -rte_atomic32_clear (&run_once); -return -1 ; +if (internal_config.no_hugetlbfs ==0 ) { +/* rte_config isn't initialized yet */ + ret = internal_config.process_type ==RTE_PROC_PRIMARY ? +eal_hugepage_info_init () : +eal_hugepage_info_read (); +if (ret <0 ) { +rte_eal_init_alert ("Cannot get hugepage information." ); + rte_errno =EACCES ; +rte_atomic32_clear (&run_once); +return -1 ; + } }if (internal_config.memory ==0 && internal_config.force_sockets ==0 ) {
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +49 -7
94 lines not on this page · raw message
lib/librte_eal/bsdapp/eal/eal_memory.c +2 -19
@@ -240,23 +240,10 @@ intrte_eal_hugepage_attach (void) {const struct hugepage_info *hpi; -int fd_hugepage_info, fd_hugepage =-1 ; +int fd_hugepage =-1 ;unsigned int i; -/* Obtain a file descriptor for hugepage_info */ - fd_hugepage_info =open (eal_hugepage_info_path (),O_RDONLY ); -if (fd_hugepage_info <0 ) { -RTE_LOG (ERR ,EAL ,"Could not open %s\n" ,eal_hugepage_info_path ()); -return -1 ; - } - -/* Map the shared hugepage_info into the process address spaces */ - hpi =mmap (NULL ,sizeof (internal_config.hugepage_info), -PROT_READ ,MAP_PRIVATE , fd_hugepage_info,0 ); -if (hpi ==MAP_FAILED ) { -RTE_LOG (ERR ,EAL ,"Could not mmap %s\n" ,eal_hugepage_info_path ()); - goto error; - } + hpi = &internal_config.hugepage_info[0 ];for (i =0 ; i < internal_config.num_hugepage_sizes; i++) {const struct hugepage_info *cur_hpi = &hpi[i];
@@ -286,13 +273,9 @@ rte_eal_hugepage_attach(void) }/* hugepage_info is no longer required */ -munmap ((void *)(uintptr_t )hpi,sizeof (internal_config.hugepage_info)); -close (fd_hugepage_info);return 0 ; error: -if (fd_hugepage_info >=0 ) -close (fd_hugepage_info);if (fd_hugepage >=0 )close (fd_hugepage);return -1 ;
lib/librte_eal/common/eal_common_options.c +4 -1
@@ -179,8 +179,11 @@ eal_reset_internal_config(struct internal_config *internal_cfg)for (i =0 ; i <RTE_MAX_NUMA_NODES ; i++) internal_cfg->socket_mem[i] =0 ;/* zero out hugedir descriptors */ -for (i =0 ; i <MAX_HUGEPAGE_SIZES ; i++) +for (i =0 ; i <MAX_HUGEPAGE_SIZES ; i++) { +memset (&internal_cfg->hugepage_info[i],0 , +sizeof (internal_cfg->hugepage_info[0 ])); internal_cfg->hugepage_info[i].lock_descriptor =-1 ; + } internal_cfg->base_virtaddr =0 ; internal_cfg->syslog_facility =LOG_DAEMON ;
lib/librte_eal/common/eal_filesystem.h +17 -0
@@ -85,6 +85,23 @@ eal_hugepage_info_path(void)return buffer; } +/** Path of hugepage info file. */ +#define HUGEPAGE_FILE_FMT "%s/.%s_hugepage_file" + +static inline const char * +eal_hugepage_file_path (void ) +{ +static char buffer[PATH_MAX ];/* static so auto-zeroed */ +const char *directory = default_config_dir; +const char *home_dir =getenv ("HOME" ); + +if (getuid () !=0 && home_dir !=NULL ) + directory = home_dir; +snprintf (buffer,sizeof (buffer) -1 ,HUGEPAGE_FILE_FMT , directory, + internal_config.hugefile_prefix); +return buffer; +} +/** String format for hugepage map files. */ #define HUGEFILE_FMT "%s/%smap_%d"#define TEMP_HUGEFILE_FMT "%s/%smap_temp_%d"
lib/librte_eal/common/eal_hugepages.h +8 -2
@@ -26,9 +26,15 @@ struct hugepage_file { };/** -* Read the information from linux on what hugepages are available -* for the EAL to use +* Read the information on what hugepages are available for the EAL to use, +* clearing out any unused ones. */ int eal_hugepage_info_init (void ); +/** +* Read whatever information primary process has shared about hugepages into +* secondary process. +*/ +int eal_hugepage_info_read (void ); +#endif /* EAL_HUGEPAGES_H */
lib/librte_eal/common/eal_internal_cfg.h +1 -1
@@ -21,7 +21,7 @@*/ struct hugepage_info {uint64_t hugepage_sz;/**< size of a huge page */ -const char *hugedir;/**< dir where hugetlbfs is mounted */ +char hugedir[PATH_MAX ];/**< dir where hugetlbfs is mounted */ uint32_t num_pages[RTE_MAX_NUMA_NODES ];/**< number of hugepages of that size on each socket */ int lock_descriptor;/**< file descriptor for hugepage dir */
lib/librte_eal/linuxapp/eal/eal.c +11 -7
@@ -807,13 +807,17 @@ rte_eal_init(int argc, char **argv) "KNI module inserted\n"); } -if (internal_config.no_hugetlbfs ==0 && - internal_config.process_type !=RTE_PROC_SECONDARY && -eal_hugepage_info_init () <0 ) { -rte_eal_init_alert ("Cannot get hugepage information." ); - rte_errno =EACCES ; -rte_atomic32_clear (&run_once); -return -1 ; +if (internal_config.no_hugetlbfs ==0 ) { +/* rte_config isn't initialized yet */ + ret = internal_config.process_type ==RTE_PROC_PRIMARY ? +eal_hugepage_info_init () : +eal_hugepage_info_read (); +if (ret <0 ) { +rte_eal_init_alert ("Cannot get hugepage information." ); + rte_errno =EACCES ; +rte_atomic32_clear (&run_once); +return -1 ; + } }if (internal_config.memory ==0 && internal_config.force_sockets ==0 ) {
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +105 -16
170 lines not on this page · raw message
lib/librte_eal/linuxapp/eal/eal_memory.c +8 -7
@@ -1060,7 +1060,7 @@ get_socket_mem_size(int socket)for (i =0 ; i < internal_config.num_hugepage_sizes; i++){struct hugepage_info *hpi = &internal_config.hugepage_info[i]; -if (hpi->hugedir !=NULL ) +if (strnlen (hpi->hugedir,sizeof (hpi->hugedir)) !=0 ) size += hpi->hugepage_sz * hpi->num_pages[socket]; }
@@ -1160,7 +1160,8 @@ calc_num_pages_per_socket(uint64_t * memory,for (socket =0 ; socket <RTE_MAX_NUMA_NODES && total_mem !=0 ; socket++) {/* skips if the memory on specific socket wasn't requested */ for (i =0 ; i < num_hp_info && memory[socket] !=0 ; i++){ - hp_used[i].hugedir = hp_info[i].hugedir; +snprintf (hp_used[i].hugedir,sizeof (hp_used[i].hugedir), +"%s" , hp_info[i].hugedir); hp_used[i].num_pages[socket] =RTE_MIN ( memory[socket] / hp_info[i].hugepage_sz, hp_info[i].num_pages[socket]);
@@ -1235,7 +1236,7 @@ eal_get_hugepage_mem_size(void)for (i =0 ; i < internal_config.num_hugepage_sizes; i++) {struct hugepage_info *hpi = &internal_config.hugepage_info[i]; -if (hpi->hugedir !=NULL ) { +if (strnlen (hpi->hugedir,sizeof (hpi->hugedir)) !=0 ) {for (j =0 ; j <RTE_MAX_NUMA_NODES ; j++) { size += hpi->hugepage_sz * hpi->num_pages[j]; }
@@ -1508,7 +1509,7 @@ eal_legacy_hugepage_init(void) }/* create shared memory */ - hugepage =create_shared_memory (eal_hugepage_info_path (), + hugepage =create_shared_memory (eal_hugepage_file_path (), nr_hugefiles *sizeof (struct hugepage_file ));if (hugepage ==NULL ) {
@@ -1693,16 +1694,16 @@ eal_legacy_hugepage_attach(void)test_phys_addrs_available (); - fd_hugepage =open (eal_hugepage_info_path (),O_RDONLY ); + fd_hugepage =open (eal_hugepage_file_path (),O_RDONLY );if (fd_hugepage <0 ) { -RTE_LOG (ERR ,EAL ,"Could not open %s\n" ,eal_hugepage_info_path ()); +RTE_LOG (ERR ,EAL ,"Could not open %s\n" ,eal_hugepage_file_path ()); goto error; } size =getFileSize (fd_hugepage); hp =mmap (NULL , size,PROT_READ ,MAP_PRIVATE , fd_hugepage,0 );if (hp ==MAP_FAILED ) { -RTE_LOG (ERR ,EAL ,"Could not mmap %s\n" ,eal_hugepage_info_path ()); +RTE_LOG (ERR ,EAL ,"Could not mmap %s\n" ,eal_hugepage_file_path ()); goto error; }
Signature · 1 line
2.7.4
PATCH v4 59/70 eal: add secondary process init with memory hotplug
In reply to Anatoly BurakovSecondary initialization will just sync memory map with primary process.
---
Notes:
v3:
- Improved handling of EAL hugepage info
lib/librte_eal/common/eal_common_memory.c | 1 + lib/librte_eal/linuxapp/eal/eal_memory.c | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-)
lib/librte_eal/common/eal_common_memory.c +1 -0
@@ -20,6 +20,7 @@#include <rte_errno.h> #include <rte_log.h> +#include "eal_memalloc.h" #include "eal_private.h" #include "eal_internal_cfg.h"
lib/librte_eal/linuxapp/eal/eal_memory.c +15 -3
@@ -1776,6 +1776,18 @@ eal_legacy_hugepage_attach(void)return -1 ; } +static int +eal_hugepage_attach (void ) +{ +if (eal_memalloc_sync_with_primary ()) { +RTE_LOG (ERR ,EAL ,"Could not map memory from primary process\n" ); +if (aslr_enabled () >0 ) +RTE_LOG (ERR ,EAL ,"It is recommended to disable ASLR in the kernel and retry running both primary and secondary processes\n" ); +return -1 ; + } +return 0 ; +} +int rte_eal_hugepage_init (void ) {
@@ -1787,9 +1799,9 @@ rte_eal_hugepage_init(void)int rte_eal_hugepage_attach (void ) { -if (internal_config.legacy_mem) -return eal_legacy_hugepage_attach (); -return -1 ; +return internal_config.legacy_mem ? +eal_legacy_hugepage_attach () : +eal_hugepage_attach (); }int
Signature · 1 line
2.7.4
PATCH v4 60/70 eal: enable memory hotplug support in rte_malloc
In reply to Anatoly BurakovThis set of changes enables rte_malloc to allocate and free memory as needed. Currently, it is disabled because legacy mem mode is enabled unconditionally.
The way it works is, first malloc checks if there is enough memory already allocated to satisfy user's request. If there isn't, we try and allocate more memory. The reverse happens with free - we free an element, check its size (including free element merging due to adjacency) and see if it's bigger than hugepage size and that its start and end span a hugepage or more. Then we remove the area from malloc heap (adjusting element lengths where appropriate), and deallocate the page.
For legacy mode, runtime alloc/free of pages is disabled.
It is worth noting that memseg lists are being sorted by page size, and that we try our best to satisfy user's request. That is, if the user requests an element from a 2MB page memory, we will check if we can satisfy that request from existing memory, if not we try and allocate more 2MB pages. If that fails and user also specified a "size is hint" flag, we then check other page sizes and try to allocate from there. If that fails too, then, depending on flags, we may try allocating from other sockets. In other words, we try our best to give the user what they asked for, but going to other sockets is last resort - first we try to allocate more memory on the same socket.
---
Notes:
v3:
- Compile fixes
lib/librte_eal/common/eal_common_memzone.c | 26 +-- lib/librte_eal/common/malloc_elem.c | 92 ++++++++ lib/librte_eal/common/malloc_elem.h | 3 + lib/librte_eal/common/malloc_heap.c | 347 ++++++++++++++++++++++++++++- lib/librte_eal/common/malloc_heap.h | 4 +- lib/librte_eal/common/rte_malloc.c | 31 +-- 6 files changed, 439 insertions(+), 64 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +3 -23
@@ -93,7 +93,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,struct rte_mem_config *mcfg;struct rte_fbarray *arr;size_t requested_len; -int socket, i, mz_idx; +int mz_idx;bool contig;/* get pointer to global configuration */
@@ -183,29 +183,9 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, } } -if (socket_id ==SOCKET_ID_ANY ) - socket =malloc_get_numa_socket (); -else - socket = socket_id; -/* allocate memory on heap */ -void *mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[socket],NULL , - requested_len, flags, align, bound, contig); - -if ((mz_addr ==NULL ) && (socket_id ==SOCKET_ID_ANY )) { -/* try other heaps */ -for (i =0 ; i <RTE_MAX_NUMA_NODES ; i++) { -if (socket == i) -continue ; - - mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[i], -NULL , requested_len, flags, align, - bound, contig); -if (mz_addr !=NULL ) -break ; - } - } - +void *mz_addr =malloc_heap_alloc (NULL , requested_len, socket_id, flags, + align, bound, contig);if (mz_addr ==NULL ) { rte_errno =ENOMEM ;return NULL ;
lib/librte_eal/common/malloc_elem.c +92 -0
98 lines not on this page · raw message
lib/librte_eal/common/malloc_elem.h +3 -0
@@ -154,6 +154,9 @@ int malloc_elem_resize(struct malloc_elem *elem, size_t size);void +malloc_elem_hide_region (struct malloc_elem *elem,void *start,size_t len); + +void malloc_elem_free_list_remove (struct malloc_elem *elem);/*
lib/librte_eal/common/malloc_heap.c +336 -11
392 lines not on this page · raw message
lib/librte_eal/common/malloc_heap.h +2 -2
@@ -26,8 +26,8 @@ malloc_get_numa_socket(void) }void * -malloc_heap_alloc (struct malloc_heap *heap,const char *type,size_t size, -unsigned int flags,size_t align,size_t bound,bool contig); +malloc_heap_alloc (const char *type,size_t size,int socket,unsigned int flags, +size_t align,size_t bound,bool contig);int malloc_heap_free (struct malloc_elem *elem);
lib/librte_eal/common/rte_malloc.c +3 -28
@@ -40,10 +40,6 @@ void * rte_malloc_socket(const char *type, size_t size, unsigned int align, int socket_arg) { - struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; -int socket, i; -void *ret; - /* return NULL if size is 0 or alignment is not power-of-2 */ if (size == 0 || (align && !rte_is_power_of_2(align))) return NULL;
@@ -51,33 +47,12 @@ rte_malloc_socket(const char *type, size_t size, unsigned int align,if (!rte_eal_has_hugepages ()) socket_arg =SOCKET_ID_ANY ; -if (socket_arg ==SOCKET_ID_ANY ) - socket =malloc_get_numa_socket (); -else - socket = socket_arg; -/* Check socket parameter */ -if (socket >=RTE_MAX_NUMA_NODES ) +if (socket_arg >=RTE_MAX_NUMA_NODES )return NULL ; - ret =malloc_heap_alloc (&mcfg->malloc_heaps[socket], type, - size,0 , align ==0 ?1 : align,0 , false); -if (ret !=NULL || socket_arg !=SOCKET_ID_ANY ) -return ret; - -/* try other heaps */ -for (i =0 ; i <RTE_MAX_NUMA_NODES ; i++) { -/* we already tried this one */ -if (i == socket) -continue ; - - ret =malloc_heap_alloc (&mcfg->malloc_heaps[i], type, - size,0 , align ==0 ?1 : align,0 , false); -if (ret !=NULL ) -return ret; - } - -return NULL ; +return malloc_heap_alloc (type, size, socket_arg,0 , + align ==0 ?1 : align,0 , false); }/*
Signature · 1 line
2.7.4
PATCH v4 61/70 eal: add support for multiprocess memory hotplug
In reply to Anatoly BurakovThis enables multiprocess synchronization for memory hotplug requests at runtime (as opposed to initialization).
Basic workflow is the following. Primary process always does initial mapping and unmapping, and secondary processes always follow primary page map. Only one allocation request can be active at any one time.
When primary allocates memory, it ensures that all other processes have allocated the same set of hugepages successfully, otherwise any allocations made are being rolled back, and heap is freed back. Heap is locked throughout the process, and there is also a global memory hotplug lock, so no race conditions can happen.
When primary frees memory, it frees the heap, deallocates affected pages, and notifies other processes of deallocations. Since heap is freed from that memory chunk, the area basically becomes invisible to other processes even if they happen to fail to unmap that specific set of pages, so it's completely safe to ignore results of sync requests.
When secondary allocates memory, it does not do so by itself. Instead, it sends a request to primary process to try and allocate pages of specified size and on specified socket, such that a specified heap allocation request could complete. Primary process then sends all secondaries (including the requestor) a separate notification of allocated pages, and expects all secondary processes to report success before considering pages as "allocated".
Only after primary process ensures that all memory has been successfully allocated in all secondary process, it will respond positively to the initial request, and let secondary proceed with the allocation. Since the heap now has memory that can satisfy allocation request, and it was locked all this time (so no other allocations could take place), secondary process will be able to allocate memory from the heap.
When secondary frees memory, it hides pages to be deallocated from the heap. Then, it sends a deallocation request to primary process, so that it deallocates pages itself, and then sends a separate sync request to all other processes (including the requestor) to unmap the same pages. This way, even if secondary fails to notify other processes of this deallocation, that memory will become invisible to other processes, and will not be allocated from again.
So, to summarize: address space will only become part of the heap if primary process can ensure that all other processes have allocated this memory successfully. If anything goes wrong, the worst thing that could happen is that a page will "leak" and will not be available to neither DPDK nor the system, as some process will still hold onto it. It's not an actual leak, as we can account for the page - it's just that none of the processes will be able to use this page for anything useful, until it gets allocated from by the primary.
Due to underlying DPDK IPC implementation being single-threaded, some asynchronous magic had to be done, as we need to complete several requests before we can definitively allow secondary process to use allocated memory (namely, it has to be present in all other secondary processes before it can be used). Additionally, only one allocation request is allowed to be submitted at once.
Memory allocation requests are only allowed when there are no secondary processes currently initializing. To enforce that, a shared rwlock is used, that is set to read lock on init (so that several secondaries could initialize concurrently), and write lock on making allocation requests (so that either secondary init will have to wait, or allocation request will have to wait until all processes have initialized).
Any other function that wishes to iterate over memory or prevent allocations should be using memory hotplug lock.
--- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_memory.c | 67 +- lib/librte_eal/common/include/rte_eal_memconfig.h | 3 + lib/librte_eal/common/malloc_heap.c | 255 ++++++-- lib/librte_eal/common/malloc_mp.c | 744 ++++++++++++++++++++++ lib/librte_eal/common/malloc_mp.h | 86 +++ lib/librte_eal/common/meson.build | 1 + lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/linuxapp/eal/eal_memalloc.c | 32 +- 9 files changed, 1126 insertions(+), 64 deletions(-) create mode 100644 lib/librte_eal/common/malloc_mp.c create mode 100644 lib/librte_eal/common/malloc_mp.h
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -59,6 +59,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_fbarray.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_malloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_heap.c +SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += malloc_mp.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_keepalive.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += rte_reciprocal.c
lib/librte_eal/common/eal_common_memory.c +49 -18
130 lines not on this page · raw message
lib/librte_eal/common/include/rte_eal_memconfig.h +3 -0
@@ -59,6 +59,9 @@ struct rte_mem_config {rte_rwlock_t qlock;/**< used for tailq operation for thread safe. */ rte_rwlock_t mplock;/**< only used by mempool LIB for thread-safe. */ +rte_rwlock_t memory_hotplug_lock; +/**< indicates whether memory hotplug request is in progress. */ +/* memory segments and zones */ struct rte_fbarray memzones;/**< Memzone descriptors. */
lib/librte_eal/common/malloc_heap.c +212 -43
371 lines not on this page · raw message
lib/librte_eal/common/malloc_mp.c new file +744 -0
744 lines not on this page · raw message
lib/librte_eal/common/malloc_mp.h new file +86 -0
86 lines not on this page · raw message
lib/librte_eal/common/meson.build +1 -0
@@ -27,6 +27,7 @@ common_sources = files( 'eal_common_timer.c', 'malloc_elem.c', 'malloc_heap.c', + 'malloc_mp.c', 'rte_keepalive.c', 'rte_malloc.c', 'rte_reciprocal.c',
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -67,6 +67,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_fbarray.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_malloc.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_elem.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_heap.c +SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += malloc_mp.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_keepalive.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_service.c SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += rte_reciprocal.c
lib/librte_eal/linuxapp/eal/eal_memalloc.c +29 -3
@@ -211,6 +211,32 @@ is_zero_length(int fd)return st.st_blocks ==0 ; } +/* we cannot use rte_memseg_list_walk() here because we will be holding a +* write lock whenever we enter every function in this file, however copying +* the same iteration code everywhere is not ideal as well. so, use a lockless +* copy of memseg list walk here. +*/ +static int +memseg_list_walk_thread_unsafe (rte_memseg_list_walk_t func,void *arg) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +int i, ret =0 ; + +for (i =0 ; i <RTE_MAX_MEMSEG_LISTS ; i++) { +struct rte_memseg_list *msl = &mcfg->memsegs[i]; + +if (msl->base_va ==NULL ) +continue ; + + ret =func (msl, arg); +if (ret <0 ) +return -1 ; +if (ret >0 ) +return 1 ; + } +return 0 ; +} +static int get_seg_fd (char *path,int buflen,struct hugepage_info *hi,unsigned int list_idx,unsigned int seg_idx)
@@ -739,7 +765,7 @@ eal_memalloc_alloc_seg_bulk(struct rte_memseg **ms, int n_segs, size_t page_sz, wa.socket = socket; wa.segs_allocated =0 ; - ret =rte_memseg_list_walk (alloc_seg_walk, &wa); + ret =memseg_list_walk_thread_unsafe (alloc_seg_walk, &wa);if (ret ==0 ) {RTE_LOG (ERR ,EAL ,"%s(): couldn't find suitable memseg_list\n" , __func__);
@@ -798,7 +824,7 @@ eal_memalloc_free_seg_bulk(struct rte_memseg **ms, int n_segs) wa.ms = cur; wa.hi = hi; - walk_res =rte_memseg_list_walk (free_seg_walk, &wa); + walk_res =memseg_list_walk_thread_unsafe (free_seg_walk, &wa);if (walk_res ==1 )continue ;if (walk_res ==0 )
@@ -1055,7 +1081,7 @@ eal_memalloc_sync_with_primary(void)if (rte_eal_process_type () ==RTE_PROC_PRIMARY )return 0 ; -if (rte_memseg_list_walk (sync_walk,NULL )) +if (memseg_list_walk_thread_unsafe (sync_walk,NULL ))return -1 ;return 0 ; }
Signature · 1 line
2.7.4
PATCH v4 62/70 eal: add support for callbacks on memory hotplug
In reply to Anatoly BurakovEach process will have its own callbacks. Callbacks will indicate whether it's allocation and deallocation that's happened, and will also provide start VA address and length of allocated block.
Since memory hotplug isn't supported on FreeBSD and in legacy mem mode, it will not be possible to register them in either.
Callbacks are called whenever something happens to the memory map of current process, therefore at those times memory hotplug subsystem is write-locked, which leads to deadlocks on attempt to use these functions. Document the limitation.
---
Notes:
v4:
- Document limitation about potential deadlocks.
Should we provide thread-unsafe versions of these functions as well?
v3:
- Made API experimental
- Compile fixes
lib/librte_eal/common/eal_common_memalloc.c | 133 ++++++++++++++++++++++++++++ lib/librte_eal/common/eal_common_memory.c | 28 ++++++ lib/librte_eal/common/eal_memalloc.h | 11 +++ lib/librte_eal/common/include/rte_memory.h | 71 +++++++++++++++ lib/librte_eal/rte_eal_version.map | 2 + 5 files changed, 245 insertions(+)
lib/librte_eal/common/eal_common_memalloc.c +133 -0
@@ -2,16 +2,46 @@* Copyright(c) 2017-2018 Intel Corporation */ +#include <string.h> + +#include <rte_errno.h> #include <rte_lcore.h> #include <rte_fbarray.h> #include <rte_memzone.h> #include <rte_memory.h> #include <rte_eal_memconfig.h> +#include <rte_rwlock.h> #include "eal_private.h" #include "eal_internal_cfg.h" #include "eal_memalloc.h" +struct mem_event_callback_entry { +TAILQ_ENTRY (mem_event_callback_entry) next; +char name[RTE_MEM_EVENT_CALLBACK_NAME_LEN ]; +rte_mem_event_callback_t clb; +}; + +/** Double linked list of actions. */ +TAILQ_HEAD (mem_event_callback_entry_list, mem_event_callback_entry); + +static struct mem_event_callback_entry_list mem_event_callback_list = +TAILQ_HEAD_INITIALIZER (mem_event_callback_list); + +static rte_rwlock_t mem_event_rwlock =RTE_RWLOCK_INITIALIZER ; + +static struct mem_event_callback_entry * +find_mem_event_callback (const char *name) +{ +struct mem_event_callback_entry *r; + + TAILQ_FOREACH(r, &mem_event_callback_list, next) { +if (!strcmp (r->name, name)) +break ; + } +return r; +} +bool eal_memalloc_is_contig (const struct rte_memseg_list *msl,void *start,size_t len)
@@ -88,3 +118,106 @@ eal_memalloc_is_contig(const struct rte_memseg_list *msl, void *start, }return true; } + +int +eal_memalloc_mem_event_callback_register (const char *name, +rte_mem_event_callback_t clb) +{ +struct mem_event_callback_entry *entry; +int ret, len; +if (name ==NULL || clb ==NULL ) { + rte_errno =EINVAL ; +return -1 ; + } + len =strnlen (name,RTE_MEM_EVENT_CALLBACK_NAME_LEN ); +if (len ==0 ) { + rte_errno =EINVAL ; +return -1 ; + }else if (len ==RTE_MEM_EVENT_CALLBACK_NAME_LEN ) { + rte_errno =ENAMETOOLONG ; +return -1 ; + } +rte_rwlock_write_lock (&mem_event_rwlock); + + entry =find_mem_event_callback (name); +if (entry !=NULL ) { + rte_errno =EEXIST ; + ret =-1 ; + goto unlock; + } + + entry =malloc (sizeof (*entry)); +if (entry ==NULL ) { + rte_errno =ENOMEM ; + ret =-1 ; + goto unlock; + } + +/* callback successfully created and is valid, add it to the list */ + entry->clb = clb; +snprintf (entry->name,RTE_MEM_EVENT_CALLBACK_NAME_LEN ,"%s" , name); +TAILQ_INSERT_TAIL (&mem_event_callback_list, entry, next); + + ret =0 ; + +RTE_LOG (DEBUG ,EAL ,"Mem event callback '%s' registered\n" , name); + +unlock: +rte_rwlock_write_unlock (&mem_event_rwlock); +return ret; +} + +int +eal_memalloc_mem_event_callback_unregister (const char *name) +{ +struct mem_event_callback_entry *entry; +int ret, len; + +if (name ==NULL ) { + rte_errno =EINVAL ; +return -1 ; + } + len =strnlen (name,RTE_MEM_EVENT_CALLBACK_NAME_LEN ); +if (len ==0 ) { + rte_errno =EINVAL ; +return -1 ; + }else if (len ==RTE_MEM_EVENT_CALLBACK_NAME_LEN ) { + rte_errno =ENAMETOOLONG ; +return -1 ; + } +rte_rwlock_write_lock (&mem_event_rwlock); + + entry =find_mem_event_callback (name); +if (entry ==NULL ) { + rte_errno =ENOENT ; + ret =-1 ; + goto unlock; + } +TAILQ_REMOVE (&mem_event_callback_list, entry, next); +free (entry); + + ret =0 ; + +RTE_LOG (DEBUG ,EAL ,"Mem event callback '%s' unregistered\n" , name); + +unlock: +rte_rwlock_write_unlock (&mem_event_rwlock); +return ret; +} + +void +eal_memalloc_mem_event_notify (enum rte_mem_event event,const void *start, +size_t len) +{ +struct mem_event_callback_entry *entry; + +rte_rwlock_read_lock (&mem_event_rwlock); + + TAILQ_FOREACH(entry, &mem_event_callback_list, next) { +RTE_LOG (DEBUG ,EAL ,"Calling mem event callback %s" , + entry->name); + entry->clb (event, start, len); + } + +rte_rwlock_read_unlock (&mem_event_rwlock); +}
lib/librte_eal/common/eal_common_memory.c +28 -0
@@ -623,6 +623,34 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,return 0 ; } +/* +* Defining here because declared in rte_memory.h, but the actual implementation +* is in eal_common_memalloc.c, like all other memalloc internals. +*/ +int __rte_experimental +rte_mem_event_callback_register (const char *name,rte_mem_event_callback_t clb) +{ +/* FreeBSD boots with legacy mem enabled by default */ +if (internal_config.legacy_mem) { +RTE_LOG (DEBUG ,EAL ,"Registering mem event callbacks not supported\n" ); + rte_errno =ENOTSUP ; +return -1 ; + } +return eal_memalloc_mem_event_callback_register (name, clb); +} + +int __rte_experimental +rte_mem_event_callback_unregister (const char *name) +{ +/* FreeBSD boots with legacy mem enabled by default */ +if (internal_config.legacy_mem) { +RTE_LOG (DEBUG ,EAL ,"Registering mem event callbacks not supported\n" ); + rte_errno =ENOTSUP ; +return -1 ; + } +return eal_memalloc_mem_event_callback_unregister (name); +} +/* Dump the physical memory layout on console */ void rte_dump_physmem_layout (FILE *f)
lib/librte_eal/common/eal_memalloc.h +11 -0
@@ -56,4 +56,15 @@ eal_memalloc_is_contig(const struct rte_memseg_list *msl, void *start,int eal_memalloc_sync_with_primary (void ); +int +eal_memalloc_mem_event_callback_register (const char *name, +rte_mem_event_callback_t clb); + +int +eal_memalloc_mem_event_callback_unregister (const char *name); + +void +eal_memalloc_mem_event_notify (enum rte_mem_event event,const void *start, +size_t len); +#endif // EAL_MEMALLOC_H
lib/librte_eal/common/include/rte_memory.h +71 -0
113 lines not on this page · raw message
lib/librte_eal/rte_eal_version.map +2 -0
@@ -238,6 +238,8 @@ EXPERIMENTAL { rte_fbarray_set_used; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; + rte_mem_event_callback_register; + rte_mem_event_callback_unregister; rte_mem_iova2virt; rte_mem_virt2memseg; rte_mem_virt2memseg_list;
Signature · 1 line
2.7.4
PATCH v4 63/70 eal: enable callbacks on malloc/free and mp sync
In reply to Anatoly BurakovCallbacks will be triggered just after allocation and just before deallocation, to ensure that memory address space referenced in the callback is always valid by the time callback is called.
--- lib/librte_eal/common/malloc_heap.c | 21 +++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_memalloc.c | 30 ++++++++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_vfio.c | 15 +++++++++++++-- 3 files changed, 64 insertions(+), 2 deletions(-)
lib/librte_eal/common/malloc_heap.c +21 -0
@@ -241,6 +241,7 @@ try_expand_heap_primary(struct malloc_heap *heap, uint64_t pg_sz,void *map_addr;size_t alloc_sz;int n_segs; +bool callback_triggered = false; alloc_sz =RTE_ALIGN_CEIL (align + elt_size +MALLOC_ELEM_TRAILER_LEN , pg_sz);
@@ -262,12 +263,22 @@ try_expand_heap_primary(struct malloc_heap *heap, uint64_t pg_sz, map_addr = ms[0 ]->addr; +/* notify user about changes in memory map */ +eal_memalloc_mem_event_notify (RTE_MEM_EVENT_ALLOC , map_addr, alloc_sz); +/* notify other processes that this has happened */ if (request_sync ()) {/* we couldn't ensure all processes have mapped memory, * so free it back and notify everyone that it's been * freed back. +* +* technically, we could've avoided adding memory addresses to +* the map, but that would've led to inconsistent behavior +* between primary and secondary processes, as those get +* callbacks during sync. therefore, force primary process to +* do alloc-and-rollback syncs as well. */ + callback_triggered = true; goto free_elem; } heap->total_size += alloc_sz;
@@ -280,6 +291,10 @@ try_expand_heap_primary(struct malloc_heap *heap, uint64_t pg_sz,return 0 ; free_elem: +if (callback_triggered) +eal_memalloc_mem_event_notify (RTE_MEM_EVENT_FREE , + map_addr, alloc_sz); +rollback_expand_heap (ms, n_segs, elem, map_addr, alloc_sz);request_sync ();
@@ -642,6 +657,10 @@ malloc_heap_free(struct malloc_elem *elem) heap->total_size -= aligned_len;if (rte_eal_process_type () ==RTE_PROC_PRIMARY ) { +/* notify user about changes in memory map */ +eal_memalloc_mem_event_notify (RTE_MEM_EVENT_FREE , + aligned_start, aligned_len); +/* don't care if any of this fails */ malloc_heap_free_pages (aligned_start, aligned_len);
@@ -666,6 +685,8 @@ malloc_heap_free(struct malloc_elem *elem)* already removed from the heap, so it is, for all intents and * purposes, hidden from the rest of DPDK even if some other * process (including this one) may have these pages mapped. +* +* notifications about deallocated memory happen during sync. */ request_to_primary (&req); }
lib/librte_eal/linuxapp/eal/eal_memalloc.c +30 -0
@@ -877,6 +877,21 @@ sync_chunk(struct rte_memseg_list *primary_msl, diff_len =RTE_MIN (chunk_len, diff_len); +/* if we are freeing memory, notify the application */ +if (!used) { +struct rte_memseg *ms; +void *start_va; +size_t len, page_sz; + + ms =rte_fbarray_get (l_arr, start); + start_va = ms->addr; + page_sz = (size_t )primary_msl->page_sz; + len = page_sz * diff_len; + +eal_memalloc_mem_event_notify (RTE_MEM_EVENT_FREE , + start_va, len); + } +for (i =0 ; i < diff_len; i++) {struct rte_memseg *p_ms, *l_ms;int seg_idx = start + i;
@@ -902,6 +917,21 @@ sync_chunk(struct rte_memseg_list *primary_msl, } } +/* if we just allocated memory, notify the application */ +if (used) { +struct rte_memseg *ms; +void *start_va; +size_t len, page_sz; + + ms =rte_fbarray_get (l_arr, start); + start_va = ms->addr; + page_sz = (size_t )primary_msl->page_sz; + len = page_sz * diff_len; + +eal_memalloc_mem_event_notify (RTE_MEM_EVENT_ALLOC , + start_va, len); + } +/* calculate how much we can advance until next chunk */ diff_len = used ? rte_fbarray_find_contig_used(l_arr, start) :
lib/librte_eal/linuxapp/eal/eal_vfio.c +13 -2
@@ -895,6 +895,7 @@ vfio_spapr_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova, create.levels =1 ;if (do_map) { +void *addr;/* re-create window and remap the entire memory */ if (iova > create.window_size) { if (vfio_spapr_create_new_dma_window(vfio_container_fd,
@@ -910,9 +911,19 @@ vfio_spapr_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova, }/* now that we've remapped all of the memory that was present * before, map the segment that we were requested to map. +* +* however, if we were called by the callback, the memory we +* were called with was already in the memseg list, so previous +* mapping should've mapped that segment already. +* +* virt2memseg_list is a relatively cheap check, so use that. if +* memory is within any memseg list, it's a memseg, so it's +* already mapped. */ -if (vfio_spapr_dma_do_map (vfio_container_fd, - vaddr, iova, len,1 ) <0 ) { + addr = (void *)(uintptr_t )vaddr; +if (rte_mem_virt2memseg_list (addr) ==NULL && +vfio_spapr_dma_do_map (vfio_container_fd, + vaddr, iova, len,1 ) <0 ) {RTE_LOG (ERR ,EAL ,"Could not map segment\n" );return -1 ; }
Signature · 1 line
2.7.4
PATCH v4 64/70 vfio: enable support for mem event callbacks
In reply to Anatoly BurakovEnable callbacks on first device attach, disable callbacks on last device attach.
PPC64 IOMMU does memseg walk, which will cause a deadlock on trying to do it inside a callback, so provide a local, thread-unsafe copy of memseg walk.
---
Notes:
v4:
- Fix PPC64 memseg walk in callback
- Check if registering callbacks succeeded
v3:
- Moved callbacks to attach/detach as opposed to init
v4:
- Fix PPC64 memseg walk in callback
v3:
- Moved callbacks to attach/detach as opposed to init
lib/librte_eal/linuxapp/eal/eal_vfio.c | 133 +++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 8 deletions(-)
lib/librte_eal/linuxapp/eal/eal_vfio.c +125 -8
@@ -7,6 +7,7 @@#include <unistd.h> #include <sys/ioctl.h> +#include <rte_errno.h> #include <rte_log.h> #include <rte_memory.h> #include <rte_eal_memconfig.h>
@@ -18,6 +19,8 @@#ifdef VFIO_PRESENT +#define VFIO_MEM_EVENT_CLB_NAME "vfio_mem_event_clb" +/* per-process VFIO config */ static struct vfio_config vfio_cfg;
@@ -53,6 +56,42 @@ static const struct vfio_iommu_type iommu_types[] = { }, }; +/* for sPAPR IOMMU, we will need to walk memseg list, but we cannot use +* rte_memseg_walk() because by the time we enter callback we will be holding a +* write lock, so regular rte-memseg_walk will deadlock. copying the same +* iteration code everywhere is not ideal as well. so, use a lockless copy of +* memseg walk here. +*/ +static int +memseg_walk_thread_unsafe (rte_memseg_walk_t func,void *arg) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +int i, ms_idx, ret =0 ; + +for (i =0 ; i <RTE_MAX_MEMSEG_LISTS ; i++) { +struct rte_memseg_list *msl = &mcfg->memsegs[i]; +const struct rte_memseg *ms; +struct rte_fbarray *arr; + +if (msl->memseg_arr.count ==0 ) +continue ; + + arr = &msl->memseg_arr; + + ms_idx =rte_fbarray_find_next_used (arr,0 ); +while (ms_idx >=0 ) { + ms =rte_fbarray_get (arr, ms_idx); + ret =func (msl, ms, arg); +if (ret <0 ) +return -1 ; +if (ret >0 ) +return 1 ; + ms_idx =rte_fbarray_find_next_used (arr, ms_idx +1 ); + } + } +return 0 ; +} +int vfio_get_group_fd (int iommu_group_no) {
@@ -214,6 +253,38 @@ vfio_group_device_count(int vfio_group_fd)return vfio_cfg.vfio_groups[i].devices; } +static void +vfio_mem_event_callback (enum rte_mem_event type,const void *addr,size_t len) +{ +struct rte_memseg_list *msl; +struct rte_memseg *ms; +size_t cur_len =0 ; + + msl =rte_mem_virt2memseg_list (addr); + +/* for IOVA as VA mode, no need to care for IOVA addresses */ +if (rte_eal_iova_mode () ==RTE_IOVA_VA ) { +uint64_t vfio_va = (uint64_t )(uintptr_t )addr; +if (type ==RTE_MEM_EVENT_ALLOC ) +rte_vfio_dma_map (vfio_va, vfio_va, len); +else +rte_vfio_dma_unmap (vfio_va, vfio_va, len); +return ; + } + +/* memsegs are contiguous in memory */ + ms =rte_mem_virt2memseg (addr, msl); +while (cur_len < len) { +if (type ==RTE_MEM_EVENT_ALLOC ) +rte_vfio_dma_map (ms->addr_64, ms->iova, ms->len); +else +rte_vfio_dma_unmap (ms->addr_64, ms->iova, ms->len); + + cur_len += ms->len; + ++ms; + } +} +int rte_vfio_clear_group (int vfio_group_fd) {
@@ -276,6 +347,8 @@ int rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, int *vfio_dev_fd, struct vfio_device_info *device_info) { + struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; +rte_rwlock_t *mem_lock = &mcfg->memory_hotplug_lock;struct vfio_group_status group_status = { .argsz =sizeof (group_status) };
@@ -363,6 +436,10 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr,rte_vfio_clear_group (vfio_group_fd);return -1 ; } +/* lock memory hotplug before mapping and release it +* after registering callback, to prevent races +*/ +rte_rwlock_read_lock (mem_lock); ret = t->dma_map_func (vfio_cfg.vfio_container_fd);if (ret) { RTE_LOG(ERR, EAL,
@@ -370,10 +447,26 @@ rte_vfio_setup_device(const char *sysfs_base, const char *dev_addr, dev_addr, errno, strerror(errno));close (vfio_group_fd);rte_vfio_clear_group (vfio_group_fd); +rte_rwlock_read_unlock (mem_lock);return -1 ; } vfio_cfg.vfio_iommu_type = t; + +/* register callback for mem events */ + ret =rte_mem_event_callback_register ( +VFIO_MEM_EVENT_CLB_NAME , + vfio_mem_event_callback); +/* unlock memory hotplug */ +rte_rwlock_read_unlock (mem_lock); +if (ret && rte_errno ==ENOTSUP ) { +RTE_LOG (DEBUG ,EAL ,"Memory event callbacks not supported\n" ); + }else if (ret) { +RTE_LOG (ERR ,EAL ,"Could not install memory event callback for VFIO\n" ); +return -1 ; + }else { +RTE_LOG (DEBUG ,EAL ,"Installed memory event callback for VFIO\n" ); + } } }
@@ -411,6 +504,8 @@ int rte_vfio_release_device(const char *sysfs_base, const char *dev_addr, int vfio_dev_fd) { + struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; +rte_rwlock_t *mem_lock = &mcfg->memory_hotplug_lock;struct vfio_group_status group_status = { .argsz =sizeof (group_status) };
@@ -418,13 +513,20 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,int iommu_group_no;int ret; +/* we don't want any DMA mapping messages to come while we're detaching +* VFIO device, because this might be the last device and we might need +* to unregister the callback. +*/ +rte_rwlock_read_lock (mem_lock); +/* get group number */ ret =vfio_get_group_no (sysfs_base, dev_addr, &iommu_group_no);if (ret <=0 ) {RTE_LOG (WARNING ,EAL ," %s not managed by VFIO driver\n" , dev_addr);/* This is an error at this point. */ -return -1 ; + ret =-1 ; + goto out; }/* get the actual group fd */
@@ -432,7 +534,8 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,if (vfio_group_fd <=0 ) {RTE_LOG (INFO ,EAL ,"vfio_get_group_fd failed for %s\n" , dev_addr); -return -1 ; + ret =-1 ; + goto out; }/* At this point we got an active group. Closing it will make the
@@ -444,7 +547,8 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,if (close (vfio_dev_fd) <0 ) {RTE_LOG (INFO ,EAL ,"Error when closing vfio_dev_fd for %s\n" , dev_addr); -return -1 ; + ret =-1 ; + goto out; }/* An VFIO group can have several devices attached. Just when there is
@@ -456,17 +560,30 @@ rte_vfio_release_device(const char *sysfs_base, const char *dev_addr,if (close (vfio_group_fd) <0 ) {RTE_LOG (INFO ,EAL ,"Error when closing vfio_group_fd for %s\n" , dev_addr); -return -1 ; + ret =-1 ; + goto out; }if (rte_vfio_clear_group (vfio_group_fd) <0 ) {RTE_LOG (INFO ,EAL ,"Error when clearing group for %s\n" , dev_addr); -return -1 ; + ret =-1 ; + goto out; } } -return 0 ; +/* if there are no active device groups, unregister the callback to +* avoid spurious attempts to map/unmap memory from VFIO. +*/ +if (vfio_cfg.vfio_active_groups ==0 ) +rte_mem_event_callback_unregister (VFIO_MEM_EVENT_CLB_NAME ); + +/* success */ + ret =0 ; + +out: +rte_rwlock_read_unlock (mem_lock); +return ret; }int
@@ -884,7 +1001,7 @@ vfio_spapr_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova,/* check if window size needs to be adjusted */ memset (¶m,0 ,sizeof (param)); -if (rte_memseg_walk (vfio_spapr_window_size_walk, ¶m) <0 ) { +if (memseg_walk_thread_unsafe (vfio_spapr_window_size_walk, ¶m) <0 ) {RTE_LOG (ERR ,EAL ,"Could not get window size\n" );return -1 ; }
@@ -903,7 +1020,7 @@ vfio_spapr_dma_mem_map(int vfio_container_fd, uint64_t vaddr, uint64_t iova,RTE_LOG (ERR ,EAL ,"Could not create new DMA window\n" );return -1 ; } -if (rte_memseg_walk (vfio_spapr_map_walk, +if (memseg_walk_thread_unsafe (vfio_spapr_map_walk, &vfio_container_fd) <0 ) {RTE_LOG (ERR ,EAL ,"Could not recreate DMA maps\n" );return -1 ;
Signature · 1 line
2.7.4
PATCH v4 65/70 bus/fslmc: move vfio DMA map into bus probe
In reply to Anatoly Burakovfslmc bus needs to map all allocated memory for VFIO before device probe. This bus doesn't support hotplug, so at the time of this call, all possible device that could be present, are present. This will also be the place where we install VFIO callback, although this change will come in the next patch.
Since rte_fslmc_vfio_dmamap() is now only called at bus probe, there is no longer any need to check if DMA mappings have been already done.
--- drivers/bus/fslmc/fslmc_bus.c | 11 +++++++++++ drivers/bus/fslmc/fslmc_vfio.c | 6 ------ drivers/net/dpaa2/dpaa2_ethdev.c | 1 - 3 files changed, 11 insertions(+), 7 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +11 -0
@@ -286,6 +286,17 @@ rte_fslmc_probe(void)return 0 ; } +/* Map existing segments as well as, in case of hotpluggable memory, +* install callback handler. +*/ + ret =rte_fslmc_vfio_dmamap (); +if (ret) { +DPAA2_BUS_ERR ("Unable to DMA map existing VAs: (%d)" , ret); +/* Not continuing ahead */ +DPAA2_BUS_ERR ("FSLMC VFIO Mapping failed" ); +return 0 ; + } + ret =fslmc_vfio_process_group ();if (ret) {DPAA2_BUS_ERR ("Unable to setup devices %d" , ret);
drivers/bus/fslmc/fslmc_vfio.c +0 -6
@@ -51,7 +51,6 @@ static int container_device_fd;static char *g_container;static uint32_t *msi_intr_vaddr;void *(*rte_mcp_ptr_list); -static int is_dma_done;static struct rte_dpaa2_object_list dpaa2_obj_list =TAILQ_HEAD_INITIALIZER (dpaa2_obj_list);
@@ -235,9 +234,6 @@ int rte_fslmc_vfio_dmamap(void) {int i =0 ; -if (is_dma_done) -return 0 ; -if (rte_memseg_walk (fslmc_vfio_map, &i) <0 )return -1 ;
@@ -254,8 +250,6 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region (&vfio_group); - is_dma_done =1 ; -return 0 ; }
drivers/net/dpaa2/dpaa2_ethdev.c +0 -1
@@ -1845,7 +1845,6 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev) eth_dev->rx_pkt_burst = dpaa2_dev_prefetch_rx; eth_dev->tx_pkt_burst = dpaa2_dev_tx; -rte_fslmc_vfio_dmamap ();DPAA2_PMD_INFO ("%s: netdev created" , eth_dev->data->name);return 0 ;
Signature · 1 line
2.7.4
PATCH v4 66/70 bus/fslmc: enable support for mem event callbacks for vfio
In reply to Anatoly BurakovVFIO needs to map and unmap segments for DMA whenever they become available or unavailable, so register a callback for memory events, and provide map/unmap functions.
--- drivers/bus/fslmc/fslmc_vfio.c | 150 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 14 deletions(-)
drivers/bus/fslmc/fslmc_vfio.c +136 -14
@@ -30,6 +30,7 @@#include <rte_kvargs.h> #include <rte_dev.h> #include <rte_bus.h> +#include <rte_eal_memconfig.h> #include "rte_fslmc.h" #include "fslmc_vfio.h"
@@ -188,11 +189,57 @@ static int vfio_map_irq_region(struct fslmc_vfio_group *group)return -errno; } +static int fslmc_map_dma (uint64_t vaddr,rte_iova_t iovaddr,size_t len); +static int fslmc_unmap_dma (uint64_t vaddr,rte_iova_t iovaddr,size_t len); + +static void +fslmc_memevent_cb (enum rte_mem_event type,const void *addr,size_t len) +{ +struct rte_memseg_list *msl; +struct rte_memseg *ms; +size_t cur_len =0 , map_len =0 ; +uint64_t virt_addr; +rte_iova_t iova_addr; +int ret; + + msl =rte_mem_virt2memseg_list (addr); + +while (cur_len < len) { +const void *va =RTE_PTR_ADD (addr, cur_len); + + ms =rte_mem_virt2memseg (va, msl); + iova_addr = ms->iova; + virt_addr = ms->addr_64; + map_len = ms->len; + +DPAA2_BUS_DEBUG ("Calling with type=%d, va=%p, virt_addr=0x%" PRIx64", iova=0x%" PRIx64", map_len=%zu\n" , + type, va, virt_addr, iova_addr, map_len); + +if (type ==RTE_MEM_EVENT_ALLOC ) + ret =fslmc_map_dma (virt_addr, iova_addr, map_len); +else + ret =fslmc_unmap_dma (virt_addr, iova_addr, map_len); + +if (ret !=0 ) { +DPAA2_BUS_ERR ("DMA Mapping/Unmapping failed. Map=%d, addr=%p, len=%zu, err:(%d)" , + type, va, map_len, ret); +return ; + } + + cur_len += map_len; + } + +if (type ==RTE_MEM_EVENT_ALLOC ) +DPAA2_BUS_DEBUG ("Total Mapped: addr=%p, len=%zu\n" , + addr, len); +else +DPAA2_BUS_DEBUG ("Total Unmapped: addr=%p, len=%zu\n" , + addr, len); +} +static int -fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, -const struct rte_memseg *ms,void *arg) +fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr __rte_unused, size_t len) { -int *n_segs = arg;struct fslmc_vfio_group *group;struct vfio_iommu_type1_dma_map dma_map = { .argsz =sizeof (struct vfio_iommu_type1_dma_map ),
@@ -200,10 +247,11 @@ fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, };int ret; - dma_map.size = ms->len; - dma_map.vaddr = ms->addr_64; + dma_map.size = len; + dma_map.vaddr = vaddr; +#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA - dma_map.iova = ms->iova; + dma_map.iova = iovaddr;#else dma_map.iova = dma_map.vaddr;#endif
@@ -216,30 +264,99 @@ fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused,return -1 ; } -DPAA2_BUS_DEBUG ("-->Initial SHM Virtual ADDR %llX" , - dma_map.vaddr); -DPAA2_BUS_DEBUG ("-----> DMA size 0x%llX" , dma_map.size); - ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , - &dma_map); +DPAA2_BUS_DEBUG ("--> Map address: %llX, size: 0x%llX\n" , + dma_map.vaddr, dma_map.size); + ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , &dma_map);if (ret) {DPAA2_BUS_ERR ("VFIO_IOMMU_MAP_DMA API(errno = %d)" , errno);return -1 ; } - (*n_segs)++; +return 0 ; } +static int +fslmc_unmap_dma(uint64_t vaddr, uint64_t iovaddr __rte_unused, size_t len) +{ +struct fslmc_vfio_group *group; +struct vfio_iommu_type1_dma_unmap dma_unmap = { + .argsz =sizeof (struct vfio_iommu_type1_dma_unmap ), + .flags =0 , + }; +int ret; + + dma_unmap.size = len; + dma_unmap.iova = vaddr; + +/* SET DMA MAP for IOMMU */ + group = &vfio_group; + +if (!group->container) { +DPAA2_BUS_ERR ("Container is not connected " ); +return -1 ; + } + +DPAA2_BUS_DEBUG ("--> Unmap address: %llX, size: 0x%llX\n" , + dma_unmap.iova, dma_unmap.size); + ret =ioctl (group->container->fd,VFIO_IOMMU_UNMAP_DMA , &dma_unmap); +if (ret) { +DPAA2_BUS_ERR ("VFIO_IOMMU_UNMAP_DMA API(errno = %d)" , + errno); +return -1 ; + } + +return 0 ; +} + +static int +fslmc_dmamap_seg(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) +{ +int *n_segs = arg; +int ret; + + ret =fslmc_map_dma (ms->addr_64, ms->iova, ms->len); +if (ret) +DPAA2_BUS_ERR ("Unable to VFIO map (addr=%p, len=%zu)\n" , + ms->addr, ms->len); +else + (*n_segs)++; + +return ret; +} +int rte_fslmc_vfio_dmamap (void ) { -int i =0 ; +int i =0 , ret; +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +rte_rwlock_t *mem_lock = &mcfg->memory_hotplug_lock; + +/* Lock before parsing and registering callback to memory subsystem */ +rte_rwlock_read_lock (mem_lock); -if (rte_memseg_walk (fslmc_vfio_map, &i) <0 ) +if (rte_memseg_walk (fslmc_dmamap_seg, &i) <0 ) { +rte_rwlock_read_unlock (mem_lock);return -1 ; + } + + ret =rte_mem_event_callback_register ("fslmc_memevent_clb" , + fslmc_memevent_cb); +if (ret && rte_errno ==ENOTSUP ) +DPAA2_BUS_DEBUG ("Memory event callbacks not supported" ); +else if (ret) +DPAA2_BUS_DEBUG ("Unable to install memory handler" ); +else +DPAA2_BUS_DEBUG ("Installed memory callback handler" );/* Verifying that at least single segment is available */ if (i <=0 ) { +/* TODO: Is this verification required any more? What would +* happen to non-legacy case where nothing was preallocated +* thus causing i==0? +*/ DPAA2_BUS_ERR ("No Segments found for VFIO Mapping" ); +rte_rwlock_read_unlock (mem_lock);return -1 ; }DPAA2_BUS_DEBUG ("Total %d segments found." , i);
@@ -250,6 +367,11 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region (&vfio_group); +/* Existing segments have been mapped and memory callback for hotplug +* has been installed. +*/ +rte_rwlock_read_unlock (mem_lock); +return 0 ; }
Signature · 1 line
2.7.4
Re: [PATCH v4 66/70] bus/fslmc: enable support for mem event callbacks for vfio
Hi Anatoly,
Quoted 40 lines · Anatoly Burakov
VFIO needs to map and unmap segments for DMA whenever they become available or unavailable, so register a callback for memory events, and provide map/unmap functions.
Signed-off-by Shreyansh Jain <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- drivers/bus/fslmc/fslmc_vfio.c | 150 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 14 deletions(-)drivers/bus/fslmc/fslmc_vfio.c +15
-0@@ -30,6 +30,7 @@#include <rte_kvargs.h> #include <rte_dev.h> #include <rte_bus.h> +#include <rte_eal_memconfig.h> #include "rte_fslmc.h" #include "fslmc_vfio.h" @@ -188,11 +189,57 @@ static int vfio_map_irq_region(struct fslmc_vfio_group *group)return -errno; } +static int fslmc_map_dma (uint64_t vaddr,rte_iova_t iovaddr,size_t len); +static int fslmc_unmap_dma (uint64_t vaddr,rte_iova_t iovaddr,size_t len); + +static void +fslmc_memevent_cb (enum rte_mem_event type,const void *addr,size_t len) +{ +struct rte_memseg_list *msl; +struct rte_memseg *ms; +size_t cur_len =0 , map_len =0 ; +uint64_t virt_addr; +rte_iova_t iova_addr; +int ret; + + msl =rte_mem_virt2memseg_list (addr);
drivers/bus/fslmc/fslmc_vfio.c static int vfio_map_irq_region(struct fslmc_vfio_group *group) · line 215
Quoted 10 lines
drivers/bus/fslmc/fslmc_vfio.c +10
-0+ +while (cur_len < len) { +const void *va =RTE_PTR_ADD (addr, cur_len); + + ms =rte_mem_virt2memseg (va, msl); + iova_addr = ms->iova; + virt_addr = ms->addr_64; + map_len = ms->len; + + DPAA2_BUS_DEBUG("Calling with type=%d, va=%p, virt_addr=0x%" PRIx64 ", iova=0x%" PRIx64 ", map_len=%zu\n",
I would like to correct this message (80char + rewording) - What do you suggest? Should I send a new patch to you or just convey what should be changed?
drivers/bus/fslmc/fslmc_vfio.c static int vfio_map_irq_region(struct fslmc_vfio_group *group) · line 225
Quoted 10 lines
drivers/bus/fslmc/fslmc_vfio.c +10
-0+ type, va, virt_addr, iova_addr, map_len); + +if (type ==RTE_MEM_EVENT_ALLOC ) + ret =fslmc_map_dma (virt_addr, iova_addr, map_len); +else + ret =fslmc_unmap_dma (virt_addr, iova_addr, map_len); + +if (ret !=0 ) { +DPAA2_BUS_ERR ("DMA Mapping/Unmapping failed. Map=%d, addr=%p, len=%zu, err:(%d)" , + type, va, map_len, ret);
Same as above. 80 Char issue.
Quoted 131 lines
drivers/bus/fslmc/fslmc_vfio.c +88
-14+return ; + } + + cur_len += map_len; + } + +if (type ==RTE_MEM_EVENT_ALLOC ) +DPAA2_BUS_DEBUG ("Total Mapped: addr=%p, len=%zu\n" , + addr, len); +else +DPAA2_BUS_DEBUG ("Total Unmapped: addr=%p, len=%zu\n" , + addr, len); +} +static int -fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, -const struct rte_memseg *ms,void *arg) +fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr __rte_unused, size_t len) { -int *n_segs = arg;struct fslmc_vfio_group *group;struct vfio_iommu_type1_dma_map dma_map = { .argsz =sizeof (struct vfio_iommu_type1_dma_map ),@@ -200,10 +247,11 @@ fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, };int ret; - dma_map.size = ms->len; - dma_map.vaddr = ms->addr_64; + dma_map.size = len; + dma_map.vaddr = vaddr; +#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA - dma_map.iova = ms->iova; + dma_map.iova = iovaddr;#else dma_map.iova = dma_map.vaddr;#endif @@ -216,30 +264,99 @@ fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused,return -1 ; } -DPAA2_BUS_DEBUG ("-->Initial SHM Virtual ADDR %llX" , - dma_map.vaddr); -DPAA2_BUS_DEBUG ("-----> DMA size 0x%llX" , dma_map.size); - ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , - &dma_map); +DPAA2_BUS_DEBUG ("--> Map address: %llX, size: 0x%llX\n" , + dma_map.vaddr, dma_map.size); + ret =ioctl (group->container->fd,VFIO_IOMMU_MAP_DMA , &dma_map);if (ret) {DPAA2_BUS_ERR ("VFIO_IOMMU_MAP_DMA API(errno = %d)" , errno);return -1 ; } - (*n_segs)++; +return 0 ; } +static int +fslmc_unmap_dma(uint64_t vaddr, uint64_t iovaddr __rte_unused, size_t len) +{ +struct fslmc_vfio_group *group; +struct vfio_iommu_type1_dma_unmap dma_unmap = { + .argsz =sizeof (struct vfio_iommu_type1_dma_unmap ), + .flags =0 , + }; +int ret; + + dma_unmap.size = len; + dma_unmap.iova = vaddr; + +/* SET DMA MAP for IOMMU */ + group = &vfio_group; + +if (!group->container) { +DPAA2_BUS_ERR ("Container is not connected " ); +return -1 ; + } + +DPAA2_BUS_DEBUG ("--> Unmap address: %llX, size: 0x%llX\n" , + dma_unmap.iova, dma_unmap.size); + ret =ioctl (group->container->fd,VFIO_IOMMU_UNMAP_DMA , &dma_unmap); +if (ret) { +DPAA2_BUS_ERR ("VFIO_IOMMU_UNMAP_DMA API(errno = %d)" , + errno); +return -1 ; + } + +return 0 ; +} + +static int +fslmc_dmamap_seg(const struct rte_memseg_list *msl __rte_unused, +const struct rte_memseg *ms,void *arg) +{ +int *n_segs = arg; +int ret; + + ret =fslmc_map_dma (ms->addr_64, ms->iova, ms->len); +if (ret) +DPAA2_BUS_ERR ("Unable to VFIO map (addr=%p, len=%zu)\n" , + ms->addr, ms->len); +else + (*n_segs)++; + +return ret; +} +int rte_fslmc_vfio_dmamap (void ) { -int i =0 ; +int i =0 , ret; +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +rte_rwlock_t *mem_lock = &mcfg->memory_hotplug_lock; + +/* Lock before parsing and registering callback to memory subsystem */ +rte_rwlock_read_lock (mem_lock); -if (rte_memseg_walk (fslmc_vfio_map, &i) <0 ) +if (rte_memseg_walk (fslmc_dmamap_seg, &i) <0 ) { +rte_rwlock_read_unlock (mem_lock);return -1 ; + } + + ret =rte_mem_event_callback_register ("fslmc_memevent_clb" , + fslmc_memevent_cb); +if (ret && rte_errno ==ENOTSUP ) +DPAA2_BUS_DEBUG ("Memory event callbacks not supported" ); +else if (ret)
drivers/bus/fslmc/fslmc_vfio.c fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused, · line 357
Quoted 10 lines
drivers/bus/fslmc/fslmc_vfio.c +7
-0+DPAA2_BUS_DEBUG ("Unable to install memory handler" ); + else + DPAA2_BUS_DEBUG("Installed memory callback handler");/* Verifying that at least single segment is available */ if (i <=0 ) { +/* TODO: Is this verification required any more? What would +* happen to non-legacy case where nothing was preallocated +* thus causing i==0? +*/
And this as well - if call backs are not going to appear in case of legacy, this needs to be removed. let me know how do you want to take these changes.
Quoted 18 lines
drivers/bus/fslmc/fslmc_vfio.c +6
-0DPAA2_BUS_ERR ("No Segments found for VFIO Mapping" ); +rte_rwlock_read_unlock (mem_lock);return -1 ; }DPAA2_BUS_DEBUG ("Total %d segments found." , i);@@ -250,6 +367,11 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region (&vfio_group); +/* Existing segments have been mapped and memory callback for hotplug +* has been installed. +*/ +rte_rwlock_read_unlock (mem_lock); +return 0 ; }
Re: [PATCH v4 66/70] bus/fslmc: enable support for mem event callbacks for vfio
Quoted 10 lines · Shreyansh Jain
Hi Anatoly,
Quoted 7 lines · Anatoly Burakov
VFIO needs to map and unmap segments for DMA whenever they become available or unavailable, so register a callback for memory events, and provide map/unmap functions.
Signed-off-by Shreyansh Jain <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
<...>
Quoted 5 lines
Quoted 2 lines
+ DPAA2_BUS_DEBUG("Calling with type=%d, va=%p, virt_addr=0x%" PRIx64 ", iova=0x%" PRIx64 ", map_len=%zu\n",
I would like to correct this message (80char + rewording) - What do you suggest? Should I send a new patch to you or just convey what should be changed?
As far as i know, leaving strings on single line is good for grepping. However, perhaps having PRIx64 etc in there breaks it anyway.
Quoted 5 lines
Quoted 5 lines
+ type, va,
virt_addr,iova_addr,map_len); +
+ if (type ==RTE_MEM_EVENT_ALLOC)
+ ret =fslmc_map_dma(virt_addr, iova_addr, map_len); + else
Quoted 8 lines
Quoted 6 lines
+ ret =
fslmc_unmap_dma(virt_addr, iova_addr, map_len); +
+ if (ret != 0) {
+ DPAA2_BUS_ERR("DMA Mapping/Unmapping failed. Map=%d, addr=%p, len=%zu, err:(%d)",
+ type, va,map_len, ret);Same as above. 80 Char issue.
Same reasoning - leaving strings unbroken allows for easier grepping the codebase, but i'm not sure what's our policy on having formatted strings unbroken.
Quoted 11 lines
Quoted 11 lines
+ return;
+ }drivers/bus/fslmc/fslmc_vfio.c +8
-0+ + cur_len += map_len; + } + + if (type == RTE_MEM_EVENT_ALLOC) + DPAA2_BUS_DEBUG("Total Mapped: addr=%p, len=%zu\n", + addr, len); + else
<...>
Quoted 15 lines
Quoted 6 lines
+ ret =
rte_mem_event_callback_register("fslmc_memevent_clb", + fslmc_memevent_cb);
+ if (ret &&rte_errno== ENOTSUP)
+DPAA2_BUS_DEBUG("Memory event callbacks not supported"); + else if (ret)
+DPAA2_BUS_DEBUG("Unable to install memory handler");Quoted 8 lines
+ else
+DPAA2_BUS_DEBUG("Installed memory callback handler"); /* Verifying that at least single segment is available */ if (i <= 0) {
+ /* TODO: Is this verification required any more? What would + * happen to non-legacy case where nothing was preallocated + * thus causing i==0?
+ */
Quoted 1 line
And this as well - if call backs are not going to appear in case of legacy, this needs to be removed.
Callbacks aren't only not going to appear in legacy mode - they will also not appear on FreeBSD. We check this above, with checking rte_errno value (if callbacks are not supported, it's set to ENOTSUP, and having callbacks unsupported is not an error).
Quoted 2 lines
let me know how do you want to take these changes.
Now that i think of it, this error condition is wrong. This is called in both legacy and non-legacy mode. This is bus probe, no? For non-legacy mode, it is entirely possible to start without any memory whatsoever. It just so happens that rte_service API allocates some on init, and hence you always have at least one segment - that may not be the case forever. So, non-legacy mode, not having memsegs is not an error, it is expected behavior, so maybe we should remove this error check altogether.
Quoted 19 lines
Quoted 17 lines
DPAA2_BUS_ERR("No Segments found for VFIO Mapping"); +rte_rwlock_read_unlock(mem_lock);
return -1;
}
DPAA2_BUS_DEBUG("Total %d segments found.", i);drivers/bus/fslmc/fslmc_vfio.c +1
-0@@ -250,6 +367,11 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region(&vfio_group); + /* Existing segments have been mapped and memory callback forhotplug
+ * has been installed.
+ */
+rte_rwlock_read_unlock(mem_lock);
+
return 0;
}
Signature · 2 lines
Thanks, Anatoly
Re: [PATCH v4 66/70] bus/fslmc: enable support for mem event callbacks for vfio
Quoted 14 lines · Anatoly
Quoted 10 lines · Shreyansh Jain
Hi Anatoly,
Quoted 7 lines · Anatoly Burakov
VFIO needs to map and unmap segments for DMA whenever they become available or unavailable, so register a callback for memory events, and provide map/unmap functions.
Signed-off-by Shreyansh Jain <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
<...>
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
+ DPAA2_BUS_DEBUG("Calling with type=%d, va=%p, virt_addr=0x%" PRIx64 ", iova=0x%" PRIx64 ", map_len=%zu\n",
I would like to correct this message (80char + rewording) - What do you suggest? Should I send a new patch to you or just convey what should be changed?
As far as i know, leaving strings on single line is good for grepping. However, perhaps having PRIx64 etc in there breaks it anyway.
Yes, that and the debug message was not helpful.
This is what I had in mind. (DPAA2_BUS_DEBUG doesn't require an extra \n)
DPAA2_BUS_DEBUG("Request for %s, va=%p, virt_addr=0x%" PRIx64 ","
"iova=0x%" PRIx64 ", map_len=%zu", type == RTE_MEM_EVENT_ALLOC? "alloc" : "dealloc", va, virt_addr, iova_addr, map_len);
Quoted 15 lines
Quoted 14 lines
Quoted 10 lines
+ type, va,
virt_addr,iova_addr,map_len);drivers/bus/fslmc/fslmc_vfio.c +8
-0+ + if (type == RTE_MEM_EVENT_ALLOC) + ret = fslmc_map_dma(virt_addr, iova_addr, map_len); + else + ret = fslmc_unmap_dma(virt_addr, iova_addr, map_len); + + if (ret != 0) { + DPAA2_BUS_ERR("DMA Mapping/Unmapping failed. Map=%d,Quoted 2 lines
addr=%p, len=%zu, err:(%d)",
+ type, va,map_len, ret);Same as above. 80 Char issue.
Quoted 1 line
Same reasoning - leaving strings unbroken allows for easier grepping the codebase, but i'm not sure what's our policy on having formatted strings unbroken.
My policy is not different, but the various variables being dumped cannot anyway help in grepping - So, keeping the variables on separate lines for 80chars is ok. "DMA Mapping/Unmapping failed." is enough for greps.
Quoted 30 lines
Quoted 12 lines
Quoted 12 lines
+ return;
+ }drivers/bus/fslmc/fslmc_vfio.c +8
-0+ + cur_len += map_len; + } + + if (type == RTE_MEM_EVENT_ALLOC) + DPAA2_BUS_DEBUG("Total Mapped: addr=%p, len=%zu\n", + addr, len); + else<...>
Quoted 15 lines
Quoted 14 lines
+ ret =
rte_mem_event_callback_register("fslmc_memevent_clb", + fslmc_memevent_cb);
+ if (ret &&rte_errno== ENOTSUP)
+DPAA2_BUS_DEBUG("Memory event callbacks not supported"); + else if (ret)
+DPAA2_BUS_DEBUG("Unable to install memory handler"); + else
+DPAA2_BUS_DEBUG("Installed memory callback handler"); /* Verifying that at least single segment is available */ if (i <= 0) {
+ /* TODO: Is this verification required any more? What would + * happen to non-legacy case where nothing was preallocated + * thus causing i==0?
+ */
Quoted 8 lines
Quoted 1 line
And this as well - if call backs are not going to appear in case of legacy, this needs to be removed.
Callbacks aren't only not going to appear in legacy mode - they will also not appear on FreeBSD. We check this above, with checking
rte_errnovalue (if callbacks are not supported, it's set to ENOTSUP, and having callbacks unsupported is not an error).Quoted 2 lines
let me know how do you want to take these changes.
Now that i think of it, this error condition is wrong. This is called in both legacy and non-legacy mode. This is bus probe, no? For non-legacy mode, it is entirely possible to start without any memory whatsoever. It just so happens that
rte_serviceAPI allocates some on init, and hence you always have at least one segment - that may not be the case forever. So, non-legacy mode, not having memsegs is not an error, it is expected behavior, so maybe we should remove this error check altogether.
Agree - that count was only required in the earlier case. It can be removed.
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
DPAA2_BUS_ERR("No Segments found for VFIO Mapping"); +rte_rwlock_read_unlock(mem_lock);
return -1;
}
DPAA2_BUS_DEBUG("Total %d segments found.", i);drivers/bus/fslmc/fslmc_vfio.c +1
-0@@ -250,6 +367,11 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region(&vfio_group); + /* Existing segments have been mapped and memory callback forhotplug
+ * has been installed.
Quoted 10 lines
Quoted 8 lines
Quoted 6 lines
+ */
+rte_rwlock_read_unlock(mem_lock);
+
return 0;
}
I think there are enough changes, even if trivial. Maybe I can rework this patch and send you. If that is inconvenient, just extract from that whatever you want.
Re: [PATCH v4 66/70] bus/fslmc: enable support for mem event callbacks for vfio
Quoted 114 lines · Shreyansh Jain
Quoted 14 lines · Anatoly
Quoted 10 lines · Shreyansh Jain
Hi Anatoly,
Quoted 7 lines · Anatoly Burakov
VFIO needs to map and unmap segments for DMA whenever they become available or unavailable, so register a callback for memory events, and provide map/unmap functions.
Signed-off-by Shreyansh Jain <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
<...>
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
+ DPAA2_BUS_DEBUG("Calling with type=%d, va=%p, virt_addr=0x%" PRIx64 ", iova=0x%" PRIx64 ", map_len=%zu\n",
I would like to correct this message (80char + rewording) - What do you suggest? Should I send a new patch to you or just convey what should be changed?
As far as i know, leaving strings on single line is good for grepping. However, perhaps having PRIx64 etc in there breaks it anyway.
Yes, that and the debug message was not helpful.
This is what I had in mind. (DPAA2_BUS_DEBUGdoesn't require an extra \n)DPAA2_BUS_DEBUG("Request for %s, va=%p, virt_addr=0x%" PRIx64 ","
"iova=0x%" PRIx64 ", map_len=%zu",
type ==RTE_MEM_EVENT_ALLOC? "alloc" : "dealloc", va,virt_addr,iova_addr,map_len);Quoted 15 lines
Quoted 14 lines
Quoted 10 lines
+ type, va,
virt_addr,iova_addr,map_len);drivers/bus/fslmc/fslmc_vfio.c +8
-0+ + if (type == RTE_MEM_EVENT_ALLOC) + ret = fslmc_map_dma(virt_addr, iova_addr, map_len); + else + ret = fslmc_unmap_dma(virt_addr, iova_addr, map_len); + + if (ret != 0) { + DPAA2_BUS_ERR("DMA Mapping/Unmapping failed. Map=%d,Quoted 2 lines
addr=%p, len=%zu, err:(%d)",
+ type, va,map_len, ret);Same as above. 80 Char issue.
Quoted 1 line
Same reasoning - leaving strings unbroken allows for easier grepping the codebase, but i'm not sure what's our policy on having formatted strings unbroken.
My policy is not different, but the various variables being dumped cannot anyway help in grepping - So, keeping the variables on separate lines for 80chars is ok. "DMA Mapping/Unmapping failed." is enough for greps.
Quoted 30 lines
Quoted 12 lines
Quoted 12 lines
+ return;
+ }drivers/bus/fslmc/fslmc_vfio.c +8
-0+ + cur_len += map_len; + } + + if (type == RTE_MEM_EVENT_ALLOC) + DPAA2_BUS_DEBUG("Total Mapped: addr=%p, len=%zu\n", + addr, len); + else<...>
Quoted 15 lines
Quoted 14 lines
+ ret =
rte_mem_event_callback_register("fslmc_memevent_clb", + fslmc_memevent_cb);
+ if (ret &&rte_errno== ENOTSUP)
+DPAA2_BUS_DEBUG("Memory event callbacks not supported"); + else if (ret)
+DPAA2_BUS_DEBUG("Unable to install memory handler"); + else
+DPAA2_BUS_DEBUG("Installed memory callback handler"); /* Verifying that at least single segment is available */ if (i <= 0) {
+ /* TODO: Is this verification required any more? What would + * happen to non-legacy case where nothing was preallocated + * thus causing i==0?
+ */Quoted 8 lines
Quoted 1 line
And this as well - if call backs are not going to appear in case of legacy, this needs to be removed.
Callbacks aren't only not going to appear in legacy mode - they will also not appear on FreeBSD. We check this above, with checking
rte_errnovalue (if callbacks are not supported, it's set to ENOTSUP, and having callbacks unsupported is not an error).Quoted 2 lines
let me know how do you want to take these changes.
Now that i think of it, this error condition is wrong. This is called in both legacy and non-legacy mode. This is bus probe, no? For non-legacy mode, it is entirely possible to start without any memory whatsoever. It just so happens that
rte_serviceAPI allocates some on init, and hence you always have at least one segment - that may not be the case forever. So, non-legacy mode, not having memsegs is not an error, it is expected behavior, so maybe we should remove this error check altogether.Agree - that count was only required in the earlier case. It can be removed.
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
DPAA2_BUS_ERR("No Segments found for VFIO Mapping"); +rte_rwlock_read_unlock(mem_lock);
return -1;
}
DPAA2_BUS_DEBUG("Total %d segments found.", i);drivers/bus/fslmc/fslmc_vfio.c +1
-0@@ -250,6 +367,11 @@ int rte_fslmc_vfio_dmamap(void)*/ vfio_map_irq_region(&vfio_group); + /* Existing segments have been mapped and memory callback forhotplug
+ * has been installed.Quoted 10 lines
Quoted 8 lines
Quoted 6 lines
+ */
+rte_rwlock_read_unlock(mem_lock);
+
return 0;
}
Quoted 2 lines
I think there are enough changes, even if trivial. Maybe I can rework this patch and send you. If that is inconvenient, just extract from that whatever you want.
There aren't a lot of changes so i'll respin it myself, addressing the comments above. Thanks!
Signature · 2 lines
Thanks, Anatoly
PATCH v4 67/70 eal: enable non-legacy memory mode
In reply to Anatoly BurakovNow that every other piece of the puzzle is in place, enable non-legacy init mode.
--- lib/librte_eal/linuxapp/eal/eal.c | 2 -- 1 file changed, 2 deletions(-)
lib/librte_eal/linuxapp/eal/eal.c +0 -2
@@ -772,8 +772,6 @@ rte_eal_init(int argc, char **argv)rte_atomic32_clear (&run_once);return -1 ; } -/* for now, always set legacy mem */ - internal_config.legacy_mem =1 ;if (eal_plugins_init () <0 ) {rte_eal_init_alert ("Cannot init plugins\n" );
Signature · 1 line
2.7.4
PATCH v4 68/70 eal: add memory validator callback
In reply to Anatoly BurakovThis API will enable application to register for notifications on page allocations that are about to happen, giving the application a chance to allow or deny the allocation when total memory utilization as a result would be above specified limit on specified socket.
---
Notes:
v4:
- Document limitation on using some functions
v3:
- Added this feature
lib/librte_eal/common/eal_common_memalloc.c | 138 +++++++++++++++++++++++++++- lib/librte_eal/common/eal_common_memory.c | 26 ++++++ lib/librte_eal/common/eal_memalloc.h | 10 ++ lib/librte_eal/common/include/rte_memory.h | 63 +++++++++++++ lib/librte_eal/rte_eal_version.map | 2 + 5 files changed, 238 insertions(+), 1 deletion(-)
lib/librte_eal/common/eal_common_memalloc.c +137 -1
@@ -22,14 +22,26 @@ struct mem_event_callback_entry {rte_mem_event_callback_t clb; }; +struct mem_alloc_validator_entry { +TAILQ_ENTRY (mem_alloc_validator_entry) next; +char name[RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ]; +rte_mem_alloc_validator_t clb; +int socket_id; +size_t limit; +}; +/** Double linked list of actions. */ TAILQ_HEAD (mem_event_callback_entry_list, mem_event_callback_entry); +TAILQ_HEAD (mem_alloc_validator_entry_list, mem_alloc_validator_entry);static struct mem_event_callback_entry_list mem_event_callback_list =TAILQ_HEAD_INITIALIZER (mem_event_callback_list); -static rte_rwlock_t mem_event_rwlock =RTE_RWLOCK_INITIALIZER ; +static struct mem_alloc_validator_entry_list mem_alloc_validator_list = +TAILQ_HEAD_INITIALIZER (mem_alloc_validator_list); +static rte_rwlock_t mem_alloc_validator_rwlock =RTE_RWLOCK_INITIALIZER ; +static struct mem_event_callback_entry *find_mem_event_callback (const char *name) {
@@ -42,6 +54,18 @@ find_mem_event_callback(const char *name)return r; } +static struct mem_alloc_validator_entry * +find_mem_alloc_validator (const char *name,int socket_id) +{ +struct mem_alloc_validator_entry *r; + + TAILQ_FOREACH(r, &mem_alloc_validator_list, next) { +if (!strcmp (r->name, name) && r->socket_id == socket_id) +break ; + } +return r; +} +bool eal_memalloc_is_contig (const struct rte_memseg_list *msl,void *start,size_t len)
@@ -221,3 +245,115 @@ eal_memalloc_mem_event_notify(enum rte_mem_event event, const void *start,rte_rwlock_read_unlock (&mem_event_rwlock); } + +int +eal_memalloc_mem_alloc_validator_register (const char *name, +rte_mem_alloc_validator_t clb,int socket_id,size_t limit) +{ +struct mem_alloc_validator_entry *entry; +int ret, len; +if (name ==NULL || clb ==NULL || socket_id <0 ) { + rte_errno =EINVAL ; +return -1 ; + } + len =strnlen (name,RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ); +if (len ==0 ) { + rte_errno =EINVAL ; +return -1 ; + }else if (len ==RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ) { + rte_errno =ENAMETOOLONG ; +return -1 ; + } +rte_rwlock_write_lock (&mem_alloc_validator_rwlock); + + entry =find_mem_alloc_validator (name, socket_id); +if (entry !=NULL ) { + rte_errno =EEXIST ; + ret =-1 ; + goto unlock; + } + + entry =malloc (sizeof (*entry)); +if (entry ==NULL ) { + rte_errno =ENOMEM ; + ret =-1 ; + goto unlock; + } + +/* callback successfully created and is valid, add it to the list */ + entry->clb = clb; + entry->socket_id = socket_id; + entry->limit = limit; +snprintf (entry->name,RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ,"%s" , name); +TAILQ_INSERT_TAIL (&mem_alloc_validator_list, entry, next); + + ret =0 ; + +RTE_LOG (DEBUG ,EAL ,"Mem alloc validator '%s' on socket %i with limit %zu registered\n" , + name, socket_id, limit); + +unlock: +rte_rwlock_write_unlock (&mem_alloc_validator_rwlock); +return ret; +} + +int +eal_memalloc_mem_alloc_validator_unregister (const char *name,int socket_id) +{ +struct mem_alloc_validator_entry *entry; +int ret, len; + +if (name ==NULL || socket_id <0 ) { + rte_errno =EINVAL ; +return -1 ; + } + len =strnlen (name,RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ); +if (len ==0 ) { + rte_errno =EINVAL ; +return -1 ; + }else if (len ==RTE_MEM_ALLOC_VALIDATOR_NAME_LEN ) { + rte_errno =ENAMETOOLONG ; +return -1 ; + } +rte_rwlock_write_lock (&mem_alloc_validator_rwlock); + + entry =find_mem_alloc_validator (name, socket_id); +if (entry ==NULL ) { + rte_errno =ENOENT ; + ret =-1 ; + goto unlock; + } +TAILQ_REMOVE (&mem_alloc_validator_list, entry, next); +free (entry); + + ret =0 ; + +RTE_LOG (DEBUG ,EAL ,"Mem alloc validator '%s' on socket %i unregistered\n" , + name, socket_id); + +unlock: +rte_rwlock_write_unlock (&mem_alloc_validator_rwlock); +return ret; +} + +int +eal_memalloc_mem_alloc_validate (int socket_id,size_t new_len) +{ +struct mem_alloc_validator_entry *entry; +int ret =0 ; + +rte_rwlock_read_lock (&mem_alloc_validator_rwlock); + + TAILQ_FOREACH(entry, &mem_alloc_validator_list, next) { +if (entry->socket_id != socket_id || entry->limit > new_len) +continue ; +RTE_LOG (DEBUG ,EAL ,"Calling mem alloc validator '%s' on socket %i\n" , + entry->name, entry->socket_id); +if (entry->clb (socket_id, entry->limit, new_len) <0 ) + ret =-1 ; + } + +rte_rwlock_read_unlock (&mem_alloc_validator_rwlock); + +return ret; +}
lib/librte_eal/common/eal_common_memory.c +26 -0
@@ -651,6 +651,32 @@ rte_mem_event_callback_unregister(const char *name)return eal_memalloc_mem_event_callback_unregister (name); } +int __rte_experimental +rte_mem_alloc_validator_register (const char *name, +rte_mem_alloc_validator_t clb,int socket_id,size_t limit) +{ +/* FreeBSD boots with legacy mem enabled by default */ +if (internal_config.legacy_mem) { +RTE_LOG (DEBUG ,EAL ,"Registering mem alloc validators not supported\n" ); + rte_errno =ENOTSUP ; +return -1 ; + } +return eal_memalloc_mem_alloc_validator_register (name, clb, socket_id, + limit); +} + +int __rte_experimental +rte_mem_alloc_validator_unregister (const char *name,int socket_id) +{ +/* FreeBSD boots with legacy mem enabled by default */ +if (internal_config.legacy_mem) { +RTE_LOG (DEBUG ,EAL ,"Registering mem alloc validators not supported\n" ); + rte_errno =ENOTSUP ; +return -1 ; + } +return eal_memalloc_mem_alloc_validator_unregister (name, socket_id); +} +/* Dump the physical memory layout on console */ void rte_dump_physmem_layout (FILE *f)
lib/librte_eal/common/eal_memalloc.h +10 -0
@@ -67,4 +67,14 @@ void eal_memalloc_mem_event_notify(enum rte_mem_event event, const void *start, size_t len); +int +eal_memalloc_mem_alloc_validator_register (const char *name, +rte_mem_alloc_validator_t clb,int socket_id,size_t limit); + +int +eal_memalloc_mem_alloc_validator_unregister (const char *name,int socket_id); + +int +eal_memalloc_mem_alloc_validate (int socket_id,size_t new_len); +#endif // EAL_MEMALLOC_H
lib/librte_eal/common/include/rte_memory.h +63 -0
69 lines not on this page · raw message
lib/librte_eal/rte_eal_version.map +2 -0
@@ -238,6 +238,8 @@ EXPERIMENTAL { rte_fbarray_set_used; rte_log_register_type_and_pick_level; rte_malloc_dump_heaps; + rte_mem_alloc_validator_register; + rte_mem_alloc_validator_unregister; rte_mem_event_callback_register; rte_mem_event_callback_unregister; rte_mem_iova2virt;
Signature · 1 line
2.7.4
PATCH v4 69/70 eal: enable validation before new page allocation
In reply to Anatoly Burakov--- lib/librte_eal/common/malloc_heap.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
lib/librte_eal/common/malloc_heap.c +9 -1
@@ -196,6 +196,15 @@ alloc_pages_on_heap(struct malloc_heap *heap, uint64_t pg_sz, size_t elt_size,int allocd_pages;void *ret, *map_addr; + alloc_sz = (size_t )pg_sz * n_segs; + +/* first, check if we're allowed to allocate this memory */ +if (eal_memalloc_mem_alloc_validate (socket, + heap->total_size + alloc_sz) <0 ) { +RTE_LOG (DEBUG ,EAL ,"User has disallowed allocation\n" ); +return NULL ; + } + allocd_pages =eal_memalloc_alloc_seg_bulk (ms, n_segs, pg_sz, socket, true);
@@ -205,7 +214,6 @@ alloc_pages_on_heap(struct malloc_heap *heap, uint64_t pg_sz, size_t elt_size, map_addr = ms[0 ]->addr; msl =rte_mem_virt2memseg_list (map_addr); - alloc_sz = (size_t )msl->page_sz * allocd_pages;/* check if we wanted contiguous memory but didn't get it */ if (contig && !eal_memalloc_is_contig (msl, map_addr, alloc_sz)) {
Signature · 1 line
2.7.4
PATCH v4 70/70 eal: prevent preallocated pages from being freed
In reply to Anatoly BurakovIt is common sense to expect for DPDK process to not deallocate any pages that were preallocated by "-m" or "--socket-mem" flags - yet, currently, DPDK memory subsystem will do exactly that once it finds that the pages are unused.
Fix this by marking pages as unfreebale, and preventing malloc from ever trying to free them.
--- lib/librte_eal/common/include/rte_memory.h | 3 +++ lib/librte_eal/common/malloc_heap.c | 23 +++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_memalloc.c | 7 +++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 18 +++++++++++++++--- 4 files changed, 48 insertions(+), 3 deletions(-)
lib/librte_eal/common/include/rte_memory.h +3 -0
@@ -83,6 +83,8 @@ typedef uint64_t rte_iova_t;/** * Physical memory segment descriptor. */ +#define RTE_MEMSEG_FLAG_DO_NOT_FREE (1 << 0) +/**< Prevent this segment from being freed back to the OS. */ struct rte_memseg { RTE_STD_C11 union {
@@ -99,6 +101,7 @@ struct rte_memseg {int32_t socket_id;/**< NUMA socket ID. */ uint32_t nchannel;/**< Number of channels. */ uint32_t nrank;/**< Number of ranks. */ +uint32_t flags;/**< Memseg-specific flags */ } __rte_packed;/**
lib/librte_eal/common/malloc_heap.c +23 -0
@@ -606,6 +606,7 @@ malloc_heap_free(struct malloc_elem *elem)void *start, *aligned_start, *end, *aligned_end;size_t len, aligned_len, page_sz;struct rte_memseg_list *msl; +unsigned int i, n_segs;int ret;if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY )
@@ -647,6 +648,28 @@ malloc_heap_free(struct malloc_elem *elem)if (aligned_len < page_sz) goto free_unlock; +/* we can free something. however, some of these pages may be marked as +* unfreeable, so also check that as well +*/ + n_segs = aligned_len / page_sz; +for (i =0 ; i < n_segs; i++) { +const struct rte_memseg *tmp = +rte_mem_virt2memseg (aligned_start, msl); + +if (tmp->flags &RTE_MEMSEG_FLAG_DO_NOT_FREE ) { +/* this is an unfreeable segment, so move start */ + aligned_start =RTE_PTR_ADD (tmp->addr, tmp->len); + } + } + +/* recalculate length and number of segments */ + aligned_len =RTE_PTR_DIFF (aligned_end, aligned_start); + n_segs = aligned_len / page_sz; + +/* check if we can still free some pages */ +if (n_segs ==0 ) + goto free_unlock; +rte_rwlock_write_lock (&mcfg->memory_hotplug_lock);/*
lib/librte_eal/linuxapp/eal/eal_memalloc.c +7 -0
@@ -806,6 +806,13 @@ eal_memalloc_free_seg_bulk(struct rte_memseg **ms, int n_segs)struct free_walk_param wa;int i, walk_res; +/* if this page is marked as unfreeable, fail */ +if (cur->flags &RTE_MEMSEG_FLAG_DO_NOT_FREE ) { +RTE_LOG (DEBUG ,EAL ,"Page is not allowed to be freed\n" ); + ret =-1 ; +continue ; + } +memset (&wa,0 ,sizeof (wa)); for (i = 0; i < (int)RTE_DIM(internal_config.hugepage_info);
lib/librte_eal/linuxapp/eal/eal_memory.c +15 -3
@@ -1637,21 +1637,33 @@ eal_hugepage_init(void) hp_sz_idx++) {for (socket_id =0 ; socket_id <RTE_MAX_NUMA_NODES ; socket_id++) { +struct rte_memseg **pages;struct hugepage_info *hpi = &used_hp[hp_sz_idx];unsigned int num_pages = hpi->num_pages[socket_id]; -int num_pages_alloc; +int num_pages_alloc, i;if (num_pages ==0 )continue ; + pages =malloc (sizeof (*pages) * num_pages); +RTE_LOG (DEBUG ,EAL ,"Allocating %u pages of size %" PRIu64"M on socket %i\n" , num_pages, hpi->hugepage_sz >>20 , socket_id); - num_pages_alloc =eal_memalloc_alloc_seg_bulk (NULL , + num_pages_alloc =eal_memalloc_alloc_seg_bulk (pages, num_pages, hpi->hugepage_sz, socket_id, true); -if (num_pages_alloc <0 ) +if (num_pages_alloc <0 ) { +free (pages);return -1 ; + } + +/* mark preallocated pages as unfreeable */ +for (i =0 ; i < num_pages_alloc; i++) { +struct rte_memseg *ms = pages[i]; + ms->flags |=RTE_MEMSEG_FLAG_DO_NOT_FREE ; + } +free (pages); } }return 0 ;
Signature · 1 line
2.7.4
v5 cover Memory Hotplug for DPDK
In reply to Anatoly BurakovThis patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].
Dependencies (to be applied in specified order):
- EAL IOVA fix [2]
Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [3]
The vast majority of changes are in the EAL and malloc, the external API disruption is minimal: a new flag is added to memzone API for contiguous memory allocation, a few API additions in rte_memory due to switch to memseg_lists as opposed to memsegs, and a few new convenience API's. Every other API change is internal to EAL, and all of the memory allocation/freeing is handled through rte_malloc, with no externally visible API changes.
Quick outline of all changes done as part of this patchset:
* Malloc heap adjusted to handle holes in address space
* Single memseg list replaced by multiple memseg lists
* VA space for hugepages is preallocated in advance
* Added alloc/free for pages happening as needed on rte_malloc/rte_free
* Added contiguous memory allocation API's for rte_memzone
* Added convenience API calls to walk over memsegs
* Integrated Pawel Wodkowski's patch for registering/unregistering memory with VFIO [4]
* Callbacks for registering memory allocations
* Callbacks for allowing/disallowing allocations above specified limit
* Multiprocess support done via DPDK IPC introduced in 18.02
The biggest difference is a "memseg" now represents a single page (as opposed to being a big contiguous block of pages). As a consequence, both memzones and malloc elements are no longer guaranteed to be physically contiguous, unless the user asks for it at reserve time. To preserve whatever functionality that was dependent on previous behavior, a legacy memory option is also provided, however it is expected (or perhaps vainly hoped) to be temporary solution.
Why multiple memseg lists instead of one? Since memseg is a single page now, the list of memsegs will get quite big, and we need to locate pages somehow when we allocate and free them. We could of course just walk the list and allocate one contiguous chunk of VA space for memsegs, but this implementation uses separate lists instead in order to speed up many operations with memseg lists.
For v5, the following limitations are present:
- VFIO support for multiple processes is not well-tested; work is ongoing to validate VFIO for all use cases
- There are known problems with PPC64 VFIO code
- For DPAA and FSLMC platforms, performance will be heavily degraded for IOVA as PA cases; separate patches are expected to address the issue
For testing, it is recommended to use the GitHub repository [5], as it will have all of the dependencies already integrated.
v5:
- Fixed missing DMA window creation on PPC64 for VFIO
- fslmc VFIO fixes
- Added new user DMA map code to keep track of user DMA maps when hotplug is in use (also used on PPC64 on remap)
- A few checkpatch and commit message fixes here and there
v4:
- Fixed bug in memzone lookup
- Added draft fslmc VFIO code
- Rebased on latest master + dependent patchset
- Documented limitations for *_walk() functions
v3:
- Lots of compile fixes
- Fixes for multiprocess synchronization
- Introduced support for sPAPR IOMMU, courtesy of Gowrishankar @ IBM
- Fixes for mempool size calculation
- Added convenience memseg walk() API's
- Added alloc validation callback
v2: - fixed deadlock at init
- reverted rte_panic changes at init, this is now handled inside IPC
[1] http://dpdk.org/dev/patchwork/bundle/aburakov/Memory_RFC/
[2] http://dpdk.org/dev/patchwork/bundle/aburakov/IOVA_mode_fixes/
[3] http://dpdk.org/dev/patchwork/patch/34002/
[4] http://dpdk.org/dev/patchwork/patch/24484/
[5] https://github.com/anatolyburakov/dpdk
Anatoly Burakov (70):
eal: move get_virtual_area out of linuxapp eal_memory.c
eal: move all locking to heap
eal: make malloc heap a doubly-linked list
eal: add function to dump malloc heap contents
test: add command to dump malloc heap contents
eal: make malloc_elem_join_adjacent_free public
eal: make malloc free list remove public
eal: make malloc free return resulting malloc element
eal: replace panics with error messages in malloc
eal: add backend support for contiguous allocation
eal: enable reserving physically contiguous memzones
ethdev: use contiguous allocation for DMA memory crypto/qat: use contiguous allocation for DMA memory net/avf: use contiguous allocation for DMA memory net/bnx2x: use contiguous allocation for DMA memory net/bnxt: use contiguous allocation for DMA memory net/cxgbe: use contiguous allocation for DMA memory net/ena: use contiguous allocation for DMA memory net/enic: use contiguous allocation for DMA memory net/i40e: use contiguous allocation for DMA memory net/qede: use contiguous allocation for DMA memory net/virtio: use contiguous allocation for DMA memory net/vmxnet3: use contiguous allocation for DMA memory
mempool: add support for the new allocation methods
eal: add function to walk all memsegs
bus/fslmc: use memseg walk instead of iteration bus/pci: use memseg walk instead of iteration net/mlx5: use memseg walk instead of iteration
eal: use memseg walk instead of iteration
mempool: use memseg walk instead of iteration
test: use memseg walk instead of iteration vfio/type1: use memseg walk instead of iteration vfio/spapr: use memseg walk instead of iteration
eal: add contig walk function
virtio: use memseg contig walk instead of iteration
eal: add iova2virt function
bus/dpaa: use iova2virt instead of memseg iteration bus/fslmc: use iova2virt instead of memseg iteration crypto/dpaa_sec: use iova2virt instead of memseg iteration
eal: add virt2memseg function
bus/fslmc: use virt2memseg instead of iteration crypto/dpaa_sec: use virt2memseg instead of iteration net/mlx4: use virt2memseg instead of iteration net/mlx5: use virt2memseg instead of iteration
eal: use memzone walk instead of iteration
vfio: allow to map other memory regions
eal: add "legacy memory" option
eal: add rte_fbarray
eal: replace memseg with memseg lists
eal: replace memzone array with fbarray
eal: add support for mapping hugepages at runtime
eal: add support for unmapping pages at runtime
eal: add "single file segments" command-line option
eal: add API to check if memory is contiguous
eal: prepare memseg lists for multiprocess sync
eal: read hugepage counts from node-specific sysfs path
eal: make use of memory hotplug for init
eal: share hugepage info primary and secondary
eal: add secondary process init with memory hotplug
eal: enable memory hotplug support in rte_malloc
eal: add support for multiprocess memory hotplug
eal: add support for callbacks on memory hotplug
eal: enable callbacks on malloc/free and mp sync
vfio: enable support for mem event callbacks bus/fslmc: move vfio DMA map into bus probe bus/fslmc: enable support for mem event callbacks for vfio
eal: enable non-legacy memory mode
eal: add memory validator callback
eal: enable validation before new page allocation
eal: prevent preallocated pages from being freed
config/common_base | 15 +- config/defconfig_i686-native-linuxapp-gcc | 3 + config/defconfig_i686-native-linuxapp-icc | 3 + config/defconfig_x86_x32-native-linuxapp-gcc | 3 + config/rte_config.h | 7 +- doc/guides/rel_notes/deprecation.rst | 9 - drivers/bus/dpaa/rte_dpaa_bus.h | 12 +- drivers/bus/fslmc/fslmc_bus.c | 11 + drivers/bus/fslmc/fslmc_vfio.c | 195 +++- drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 27 +- drivers/bus/pci/Makefile | 3 + drivers/bus/pci/linux/pci.c | 28 +- drivers/bus/pci/meson.build | 3 + drivers/crypto/dpaa_sec/dpaa_sec.c | 30 +- drivers/crypto/qat/qat_qp.c | 23 +- drivers/event/dpaa2/Makefile | 3 + drivers/mempool/dpaa/Makefile | 3 + drivers/mempool/dpaa/meson.build | 3 + drivers/mempool/dpaa2/Makefile | 3 + drivers/mempool/dpaa2/meson.build | 3 + drivers/net/avf/avf_ethdev.c | 4 +- drivers/net/bnx2x/bnx2x.c | 2 +- drivers/net/bnx2x/bnx2x_rxtx.c | 3 +- drivers/net/bnxt/bnxt_ethdev.c | 17 +- drivers/net/bnxt/bnxt_ring.c | 9 +- drivers/net/bnxt/bnxt_vnic.c | 8 +- drivers/net/cxgbe/sge.c | 3 +- drivers/net/dpaa/Makefile | 3 + drivers/net/dpaa2/Makefile | 3 + drivers/net/dpaa2/dpaa2_ethdev.c | 1 - drivers/net/dpaa2/meson.build | 3 + drivers/net/ena/Makefile | 3 + drivers/net/ena/base/ena_plat_dpdk.h | 9 +- drivers/net/ena/ena_ethdev.c | 10 +- drivers/net/enic/enic_main.c | 9 +- drivers/net/i40e/i40e_ethdev.c | 4 +- drivers/net/i40e/i40e_rxtx.c | 4 +- drivers/net/mlx4/mlx4_mr.c | 18 +- drivers/net/mlx5/Makefile | 3 + drivers/net/mlx5/mlx5.c | 25 +- drivers/net/mlx5/mlx5_mr.c | 19 +- drivers/net/qede/base/bcm_osal.c | 7 +- drivers/net/virtio/virtio_ethdev.c | 8 +- drivers/net/virtio/virtio_user/vhost_kernel.c | 83 +- drivers/net/vmxnet3/vmxnet3_ethdev.c | 5 +- lib/librte_eal/bsdapp/eal/Makefile | 4 + lib/librte_eal/bsdapp/eal/eal.c | 83 +- lib/librte_eal/bsdapp/eal/eal_hugepage_info.c | 65 +- lib/librte_eal/bsdapp/eal/eal_memalloc.c | 48 + lib/librte_eal/bsdapp/eal/eal_memory.c | 224 +++- lib/librte_eal/bsdapp/eal/meson.build | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_fbarray.c | 859 ++++++++++++++++ lib/librte_eal/common/eal_common_memalloc.c | 359 +++++++ lib/librte_eal/common/eal_common_memory.c | 824 ++++++++++++++- lib/librte_eal/common/eal_common_memzone.c | 235 +++-- lib/librte_eal/common/eal_common_options.c | 13 +- lib/librte_eal/common/eal_filesystem.h | 30 + lib/librte_eal/common/eal_hugepages.h | 11 +- lib/librte_eal/common/eal_internal_cfg.h | 12 +- lib/librte_eal/common/eal_memalloc.h | 80 ++ lib/librte_eal/common/eal_options.h | 4 + lib/librte_eal/common/eal_private.h | 33 + lib/librte_eal/common/include/rte_eal_memconfig.h | 28 +- lib/librte_eal/common/include/rte_fbarray.h | 353 +++++++ lib/librte_eal/common/include/rte_malloc.h | 10 + lib/librte_eal/common/include/rte_malloc_heap.h | 6 + lib/librte_eal/common/include/rte_memory.h | 258 ++++- lib/librte_eal/common/include/rte_memzone.h | 12 +- lib/librte_eal/common/include/rte_vfio.h | 41 + lib/librte_eal/common/malloc_elem.c | 433 ++++++-- lib/librte_eal/common/malloc_elem.h | 43 +- lib/librte_eal/common/malloc_heap.c | 704 ++++++++++++- lib/librte_eal/common/malloc_heap.h | 15 +- lib/librte_eal/common/malloc_mp.c | 744 ++++++++++++++ lib/librte_eal/common/malloc_mp.h | 86 ++ lib/librte_eal/common/meson.build | 4 + lib/librte_eal/common/rte_malloc.c | 85 +- lib/librte_eal/linuxapp/eal/Makefile | 5 + lib/librte_eal/linuxapp/eal/eal.c | 62 +- lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 218 +++- lib/librte_eal/linuxapp/eal/eal_memalloc.c | 1123 +++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 1119 ++++++++++++-------- lib/librte_eal/linuxapp/eal/eal_vfio.c | 870 ++++++++++++++-- lib/librte_eal/linuxapp/eal/eal_vfio.h | 12 + lib/librte_eal/linuxapp/eal/meson.build | 1 + lib/librte_eal/rte_eal_version.map | 30 +- lib/librte_ether/rte_ethdev.c | 3 +- lib/librte_mempool/Makefile | 3 + lib/librte_mempool/meson.build | 3 + lib/librte_mempool/rte_mempool.c | 149 ++- test/test/commands.c | 3 + test/test/test_malloc.c | 30 +- test/test/test_memory.c | 27 +- test/test/test_memzone.c | 62 +- 95 files changed, 8794 insertions(+), 1285 deletions(-) create mode 100644 lib/librte_eal/bsdapp/eal/eal_memalloc.c create mode 100644 lib/librte_eal/common/eal_common_fbarray.c create mode 100644 lib/librte_eal/common/eal_common_memalloc.c create mode 100644 lib/librte_eal/common/eal_memalloc.h create mode 100644 lib/librte_eal/common/include/rte_fbarray.h create mode 100644 lib/librte_eal/common/malloc_mp.c create mode 100644 lib/librte_eal/common/malloc_mp.h create mode 100644 lib/librte_eal/linuxapp/eal/eal_memalloc.c
Signature · 1 line
2.7.4
PATCH v5 1/70 eal: move get_virtual_area out of linuxapp eal_memory.c
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.
---
Notes:
v3: replace uint64_t with size_t for size variables
lib/librte_eal/common/eal_common_memory.c | 101 ++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 33 +++++++ lib/librte_eal/linuxapp/eal/eal_memory.c | 137 ++++++------------------------ 3 files changed, 161 insertions(+), 110 deletions(-)
lib/librte_eal/common/eal_common_memory.c +101 -0
@@ -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,12 +16,111 @@#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 * memory. The last element of the table contains a NULL address.
lib/librte_eal/common/eal_private.h +33 -0
@@ -127,6 +127,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. * * This function is private to the EAL.
lib/librte_eal/linuxapp/eal/eal_memory.c +27 -110
204 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v5 2/70 eal: move all locking to heap
In reply to Anatoly BurakovDown the line, we will need to do everything from the heap as any alloc or free may trigger alloc/free OS memory, which would involve growing/shrinking heap.
---
Notes:
v4: clarified commit message
lib/librte_eal/common/malloc_elem.c | 16 ++-------------- lib/librte_eal/common/malloc_heap.c | 38 +++++++++++++++++++++++++++++++++++++ lib/librte_eal/common/malloc_heap.h | 6 ++++++ lib/librte_eal/common/rte_malloc.c | 4 ++-- 4 files changed, 48 insertions(+), 16 deletions(-)
lib/librte_eal/common/malloc_elem.c +2 -14
@@ -243,10 +243,6 @@ join_elem(struct malloc_elem *elem1, struct malloc_elem *elem2)int malloc_elem_free (struct malloc_elem *elem) { -if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) -return -1 ; - -rte_spinlock_lock (&(elem->heap->lock));size_t sz = elem->size -sizeof (*elem) -MALLOC_ELEM_TRAILER_LEN ;uint8_t *ptr = (uint8_t *)&elem[1 ];struct malloc_elem *next =RTE_PTR_ADD (elem, elem->size);
@@ -274,8 +270,6 @@ malloc_elem_free(struct malloc_elem *elem)memset (ptr,0 , sz); -rte_spinlock_unlock (&(elem->heap->lock)); -return 0 ; }
@@ -292,11 +286,10 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)return 0 ;struct malloc_elem *next =RTE_PTR_ADD (elem, elem->size); -rte_spinlock_lock (&elem->heap->lock);if (next ->state !=ELEM_FREE ) - goto err_return; +return -1 ;if (elem->size + next->size < new_size) - goto err_return; +return -1 ;/* we now know the element fits, so remove from free list, * join the two
@@ -311,10 +304,5 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)split_elem (elem, split_pt);malloc_elem_free_list_insert (split_pt); } -rte_spinlock_unlock (&elem->heap->lock);return 0 ; - -err_return: -rte_spinlock_unlock (&elem->heap->lock); -return -1 ; }
lib/librte_eal/common/malloc_heap.c +38 -0
@@ -145,6 +145,44 @@ malloc_heap_alloc(struct malloc_heap *heap,return elem ==NULL ?NULL : (void *)(&elem[1 ]); } +int +malloc_heap_free (struct malloc_elem *elem) +{ +struct malloc_heap *heap; +int ret; + +if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) +return -1 ; + +/* elem may be merged with previous element, so keep heap address */ + heap = elem->heap; + +rte_spinlock_lock (&(heap->lock)); + + ret =malloc_elem_free (elem); + +rte_spinlock_unlock (&(heap->lock)); + +return ret; +} + +int +malloc_heap_resize (struct malloc_elem *elem,size_t size) +{ +int ret; + +if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY ) +return -1 ; + +rte_spinlock_lock (&(elem->heap->lock)); + + ret =malloc_elem_resize (elem, size); + +rte_spinlock_unlock (&(elem->heap->lock)); + +return ret; +} +/* * Function to retrieve data for heap on given socket */
lib/librte_eal/common/malloc_heap.h +6 -0
@@ -28,6 +28,12 @@ malloc_heap_alloc(struct malloc_heap *heap, const char *type, size_t size, unsigned flags, size_t align, size_t bound);int +malloc_heap_free (struct malloc_elem *elem); + +int +malloc_heap_resize (struct malloc_elem *elem,size_t size); + +int malloc_heap_get_stats (struct malloc_heap *heap,struct rte_malloc_socket_stats *socket_stats);
lib/librte_eal/common/rte_malloc.c +2 -2
@@ -29,7 +29,7 @@void rte_free (void *addr) {if (addr ==NULL )return ; -if (malloc_elem_free (malloc_elem_from_data (addr)) <0 ) +if (malloc_heap_free (malloc_elem_from_data (addr)) <0 )rte_panic ("Fatal error: Invalid memory\n" ); }
@@ -140,7 +140,7 @@ rte_realloc(void *ptr, size_t size, unsigned align) size =RTE_CACHE_LINE_ROUNDUP (size), align =RTE_CACHE_LINE_ROUNDUP (align);/* check alignment matches first, and if ok, see if we can resize block */ if (RTE_PTR_ALIGN (ptr,align) == ptr && -malloc_elem_resize (elem, size) ==0 ) +malloc_heap_resize (elem, size) ==0 )return ptr;/* either alignment is off, or we have no room to expand,
Signature · 1 line
2.7.4
PATCH v5 3/70 eal: make malloc heap a doubly-linked list
In reply to Anatoly BurakovAs we are preparing for dynamic memory allocation, we need to be able to handle holes in our malloc heap, hence we're switching to doubly linked list, and prepare infrastructure to support it.
Since our heap is now aware where are our first and last elements, there is no longer any need to have a dummy element at the end of each heap, so get rid of that as well. Instead, let insert/remove/ join/split operations handle end-of-list conditions automatically.
---
Notes:
v3:
- Make first/last element pointers volatile
lib/librte_eal/common/include/rte_malloc_heap.h | 6 + lib/librte_eal/common/malloc_elem.c | 200 +++++++++++++++++++----- lib/librte_eal/common/malloc_elem.h | 14 +- lib/librte_eal/common/malloc_heap.c | 8 +- 4 files changed, 179 insertions(+), 49 deletions(-)
lib/librte_eal/common/include/rte_malloc_heap.h +6 -0
@@ -13,12 +13,18 @@/* Number of free lists per heap, grouped by size. */ #define RTE_HEAP_NUM_FREELISTS 13 +/* dummy definition, for pointers */ +struct malloc_elem ; +/** * Structure to hold malloc heap */ struct malloc_heap {rte_spinlock_t lock; LIST_HEAD(, malloc_elem) free_head[RTE_HEAP_NUM_FREELISTS]; +struct malloc_elem *volatile first; +struct malloc_elem *volatile last; +unsigned alloc_count;size_t total_size; } __rte_cache_aligned;
lib/librte_eal/common/malloc_elem.c +164 -36
271 lines not on this page · raw message
lib/librte_eal/common/malloc_elem.h +7 -7
@@ -18,8 +18,12 @@ enum elem_state {struct malloc_elem {struct malloc_heap *heap; -struct malloc_elem *volatile prev;/* points to prev elem in memseg */ -LIST_ENTRY (malloc_elem) free_list;/* list of free elements in heap */ +struct malloc_elem *volatile prev; +/**< points to prev elem in memseg */ +struct malloc_elem *volatile next; +/**< points to next elem in memseg */ +LIST_ENTRY (malloc_elem) free_list; +/**< list of free elements in heap */ const struct rte_memseg *ms;volatile enum elem_state state;uint32_t pad;
@@ -110,12 +114,8 @@ malloc_elem_init(struct malloc_elem *elem,const struct rte_memseg *ms, size_t size); -/* -* initialise a dummy malloc_elem header for the end-of-memseg marker -*/ void -malloc_elem_mkend (struct malloc_elem *elem, -struct malloc_elem *prev_free); +malloc_elem_insert (struct malloc_elem *elem);/* * return true if the current malloc_elem can hold a block of data
lib/librte_eal/common/malloc_heap.c +2 -6
@@ -70,15 +70,11 @@ check_hugepage_sz(unsigned flags, uint64_t hugepage_sz)static void malloc_heap_add_memseg (struct malloc_heap *heap,struct rte_memseg *ms) { -/* allocate the memory block headers, one at end, one at start */ struct malloc_elem *start_elem = (struct malloc_elem *)ms->addr; -struct malloc_elem *end_elem =RTE_PTR_ADD (ms->addr, - ms->len -MALLOC_ELEM_OVERHEAD ); - end_elem =RTE_PTR_ALIGN_FLOOR (end_elem,RTE_CACHE_LINE_SIZE ); -const size_t elem_size = (uintptr_t )end_elem - (uintptr_t )start_elem; +const size_t elem_size = ms->len -MALLOC_ELEM_OVERHEAD ;malloc_elem_init (start_elem, heap, ms, elem_size); -malloc_elem_mkend (end_elem, start_elem); +malloc_elem_insert (start_elem);malloc_elem_free_list_insert (start_elem); heap->total_size += elem_size;
Signature · 1 line
2.7.4
PATCH v5 4/70 eal: add function to dump malloc heap contents
In reply to Anatoly BurakovMalloc heap is now a doubly linked list, so it's now possible to iterate over each malloc element regardless of its state.
---
Notes:
v3: mark function as experimental
lib/librte_eal/common/include/rte_malloc.h | 10 ++++++++++ lib/librte_eal/common/malloc_elem.c | 24 ++++++++++++++++++++++++ lib/librte_eal/common/malloc_elem.h | 6 ++++++ lib/librte_eal/common/malloc_heap.c | 22 ++++++++++++++++++++++ lib/librte_eal/common/malloc_heap.h | 3 +++ lib/librte_eal/common/rte_malloc.c | 17 +++++++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 7 files changed, 83 insertions(+)
lib/librte_eal/common/include/rte_malloc.h +10 -0
@@ -13,6 +13,7 @@#include <stdio.h> #include <stddef.h> +#include <rte_compat.h> #include <rte_memory.h> #ifdef __cplusplus
@@ -278,6 +279,15 @@ void rte_malloc_dump_stats(FILE *f, const char *type);/** +* Dump contents of all malloc heaps to a file. +* +* @param f +* A pointer to a file for output +*/ +void __rte_experimental +rte_malloc_dump_heaps (FILE *f); + +/** * Set the maximum amount of allocated memory for this type. * * This is not yet implemented
lib/librte_eal/common/malloc_elem.c +24 -0
@@ -1,6 +1,7 @@/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2014 Intel Corporation */ +#include <inttypes.h> #include <stdint.h> #include <stddef.h> #include <stdio.h>
@@ -434,3 +435,26 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size) }return 0 ; } + +static inline const char * +elem_state_to_str (enum elem_state state) +{ +switch (state) { +case ELEM_PAD : +return "PAD" ; +case ELEM_BUSY : +return "BUSY" ; +case ELEM_FREE : +return "FREE" ; + } +return "ERROR" ; +} + +void +malloc_elem_dump (const struct malloc_elem *elem,FILE *f) +{ +fprintf (f,"Malloc element at %p (%s)\n" , elem, +elem_state_to_str (elem->state)); +fprintf (f," len: 0x%zx pad: 0x%" PRIx32"\n" , elem->size, elem->pad); +fprintf (f," prev: %p next: %p\n" , elem->prev, elem->next); +}
lib/librte_eal/common/malloc_elem.h +6 -0
@@ -149,6 +149,12 @@ int malloc_elem_resize(struct malloc_elem *elem, size_t size);/* +* dump contents of malloc elem to a file. +*/ +void +malloc_elem_dump (const struct malloc_elem *elem,FILE *f); + +/* * Given an element size, compute its freelist index. */ size_t
lib/librte_eal/common/malloc_heap.c +22 -0
@@ -217,6 +217,28 @@ malloc_heap_get_stats(struct malloc_heap *heap,return 0 ; } +/* +* Function to retrieve data for heap on given socket +*/ +void +malloc_heap_dump (struct malloc_heap *heap,FILE *f) +{ +struct malloc_elem *elem; + +rte_spinlock_lock (&heap->lock); + +fprintf (f,"Heap size: 0x%zx\n" , heap->total_size); +fprintf (f,"Heap alloc count: %u\n" , heap->alloc_count); + + elem = heap->first; +while (elem) { +malloc_elem_dump (elem, f); + elem = elem->next; + } + +rte_spinlock_unlock (&heap->lock); +} +int rte_eal_malloc_heap_init (void ) {
lib/librte_eal/common/malloc_heap.h +3 -0
@@ -37,6 +37,9 @@ int malloc_heap_get_stats(struct malloc_heap *heap, struct rte_malloc_socket_stats *socket_stats); +void +malloc_heap_dump (struct malloc_heap *heap,FILE *f); +int rte_eal_malloc_heap_init (void );
lib/librte_eal/common/rte_malloc.c +17 -0
@@ -182,6 +182,23 @@ rte_malloc_get_socket_stats(int socket, }/* +* Function to dump contents of all heaps +*/ +void __rte_experimental +rte_malloc_dump_heaps (FILE *f) +{ +struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config; +unsigned int idx; + +for (idx =0 ; idx <rte_socket_count (); idx++) { +unsigned int socket =rte_socket_id_by_idx (idx); +fprintf (f,"Heap on socket %i:\n" , socket); +malloc_heap_dump (&mcfg->malloc_heaps[socket], f); + } + +} + +/* * Print stats on memory type. If type is NULL, info on all types is printed */ void
lib/librte_eal/rte_eal_version.map +1 -0
@@ -222,6 +222,7 @@ EXPERIMENTAL { rte_eal_hotplug_remove; rte_eal_mbuf_user_pool_ops; rte_log_register_type_and_pick_level; + rte_malloc_dump_heaps; rte_mp_action_register; rte_mp_action_unregister; rte_mp_reply;
Signature · 1 line
2.7.4
PATCH v5 5/70 test: add command to dump malloc heap contents
In reply to Anatoly Burakov--- test/test/commands.c | 3 +++ 1 file changed, 3 insertions(+)
test/test/commands.c +3 -0
@@ -137,6 +137,8 @@ static void cmd_dump_parsed(void *parsed_result,rte_log_dump (stdout); else if (!strcmp(res->dump, "dump_malloc_stats"))rte_malloc_dump_stats (stdout,NULL ); + else if (!strcmp(res->dump, "dump_malloc_heaps")) +rte_malloc_dump_heaps (stdout); } cmdline_parse_token_string_t cmd_dump_dump =
@@ -147,6 +149,7 @@ cmdline_parse_token_string_t cmd_dump_dump ="dump_ring#" "dump_mempool#" "dump_malloc_stats#" +"dump_malloc_heaps#" "dump_devargs#" "dump_log_types");
Signature · 1 line
2.7.4
PATCH v5 6/70 eal: make malloc_elem_join_adjacent_free public
In reply to Anatoly BurakovDown the line, we will need to join free segments to determine whether the resulting contiguous free space is bigger than a page size, allowing to free some memory back to the system.
---
Notes:
v4: clarified commit message
lib/librte_eal/common/malloc_elem.c | 6 +++--- lib/librte_eal/common/malloc_elem.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-)
lib/librte_eal/common/malloc_elem.c +3 -3
@@ -325,8 +325,8 @@ join_elem(struct malloc_elem *elem1, struct malloc_elem *elem2) elem1->next = next; } -static struct malloc_elem * -elem_join_adjacent_free (struct malloc_elem *elem) +struct malloc_elem * +malloc_elem_join_adjacent_free (struct malloc_elem *elem) {/* * check if next element exists, is adjacent and is free, if so join
@@ -388,7 +388,7 @@ malloc_elem_free(struct malloc_elem *elem) ptr =RTE_PTR_ADD (elem,sizeof (*elem)); data_len = elem->size -MALLOC_ELEM_OVERHEAD ; - elem =elem_join_adjacent_free (elem); + elem =malloc_elem_join_adjacent_free (elem);malloc_elem_free_list_insert (elem);
lib/librte_eal/common/malloc_elem.h +3 -0
@@ -141,6 +141,9 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size,int malloc_elem_free (struct malloc_elem *elem); +struct malloc_elem * +malloc_elem_join_adjacent_free (struct malloc_elem *elem); +/* * attempt to resize a malloc_elem by expanding into any free space * immediately after it in memory.
Signature · 1 line
2.7.4
PATCH v5 7/70 eal: make malloc free list remove public
In reply to Anatoly BurakovWe will need to be able to remove entries from free lists from heaps during certain events, such as rollbacks, or when freeing memory to the system (where a previously element disappears and thus can no longer be in the free list).
---
Notes:
v4: clarified commit message
lib/librte_eal/common/malloc_elem.c | 12 ++++++------ lib/librte_eal/common/malloc_elem.h | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-)
lib/librte_eal/common/malloc_elem.c +6 -6
@@ -245,8 +245,8 @@ malloc_elem_free_list_insert(struct malloc_elem *elem)/* * Remove the specified element from its heap's free list. */ -static void -elem_free_list_remove (struct malloc_elem *elem) +void +malloc_elem_free_list_remove (struct malloc_elem *elem) {LIST_REMOVE (elem, free_list); }
@@ -266,7 +266,7 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size, unsigned align,const size_t trailer_size = elem->size - old_elem_size - size -MALLOC_ELEM_OVERHEAD ; -elem_free_list_remove (elem); +malloc_elem_free_list_remove (elem);if (trailer_size >MALLOC_ELEM_OVERHEAD +MIN_DATA_SIZE ) {/* split it, too much free space after elem */
@@ -340,7 +340,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase =RTE_PTR_SUB (elem->next,MALLOC_ELEM_TRAILER_LEN );/* remove from free list, join to this one */ -elem_free_list_remove (elem->next); +malloc_elem_free_list_remove (elem->next);join_elem (elem, elem->next);/* erase header and trailer */
@@ -360,7 +360,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem) erase =RTE_PTR_SUB (elem,MALLOC_ELEM_TRAILER_LEN );/* remove from free list, join to this one */ -elem_free_list_remove (elem->prev); +malloc_elem_free_list_remove (elem->prev); new_elem = elem->prev;join_elem (new_elem, elem);
@@ -423,7 +423,7 @@ malloc_elem_resize(struct malloc_elem *elem, size_t size)/* we now know the element fits, so remove from free list, * join the two */ -elem_free_list_remove (elem->next); +malloc_elem_free_list_remove (elem->next);join_elem (elem, elem->next);if (elem->size - new_size >=MIN_DATA_SIZE +MALLOC_ELEM_OVERHEAD ) {
lib/librte_eal/common/malloc_elem.h +3 -0
@@ -151,6 +151,9 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem);int malloc_elem_resize (struct malloc_elem *elem,size_t size); +void +malloc_elem_free_list_remove (struct malloc_elem *elem); +/* * dump contents of malloc elem to a file. */
Signature · 1 line
2.7.4
PATCH v5 8/70 eal: make malloc free return resulting malloc element
In reply to Anatoly BurakovThis will be needed because we need to know how big is the new empty space, to check whether we can free some pages as a result.
---
Notes:
v4: clarified commit message
lib/librte_eal/common/malloc_elem.c | 4 ++-- lib/librte_eal/common/malloc_elem.h | 2 +- lib/librte_eal/common/malloc_heap.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-)
lib/librte_eal/common/malloc_elem.c +2 -2
@@ -379,7 +379,7 @@ malloc_elem_join_adjacent_free(struct malloc_elem *elem)* blocks either immediately before or immediately after newly freed block * are also free, the blocks are merged together. */ -int +struct malloc_elem *malloc_elem_free (struct malloc_elem *elem) {void *ptr;
@@ -397,7 +397,7 @@ malloc_elem_free(struct malloc_elem *elem)memset (ptr,0 , data_len); -return 0 ; +return elem; }/*
lib/librte_eal/common/malloc_elem.h +1 -1
@@ -138,7 +138,7 @@ malloc_elem_alloc(struct malloc_elem *elem, size_t size,* blocks either immediately before or immediately after newly freed block * are also free, the blocks are merged together. */ -int +struct malloc_elem *malloc_elem_free (struct malloc_elem *elem); struct malloc_elem *
lib/librte_eal/common/malloc_heap.c +2 -2
@@ -145,7 +145,7 @@ int malloc_heap_free(struct malloc_elem *elem) {struct malloc_heap *heap; -int ret; +struct malloc_elem *ret;if (!malloc_elem_cookies_ok (elem) || elem->state !=ELEM_BUSY )return -1 ;
@@ -159,7 +159,7 @@ malloc_heap_free(struct malloc_elem *elem)rte_spinlock_unlock (&(heap->lock)); -return ret; +return ret !=NULL ?0 :-1 ; }int
Signature · 1 line
2.7.4
PATCH v5 9/70 eal: replace panics with error messages in malloc
In reply to Anatoly BurakovWe shouldn't ever panic in system libraries, let alone in such core ones as EAL, so replace all panic messages with error messages.
---
Notes:
v4: clarified commit message
lib/librte_eal/common/rte_malloc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
lib/librte_eal/common/rte_malloc.c +5 -3
@@ -30,7 +30,7 @@ void rte_free(void *addr) {if (addr ==NULL )return ;if (malloc_heap_free (malloc_elem_from_data (addr)) <0 ) -rte_panic ("Fatal error: Invalid memory\n" ); +RTE_LOG (ERR ,EAL ,"Error: Invalid memory\n" ); }/*
@@ -134,8 +134,10 @@ rte_realloc(void *ptr, size_t size, unsigned align)return rte_malloc (NULL , size, align);struct malloc_elem *elem =malloc_elem_from_data (ptr); -if (elem ==NULL ) -rte_panic ("Fatal error: memory corruption detected\n" ); +if (elem ==NULL ) { +RTE_LOG (ERR ,EAL ,"Error: memory corruption detected\n" ); +return NULL ; + } size =RTE_CACHE_LINE_ROUNDUP (size), align =RTE_CACHE_LINE_ROUNDUP (align);/* check alignment matches first, and if ok, see if we can resize block */
Signature · 1 line
2.7.4
PATCH v5 10/70 eal: add backend support for contiguous allocation
In reply to Anatoly BurakovNo major changes, just add some checks in a few key places, and a new parameter to pass around.
Also, add a function to check malloc element for physical contiguousness. For now, assume hugepage memory is always contiguous, while non-hugepage memory will be checked.
---
Notes:
v3:
- Moved this patch earlier
- Added physical contiguousness checking function
lib/librte_eal/common/eal_common_memzone.c | 23 +++--- lib/librte_eal/common/malloc_elem.c | 125 ++++++++++++++++++++++++----- lib/librte_eal/common/malloc_elem.h | 6 +- lib/librte_eal/common/malloc_heap.c | 11 +-- lib/librte_eal/common/malloc_heap.h | 4 +- lib/librte_eal/common/rte_malloc.c | 7 +- 6 files changed, 133 insertions(+), 43 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +13 -10
@@ -98,7 +98,8 @@ find_heap_max_free_elem(int *s, unsigned align)static const struct rte_memzone *memzone_reserve_aligned_thread_unsafe (const char *name,size_t len, -int socket_id,unsigned flags,unsigned align,unsigned bound) +int socket_id,unsigned int flags,unsigned int align, +unsigned int bound,bool contig) {struct rte_memzone *mz;struct rte_mem_config *mcfg;
@@ -188,7 +189,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,/* allocate memory on heap */ void *mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[socket],NULL , - requested_len, flags, align, bound); + requested_len, flags, align, bound, contig);if ((mz_addr ==NULL ) && (socket_id ==SOCKET_ID_ANY )) {/* try other heaps */
@@ -197,7 +198,8 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,continue ; mz_addr =malloc_heap_alloc (&mcfg->malloc_heaps[i], -NULL , requested_len, flags, align, bound); +NULL , requested_len, flags, align, + bound, contig);if (mz_addr !=NULL )break ; }
@@ -235,9 +237,9 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len, }static const struct rte_memzone * -rte_memzone_reserve_thread_safe (const char *name,size_t len, -int socket_id,unsigned flags,unsigned align, -unsigned bound) +rte_memzone_reserve_thread_safe (const char *name,size_t len,int socket_id, +unsigned int flags,unsigned int align,unsigned int bound, +bool contig) {struct rte_mem_config *mcfg;const struct rte_memzone *mz =NULL ;
@@ -248,7 +250,7 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len,rte_rwlock_write_lock (&mcfg->mlock); mz =memzone_reserve_aligned_thread_unsafe ( - name, len, socket_id, flags, align, bound); + name, len, socket_id, flags, align, bound, contig);rte_rwlock_write_unlock (&mcfg->mlock);
@@ -265,7 +267,7 @@ rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id, unsigned flags, unsigned align, unsigned bound) { return rte_memzone_reserve_thread_safe(name, len, socket_id, flags, -align ,bound ); +align ,bound ,false ); }/*
@@ -277,7 +279,7 @@ rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id, unsigned flags, unsigned align) {return rte_memzone_reserve_thread_safe (name, len, socket_id, flags, - align,0 ); + align,0 , false); }/*
@@ -289,7 +291,8 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) {return rte_memzone_reserve_thread_safe (name, len, socket_id, - flags,RTE_CACHE_LINE_SIZE ,0 ); + flags,RTE_CACHE_LINE_SIZE ,0 , + false); }int
lib/librte_eal/common/malloc_elem.c +103 -22
160 lines not on this page · raw message
lib/librte_eal/common/malloc_elem.h +4 -2
@@ -5,6 +5,8 @@#ifndef MALLOC_ELEM_H_ #define MALLOC_ELEM_H_ +#include <stdbool.h> +#include <rte_memory.h> /* dummy definition of struct so we can use pointers to it in malloc_elem struct */
@@ -123,7 +125,7 @@ malloc_elem_insert(struct malloc_elem *elem);*/ int malloc_elem_can_hold (struct malloc_elem *elem,size_t size, -unsigned align,size_t bound); +unsigned int align,size_t bound,bool contig);/* * reserve a block of data in an existing malloc_elem. If the malloc_elem
@@ -131,7 +133,7 @@ malloc_elem_can_hold(struct malloc_elem *elem, size_t size,*/ struct malloc_elem *malloc_elem_alloc (struct malloc_elem *elem,size_t size, -unsigned align,size_t bound); +unsigned int align,size_t bound,bool contig);/* * free a malloc_elem block by adding it to the free list. If the
lib/librte_eal/common/malloc_heap.c +6 -5
@@ -88,7 +88,7 @@ malloc_heap_add_memseg(struct malloc_heap *heap, struct rte_memseg *ms)*/ static struct malloc_elem *find_suitable_element (struct malloc_heap *heap,size_t size, -unsigned flags,size_t align,size_t bound) +unsigned int flags,size_t align,size_t bound,bool contig) {size_t idx;struct malloc_elem *elem, *alt_elem =NULL ;
@@ -97,7 +97,8 @@ find_suitable_element(struct malloc_heap *heap, size_t size, idx < RTE_HEAP_NUM_FREELISTS; idx++) {for (elem =LIST_FIRST (&heap->free_head[idx]); !!elem; elem =LIST_NEXT (elem, free_list)) { -if (malloc_elem_can_hold (elem, size, align, bound)) { +if (malloc_elem_can_hold (elem, size, align, bound, + contig)) {if (check_hugepage_sz (flags, elem->ms->hugepage_sz))return elem;if (alt_elem ==NULL )
@@ -121,7 +122,7 @@ find_suitable_element(struct malloc_heap *heap, size_t size,void *malloc_heap_alloc (struct malloc_heap *heap,const char *type __attribute__((unused)),size_t size,unsigned flags, -size_t align,size_t bound) +size_t align,size_t bound,bool contig) {struct malloc_elem *elem;
@@ -130,9 +131,9 @@ malloc_heap_alloc(struct malloc_heap *heap,rte_spinlock_lock (&heap->lock); - elem =find_suitable_element (heap, size, flags, align, bound); + elem =find_suitable_element (heap, size, flags, align, bound, contig);if (elem !=NULL ) { - elem =malloc_elem_alloc (elem, size, align, bound); + elem =malloc_elem_alloc (elem, size, align, bound, contig);/* increase heap's count of allocated elements */ heap->alloc_count++; }
lib/librte_eal/common/malloc_heap.h +3 -1
@@ -5,6 +5,8 @@#ifndef MALLOC_HEAP_H_ #define MALLOC_HEAP_H_ +#include <stdbool.h> +#include <rte_malloc.h> #include <rte_malloc_heap.h>
@@ -25,7 +27,7 @@ malloc_get_numa_socket(void)void *malloc_heap_alloc (struct malloc_heap *heap,const char *type,size_t size, -unsigned flags,size_t align,size_t bound); +unsigned int flags,size_t align,size_t bound,bool contig);int malloc_heap_free (struct malloc_elem *elem);
lib/librte_eal/common/rte_malloc.c +4 -3
@@ -37,7 +37,8 @@ void rte_free(void *addr)* Allocate memory on specified heap. */ void * -rte_malloc_socket (const char *type,size_t size,unsigned align,int socket_arg) +rte_malloc_socket (const char *type,size_t size,unsigned int align, +int socket_arg) {struct rte_mem_config *mcfg =rte_eal_get_configuration ()->mem_config;int socket, i;
@@ -60,7 +61,7 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket_arg)return NULL ; ret =malloc_heap_alloc (&mcfg->malloc_heaps[socket], type, - size,0 , align ==0 ?1 : align,0 ); + size,0 , align ==0 ?1 : align,0 , false);if (ret !=NULL || socket_arg !=SOCKET_ID_ANY )return ret;
@@ -71,7 +72,7 @@ rte_malloc_socket(const char *type, size_t size, unsigned align, int socket_arg)continue ; ret =malloc_heap_alloc (&mcfg->malloc_heaps[i], type, - size,0 , align ==0 ?1 : align,0 ); + size,0 , align ==0 ?1 : align,0 , false);if (ret !=NULL )return ret; }
Signature · 1 line
2.7.4
PATCH v5 11/70 eal: enable reserving physically contiguous memzones
In reply to Anatoly BurakovThis adds a new flag to request reserved memzone to be IOVA contiguous. This is useful for allocating hardware resources like NIC rings/queues etc.For now, hugepage memory is always contiguous, but we need to prepare the drivers for the switch.
---
Notes:
v4:
- Replaced a new API with a memzone flag
v3:
- Moved this patch earlier
lib/librte_eal/common/eal_common_memzone.c | 25 +++++++++++++++++-------- lib/librte_eal/common/include/rte_memzone.h | 11 +++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +17 -8
@@ -99,12 +99,13 @@ find_heap_max_free_elem(int *s, unsigned align)static const struct rte_memzone *memzone_reserve_aligned_thread_unsafe (const char *name,size_t len,int socket_id,unsigned int flags,unsigned int align, -unsigned int bound,bool contig) +unsigned int bound) {struct rte_memzone *mz;struct rte_mem_config *mcfg;size_t requested_len;int socket, i; +bool contig;/* get pointer to global configuration */ mcfg =rte_eal_get_configuration ()->mem_config;
@@ -170,7 +171,17 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,if (!rte_eal_has_hugepages ()) socket_id =SOCKET_ID_ANY ; + contig = (flags &RTE_MEMZONE_IOVA_CONTIG ) !=0 ; +/* malloc only cares about size flags, remove contig flag from flags */ + flags &= ~RTE_MEMZONE_IOVA_CONTIG ; +if (len ==0 ) { +/* len == 0 is only allowed for non-contiguous zones */ +if (contig) { +RTE_LOG (DEBUG ,EAL ,"Reserving zero-length contiguous memzones is not supported\n" ); + rte_errno =EINVAL ; +return NULL ; + }if (bound !=0 ) requested_len = bound;else {
@@ -238,8 +249,7 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,static const struct rte_memzone *rte_memzone_reserve_thread_safe (const char *name,size_t len,int socket_id, -unsigned int flags,unsigned int align,unsigned int bound, -bool contig) +unsigned int flags,unsigned int align,unsigned int bound) {struct rte_mem_config *mcfg;const struct rte_memzone *mz =NULL ;
@@ -250,7 +260,7 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len, int socket_id,rte_rwlock_write_lock (&mcfg->mlock); mz =memzone_reserve_aligned_thread_unsafe ( - name, len, socket_id, flags, align, bound, contig); + name, len, socket_id, flags, align, bound);rte_rwlock_write_unlock (&mcfg->mlock);
@@ -267,7 +277,7 @@ rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id, unsigned flags, unsigned align, unsigned bound) { return rte_memzone_reserve_thread_safe(name, len, socket_id, flags, -align ,bound ,false ); +align ,bound ); }/*
@@ -279,7 +289,7 @@ rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id, unsigned flags, unsigned align) {return rte_memzone_reserve_thread_safe (name, len, socket_id, flags, - align,0 , false); + align,0 ); }/*
@@ -291,8 +301,7 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) {return rte_memzone_reserve_thread_safe (name, len, socket_id, - flags,RTE_CACHE_LINE_SIZE ,0 , - false); + flags,RTE_CACHE_LINE_SIZE ,0 ); }int
lib/librte_eal/common/include/rte_memzone.h +11 -0
@@ -23,6 +23,7 @@*/ #include <stdio.h> +#include <rte_compat.h> #include <rte_memory.h> #include <rte_common.h>
@@ -39,6 +40,7 @@ extern "C" {#define RTE_MEMZONE_512MB 0x00040000/**< Use 512MB pages. */ #define RTE_MEMZONE_4GB 0x00080000/**< Use 4GB pages. */ #define RTE_MEMZONE_SIZE_HINT_ONLY 0x00000004/**< Use available page size */ +#define RTE_MEMZONE_IOVA_CONTIG 0x00100000/**< Ask for IOVA-contiguous memzone. */ /** * A structure describing a memzone, which is a contiguous portion of
@@ -102,6 +104,9 @@ struct rte_memzone {* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @return * A pointer to a correctly-filled read-only memzone descriptor, or NULL * on error.
@@ -152,6 +157,9 @@ const struct rte_memzone *rte_memzone_reserve(const char *name,* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @param align * Alignment for resulting memzone. Must be a power of 2. * @return
@@ -207,6 +215,9 @@ const struct rte_memzone *rte_memzone_reserve_aligned(const char *name,* If this flag is not set, the function * will return error on an unavailable size * request. +* - RTE_MEMZONE_IOVA_CONTIG - Ensure reserved memzone is IOVA-contiguous. +* This option should be used when allocating +* memory intended for hardware rings etc. * @param align * Alignment for resulting memzone. Must be a power of 2. * @param bound
Signature · 1 line
2.7.4
PATCH v5 12/70 ethdev: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
This fixes the following drivers in one go:
grep -Rl rte_eth_dma_zone_reserve drivers/
drivers/net/avf/avf_rxtx.cdrivers/net/thunderx/nicvf_ethdev.cdrivers/net/e1000/igb_rxtx.cdrivers/net/e1000/em_rxtx.cdrivers/net/fm10k/fm10k_ethdev.cdrivers/net/vmxnet3/vmxnet3_rxtx.cdrivers/net/liquidio/lio_rxtx.cdrivers/net/i40e/i40e_rxtx.cdrivers/net/sfc/sfc.cdrivers/net/ixgbe/ixgbe_rxtx.cdrivers/net/nfp/nfp_net.c
---
Notes:
v4: replaced use of new API with additional memzone flag
v3: moved this patch earlier in the patchset
lib/librte_ether/rte_ethdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/librte_ether/rte_ethdev.c +2 -1
@@ -3403,7 +3403,8 @@ rte_eth_dma_zone_reserve(const struct rte_eth_dev *dev, const char *ring_name,if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, size, socket_id,0 , align); +return rte_memzone_reserve_aligned (z_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align); }int
Signature · 1 line
2.7.4
PATCH v5 13/70 crypto/qat: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
Also, remove the weird page alignment code.
---
Notes:
v4:
- Replace new API with new memzone flag
- Removed experimental API from build files
v3:
- Move the patch earlier in the patchset
- Fix build system files to allow experimental API's
- Removed non-sensical memzone flags code
drivers/crypto/qat/qat_qp.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-)
drivers/crypto/qat/qat_qp.c +2 -21
@@ -54,8 +54,6 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size, int socket_id) {const struct rte_memzone *mz; -unsigned memzone_flags =0 ; -const struct rte_memseg *ms;PMD_INIT_FUNC_TRACE (); mz =rte_memzone_lookup (queue_name);
@@ -78,25 +76,8 @@ queue_dma_zone_reserve(const char *queue_name, uint32_t queue_size,PMD_DRV_LOG (DEBUG ,"Allocate memzone for %s, size %u on socket %u" , queue_name, queue_size, socket_id); - ms =rte_eal_get_physmem_layout (); -switch (ms[0 ].hugepage_sz) { -case (RTE_PGSIZE_2M ): - memzone_flags =RTE_MEMZONE_2MB ; -break ; -case (RTE_PGSIZE_1G ): - memzone_flags =RTE_MEMZONE_1GB ; -break ; -case (RTE_PGSIZE_16M ): - memzone_flags =RTE_MEMZONE_16MB ; -break ; -case (RTE_PGSIZE_16G ): - memzone_flags =RTE_MEMZONE_16GB ; -break ; -default : - memzone_flags =RTE_MEMZONE_SIZE_HINT_ONLY ; - } -return rte_memzone_reserve_aligned (queue_name, queue_size, socket_id, - memzone_flags, queue_size); +return rte_memzone_reserve_aligned (queue_name, queue_size, + socket_id,RTE_MEMZONE_IOVA_CONTIG , queue_size); } int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
Signature · 1 line
2.7.4
PATCH v5 14/70 net/avf: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/avf/avf_ethdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/avf/avf_ethdev.c +2 -2
@@ -1365,8 +1365,8 @@ avf_allocate_dma_mem_d(__rte_unused struct avf_hw *hw,return AVF_ERR_PARAM ;snprintf (z_name,sizeof (z_name),"avf_dma_%" PRIu64,rte_rand ()); - mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY ,0 , - alignment,RTE_PGSIZE_2M ); + mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG , alignment,RTE_PGSIZE_2M );if (!mz)return AVF_ERR_NO_MEMORY ;
Signature · 1 line
2.7.4
PATCH v5 15/70 net/bnx2x: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/bnx2x/bnx2x.c | 2 +- drivers/net/bnx2x/bnx2x_rxtx.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
drivers/net/bnx2x/bnx2x.c +1 -1
@@ -177,7 +177,7 @@ bnx2x_dma_alloc(struct bnx2x_softc *sc, size_t size, struct bnx2x_dma *dma, rte_get_timer_cycles());/* Caller must take care that strlen(mz_name) < RTE_MEMZONE_NAMESIZE */ - z =rte_memzone_reserve_aligned (mz_name, (uint64_t ) (size), + z =rte_memzone_reserve_aligned_contig (mz_name, (uint64_t )size,SOCKET_ID_ANY ,0 , align);if (z ==NULL ) {
drivers/net/bnx2x/bnx2x_rxtx.c +2 -1
@@ -26,7 +26,8 @@ ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, ring_size, socket_id,0 ,BNX2X_PAGE_SIZE ); +return rte_memzone_reserve_aligned (z_name, ring_size, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,BNX2X_PAGE_SIZE ); } static void
Signature · 1 line
2.7.4
Re: [PATCH v5 15/70] net/bnx2x: use contiguous allocation for DMA memory
Compilation error with clang:
09/04/2018 20:00, Anatoly Burakov:
drivers/net/bnx2x/bnx2x.c bnx2x_dma_alloc(struct bnx2x_softc *sc, size_t size, struct bnx2x_dma *dma, · line 180
Quoted 4 lines
drivers/net/bnx2x/bnx2x.c +1
-1- z = rte_memzone_reserve_aligned(mz_name, (uint64_t) (size), + z = rte_memzone_reserve_aligned_contig(mz_name, (uint64_t)size,
drivers/net/bnx2x/bnx2x.c:180:6: fatal error:
implicit declaration of function 'rte_memzone_reserve_aligned_contig' is invalid in C99
Re: [PATCH v5 15/70] net/bnx2x: use contiguous allocation for DMA memory
Quoted 15 lines · Thomas Monjalon
Compilation error with clang:
09/04/2018 20:00, Anatoly Burakov:
drivers/net/bnx2x/bnx2x.c bnx2x_dma_alloc(struct bnx2x_softc *sc, size_t size, struct bnx2x_dma *dma, · line 180
Quoted 4 lines
drivers/net/bnx2x/bnx2x.c +1
-1- z = rte_memzone_reserve_aligned(mz_name, (uint64_t) (size), + z = rte_memzone_reserve_aligned_contig(mz_name, (uint64_t)size,
drivers/net/bnx2x/bnx2x.c:180:6: fatal error:
implicit declaration of function 'rte_memzone_reserve_aligned_contig' is invalid in C99
Apologies, missed the rename. This API call doesn't exist any more.
Signature · 2 lines
Thanks, Anatoly
PATCH v5 16/70 net/bnxt: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Added this driver to the list of modified drivers
- Add experimental API to build files
All memzone reserve calls then check physical addresses, so this looks like they're reserving DMA memory. Corrections welcome.
drivers/net/bnxt/bnxt_ethdev.c | 17 ++++++++++------- drivers/net/bnxt/bnxt_ring.c | 9 +++++---- drivers/net/bnxt/bnxt_vnic.c | 8 ++++---- 3 files changed, 19 insertions(+), 15 deletions(-)
drivers/net/bnxt/bnxt_ethdev.c +10 -7
@@ -3147,9 +3147,10 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev) sizeof(struct rx_port_stats) + 512);if (!mz) { mz =rte_memzone_reserve (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (mz ==NULL )return -ENOMEM ; }
@@ -3181,10 +3182,12 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev) total_alloc_len =RTE_CACHE_LINE_ROUNDUP (sizeof (struct tx_port_stats ) +512 );if (!mz) { - mz =rte_memzone_reserve (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); + mz =rte_memzone_reserve (mz_name, + total_alloc_len, +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (mz ==NULL )return -ENOMEM ; }
drivers/net/bnxt/bnxt_ring.c +5 -4
@@ -166,10 +166,11 @@ int bnxt_alloc_rings(struct bnxt *bp, uint16_t qidx, mz =rte_memzone_lookup (mz_name);if (!mz) { mz =rte_memzone_reserve_aligned (mz_name, total_alloc_len, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY , -getpagesize ()); +SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG , +getpagesize ());if (mz ==NULL )return -ENOMEM ; }
drivers/net/bnxt/bnxt_vnic.c +4 -4
@@ -185,10 +185,10 @@ int bnxt_alloc_vnic_attributes(struct bnxt *bp) mz =rte_memzone_lookup (mz_name);if (!mz) { mz =rte_memzone_reserve (mz_name, - entry_length * max_vnics, -SOCKET_ID_ANY , -RTE_MEMZONE_2MB | -RTE_MEMZONE_SIZE_HINT_ONLY ); + entry_length * max_vnics,SOCKET_ID_ANY , +RTE_MEMZONE_2MB | +RTE_MEMZONE_SIZE_HINT_ONLY | +RTE_MEMZONE_IOVA_CONTIG );if (!mz)return -ENOMEM ; }
Signature · 1 line
2.7.4
PATCH v5 17/70 net/cxgbe: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/cxgbe/sge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/cxgbe/sge.c +2 -1
@@ -1344,7 +1344,8 @@ static void *alloc_ring(size_t nelem, size_t elem_size,* handle the maximum ring size is allocated in order to allow for * resizing in later calls to the queue setup function. */ - tz =rte_memzone_reserve_aligned (z_name, len, socket_id,0 ,4096 ); + tz =rte_memzone_reserve_aligned (z_name, len, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,4096 );if (!tz)return NULL ;
Signature · 1 line
2.7.4
PATCH v5 18/70 net/ena: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/ena/base/ena_plat_dpdk.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/ena/base/ena_plat_dpdk.h +6 -3
@@ -188,7 +188,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (handle); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size,SOCKET_ID_ANY ,0 ); \ + mz =rte_memzone_reserve (z_name, size,SOCKET_ID_ANY , \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ phys = mz->iova; \
@@ -206,7 +207,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (dev_node); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size, node,0 ); \ + mz =rte_memzone_reserve (z_name, size, node, \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ phys = mz->iova; \
@@ -219,7 +221,8 @@ typedef uint64_t dma_addr_t;ENA_TOUCH (dmadev);ENA_TOUCH (dev_node); \snprintf (z_name,sizeof (z_name), \"ena_alloc_%d" , ena_alloc_cnt++); \ - mz =rte_memzone_reserve (z_name, size, node,0 ); \ + mz =rte_memzone_reserve (z_name, size, node, \ +RTE_MEMZONE_IOVA_CONTIG ); \memset (mz->addr,0 , size); \ virt = mz->addr; \ }while (0 )
Signature · 1 line
2.7.4
PATCH v5 19/70 net/enic: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/enic/enic_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/net/enic/enic_main.c +4 -5
@@ -343,8 +343,8 @@ enic_alloc_consistent(void *priv, size_t size,struct enic *enic = (struct enic *)priv;struct enic_memzone_entry *mze; - rz =rte_memzone_reserve_aligned ((const char *)name, - size,SOCKET_ID_ANY ,0 ,ENIC_ALIGN ); + rz =rte_memzone_reserve_aligned ((const char *)name, size, +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG ,ENIC_ALIGN );if (!rz) {pr_err ("%s : Failed to allocate memory requested for %s\n" , __func__, name);
@@ -888,9 +888,8 @@ int enic_alloc_wq(struct enic *enic, uint16_t queue_idx, instance++); wq->cqmsg_rz =rte_memzone_reserve_aligned ((const char *)name, -sizeof (uint32_t ), -SOCKET_ID_ANY ,0 , -ENIC_ALIGN ); +sizeof (uint32_t ),SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG ,ENIC_ALIGN );if (!wq->cqmsg_rz)return -ENOMEM ;
Signature · 1 line
2.7.4
PATCH v5 20/70 net/i40e: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/i40e/i40e_ethdev.c | 4 ++-- drivers/net/i40e/i40e_rxtx.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/net/i40e/i40e_ethdev.c +2 -2
@@ -4053,8 +4053,8 @@ i40e_allocate_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,return I40E_ERR_PARAM ;snprintf (z_name,sizeof (z_name),"i40e_dma_%" PRIu64,rte_rand ()); - mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY ,0 , - alignment,RTE_PGSIZE_2M ); + mz =rte_memzone_reserve_bounded (z_name, size,SOCKET_ID_ANY , +RTE_MEMZONE_IOVA_CONTIG , alignment,RTE_PGSIZE_2M );if (!mz)return I40E_ERR_NO_MEMORY ;
drivers/net/i40e/i40e_rxtx.c +2 -2
@@ -2189,8 +2189,8 @@ i40e_memzone_reserve(const char *name, uint32_t len, int socket_id)if (mz)return mz; - mz =rte_memzone_reserve_aligned (name, len, - socket_id,0 ,I40E_RING_BASE_ALIGN ); + mz =rte_memzone_reserve_aligned (name, len, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,I40E_RING_BASE_ALIGN );return mz; }
Signature · 1 line
2.7.4
PATCH v5 21/70 net/qede: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved the patch earlier in the patchset
drivers/net/qede/base/bcm_osal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/qede/base/bcm_osal.c +4 -3
@@ -135,8 +135,8 @@ void *osal_dma_alloc_coherent(struct ecore_dev *p_dev,if (core_id == (unsigned int )LCORE_ID_ANY ) core_id =rte_get_master_lcore (); socket_id =rte_lcore_to_socket_id (core_id); - mz =rte_memzone_reserve_aligned (mz_name, size, - socket_id,0 ,RTE_CACHE_LINE_SIZE ); + mz =rte_memzone_reserve_aligned (mz_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG ,RTE_CACHE_LINE_SIZE );if (!mz) { DP_ERR(p_dev, "Unable to allocate DMA memory " "of size %zu bytes - %s\n",
@@ -174,7 +174,8 @@ void *osal_dma_alloc_coherent_aligned(struct ecore_dev *p_dev,if (core_id == (unsigned int )LCORE_ID_ANY ) core_id =rte_get_master_lcore (); socket_id =rte_lcore_to_socket_id (core_id); - mz =rte_memzone_reserve_aligned (mz_name, size, socket_id,0 , align); + mz =rte_memzone_reserve_aligned (mz_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align);if (!mz) { DP_ERR(p_dev, "Unable to allocate DMA memory " "of size %zu bytes - %s\n",
Signature · 1 line
2.7.4
PATCH v5 22/70 net/virtio: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
v3:
- Moved patch earlier in the patchset
drivers/net/virtio/virtio_ethdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/virtio/virtio_ethdev.c +4 -4
@@ -391,8 +391,8 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx) size, vq->vq_ring_size); mz =rte_memzone_reserve_aligned (vq_name, vq->vq_ring_size, -SOCKET_ID_ANY , -0 ,VIRTIO_PCI_VRING_ALIGN ); +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG , +VIRTIO_PCI_VRING_ALIGN );if (mz ==NULL ) {if (rte_errno ==EEXIST ) mz =rte_memzone_lookup (vq_name);
@@ -417,8 +417,8 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)snprintf (vq_hdr_name,sizeof (vq_hdr_name),"port%d_vq%d_hdr" , dev->data->port_id, vtpci_queue_idx); hdr_mz =rte_memzone_reserve_aligned (vq_hdr_name, sz_hdr_mz, -SOCKET_ID_ANY ,0 , -RTE_CACHE_LINE_SIZE ); +SOCKET_ID_ANY ,RTE_MEMZONE_IOVA_CONTIG , +RTE_CACHE_LINE_SIZE );if (hdr_mz ==NULL ) {if (rte_errno ==EEXIST ) hdr_mz =rte_memzone_lookup (vq_hdr_name);
Signature · 1 line
2.7.4
PATCH v5 23/70 net/vmxnet3: use contiguous allocation for DMA memory
In reply to Anatoly BurakovAll hardware drivers should allocate IOVA-contiguous memzones for their hardware resources.
---
Notes:
v4:
- Use new memzone flag instead of new API
- Remove experimental API from build files
v3:
- Add experimental API to build files
- Moved patch earlier in the patchset
drivers/net/vmxnet3/vmxnet3_ethdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/vmxnet3/vmxnet3_ethdev.c +3 -2
@@ -150,13 +150,14 @@ gpa_zone_reserve(struct rte_eth_dev *dev, uint32_t size,if (mz)rte_memzone_free (mz);return rte_memzone_reserve_aligned (z_name, size, socket_id, -0 , align); +RTE_MEMZONE_IOVA_CONTIG , align); }if (mz)return mz; -return rte_memzone_reserve_aligned (z_name, size, socket_id,0 , align); +return rte_memzone_reserve_aligned (z_name, size, socket_id, +RTE_MEMZONE_IOVA_CONTIG , align); }/*
Signature · 1 line
2.7.4