Skip to contentSkip to conversation

Memory Hotplug for DPDK

PATCH Superseded Anatoly Burakov 20 participants 471 messages Mar 3, 2018 – Apr 17, 2018 Page 2 of 5

Subsystems (4)
lore
Share & tools
lore
#115 lore raw

PATCH v2 36/41 net/ena: use contiguous allocation for DMA memory

In reply to Anatoly Burakov
---
 drivers/net/ena/base/ena_plat_dpdk.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ena/base/ena_plat_dpdk.h +4 -3
index 8cba319..c1ebf00 100644
@@ -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_contig(z_name,			\
+				size, SOCKET_ID_ANY, 0);		\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 		phys = mz->iova;					\
@@ -206,7 +207,7 @@ 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_contig(z_name, size, node, 0);	\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 		phys = mz->iova;					\
@@ -219,7 +220,7 @@ 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_contig(z_name, size, node, 0);	\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 	} while (0)
Signature · 1 line
2.7.4
Acked-by on v2 36/41
#116 lore raw

Re: [PATCH v2 36/41] net/ena: use contiguous allocation for DMA memory

2018-03-07 17:57 GMT+01:00 Anatoly Burakov <[email protected]>:

Quoted 1 line
Quoted 38 lines
---
 drivers/net/ena/base/ena_plat_dpdk.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/ena/base/ena_plat_dpdk.h +4 -4
index 8cba319..c1ebf00 100644
@@ -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_contig(z_name,                 \
+                               size, SOCKET_ID_ANY, 0);                \
                memset(mz->addr, 0, size);                              \
                virt = mz->addr;                                        \
                phys = mz->iova;                                        \
@@ -206,7 +207,7 @@ 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_contig(z_name, size, node, 0); \
                memset(mz->addr, 0, size);                              \
                virt = mz->addr;                                        \
                phys = mz->iova;                                        \
@@ -219,7 +220,7 @@ 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_contig(z_name, size, node, 0); \
                memset(mz->addr, 0, size);                              \
                virt = mz->addr;                                        \
        } while (0)
--

2.7.4

#117 lore raw

PATCH v2 37/41 net/enic: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
It is not 100% clear that second call to memzone_reserve is allocating DMA memory. Corrections welcome.

 drivers/net/enic/enic_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/enic/enic_main.c +2 -2
index ec9d343..cb2a7ba 100644
@@ -319,7 +319,7 @@ 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,
+	rz = rte_memzone_reserve_aligned_contig((const char *)name,
 					 size, SOCKET_ID_ANY, 0, ENIC_ALIGN);
 	if (!rz) {
 		pr_err("%s : Failed to allocate memory requested for %s\n",
@@ -787,7 +787,7 @@ int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
 		 "vnic_cqmsg-%s-%d-%d", enic->bdf_name, queue_idx,
 		instance++);
 
-	wq->cqmsg_rz = rte_memzone_reserve_aligned((const char *)name,
+	wq->cqmsg_rz = rte_memzone_reserve_aligned_contig((const char *)name,
 						   sizeof(uint32_t),
 						   SOCKET_ID_ANY, 0,
 						   ENIC_ALIGN);
Signature · 1 line
2.7.4
#118 lore raw

PATCH v2 38/41 net/i40e: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
It is not 100% clear that all users of this function need to allocate DMA memory. Corrections welcome.

 drivers/net/i40e/i40e_ethdev.c | 2 +-
 drivers/net/i40e/i40e_rxtx.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/i40e/i40e_ethdev.c +1 -1
index 508b417..0fffe2c 100644
@@ -4010,7 +4010,7 @@ 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,
+	mz = rte_memzone_reserve_bounded_contig(z_name, size, SOCKET_ID_ANY, 0,
 					 alignment, RTE_PGSIZE_2M);
 	if (!mz)
 		return I40E_ERR_NO_MEMORY;
drivers/net/i40e/i40e_rxtx.c +1 -1
index 1217e5a..6b2b40e 100644
@@ -2189,7 +2189,7 @@ i40e_memzone_reserve(const char *name, uint32_t len, int socket_id)
 	if (mz)
 		return mz;
 
-	mz = rte_memzone_reserve_aligned(name, len,
+	mz = rte_memzone_reserve_aligned_contig(name, len,
 					 socket_id, 0, I40E_RING_BASE_ALIGN);
 	return mz;
 }
Signature · 1 line
2.7.4
#119 lore raw

PATCH v2 39/41 net/qede: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
Doing "grep -R rte_memzone_reserve drivers/net/qede" returns the following:

drivers/net/qede/qede_fdir.c: mz = rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
drivers/net/qede/base/bcm_osal.c: mz = rte_memzone_reserve_aligned_contig(mz_name, size, drivers/net/qede/base/bcm_osal.c: mz = rte_memzone_reserve_aligned_contig(mz_name, size, socket_id, 0,

I took a brief look at memzone in qede_fdir and it didn't look like memzone was used for DMA, so i left it alone. Corrections welcome.

 drivers/net/qede/base/bcm_osal.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/qede/base/bcm_osal.c +3 -2
index fe42f32..707d553 100644
@@ -135,7 +135,7 @@ void *osal_dma_alloc_coherent(struct ecore_dev *p_dev,
 	if (core_id == (unsigned int)LCORE_ID_ANY)
 		core_id = 0;
 	socket_id = rte_lcore_to_socket_id(core_id);
-	mz = rte_memzone_reserve_aligned(mz_name, size,
+	mz = rte_memzone_reserve_aligned_contig(mz_name, size,
 					 socket_id, 0, RTE_CACHE_LINE_SIZE);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
@@ -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 = 0;
 	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_contig(mz_name, size, socket_id, 0,
+			align);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
 		       "of size %zu bytes - %s\n",
Signature · 1 line
2.7.4
Acked-by on v2 39/41
#120 lore raw

Re: [PATCH v2 39/41] net/qede: use contiguous allocation for DMA memory

-----Original Message-----
From: Anatoly Burakov <[email protected]>
Date: Wednesday, March 7, 2018 at 8:57 AM
To: "[email protected]" <[email protected]>
Cc: "Mody, Rasesh" <[email protected]>, Harish Patil <[email protected]>, "Shaikh, Shahed" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>, "Jacob, Jerin" <[email protected]>, "[email protected]" <[email protected]>, "[email protected]" <[email protected]>
Subject: [PATCH v2 39/41] net/qede: use contiguous allocation for DMA memory

Quoted 14 lines

---

Notes:
Doing "grep -R rte_memzone_reserve drivers/net/qede" returns the
following:

drivers/net/qede/qede_fdir.c: mz =
rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
drivers/net/qede/base/bcm_osal.c: mz =
rte_memzone_reserve_aligned_contig(mz_name, size,
drivers/net/qede/base/bcm_osal.c: mz =
rte_memzone_reserve_aligned_contig(mz_name, size, socket_id, 0,

Quoted 3 lines

I took a brief look at memzone in qede_fdir and it didn't look like
memzone
was used for DMA, so i left it alone. Corrections welcome.

That’s right.

Quoted 28 lines

drivers/net/qede/base/bcm_osal.c | 5 +++--

1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/qede/base/bcm_osal.c +3 -2
index fe42f32..707d553 100644
@@ -135,7 +135,7 @@ void *osal_dma_alloc_coherent(struct ecore_dev *p_dev,
 	if (core_id == (unsigned int)LCORE_ID_ANY)
 		core_id = 0;
 	socket_id = rte_lcore_to_socket_id(core_id);
-	mz = rte_memzone_reserve_aligned(mz_name, size,
+	mz = rte_memzone_reserve_aligned_contig(mz_name, size,
 					 socket_id, 0, RTE_CACHE_LINE_SIZE);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
@@ -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 = 0;
 	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_contig(mz_name, size, socket_id, 0,
+			align);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
Quoted 3 lines
		       "of size %zu bytes - %s\n",
Signature · 1 line
2.7.4
Quoted 1 line
#121 lore raw

PATCH v2 40/41 net/virtio: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
Not sure if virtio needs to allocate DMA-capable memory, being a software driver and all. Corrections welcome.

 drivers/net/virtio/virtio_ethdev.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/virtio/virtio_ethdev.c +4 -4
index 884f74a..35812e4 100644
@@ -391,7 +391,7 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
 	PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d",
 		     size, vq->vq_ring_size);
 
-	mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
+	mz = rte_memzone_reserve_aligned_contig(vq_name, vq->vq_ring_size,
 					 SOCKET_ID_ANY,
 					 0, VIRTIO_PCI_VRING_ALIGN);
 	if (mz == NULL) {
@@ -417,9 +417,9 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
 	if (sz_hdr_mz) {
 		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);
+		hdr_mz = rte_memzone_reserve_aligned_contig(vq_hdr_name,
+				sz_hdr_mz, SOCKET_ID_ANY, 0,
+				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
Reviewed-by on v2 40/41
#122 lore raw

Re: [PATCH v2 40/41] net/virtio: use contiguous allocation for DMA memory

Hi Anatoly,

Quoted 7 lines · Anatoly Burakov

---

Notes:
Not sure if virtio needs to allocate DMA-capable memory, being a software driver and all. Corrections welcome.

Yes, we need the ring memory to be contiguous in physical address space.

Quoted 2 lines
  drivers/net/virtio/virtio_ethdev.c | 8 ++++----
  1 file changed, 4 insertions(+), 4 deletions(-)

So:

Thanks,
Maxime

#123 lore raw

PATCH v2 41/41 net/vmxnet3: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
Not sure if DMA-capable memzones are needed for vmxnet3. Corrections welcome.

 drivers/net/vmxnet3/vmxnet3_ethdev.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/net/vmxnet3/vmxnet3_ethdev.c +4 -3
index 4e68aae..c787379 100644
@@ -150,14 +150,15 @@ gpa_zone_reserve(struct rte_eth_dev *dev, uint32_t size,
 	if (!reuse) {
 		if (mz)
 			rte_memzone_free(mz);
-		return rte_memzone_reserve_aligned(z_name, size, socket_id,
-						   0, align);
+		return rte_memzone_reserve_aligned_contig(z_name, size,
+				socket_id, 0, align);
 	}
 
 	if (mz)
 		return mz;
 
-	return rte_memzone_reserve_aligned(z_name, size, socket_id, 0, align);
+	return rte_memzone_reserve_aligned_contig(z_name, size, socket_id, 0,
+			align);
 }
 
 /**
Signature · 1 line
2.7.4
#124 lore raw
In reply to Anatoly Burakov

Hi Anatoly,

I am trying to verify this patchset and have encountered few issues.

Few -Werror=maybe-uninitialized errors in eal_memalloc.c/eal_memory.c/ eal_common_memzone.c files.

lib/librte_eal/common/eal_common_memzone.c +1 -1
index a7cfdaf03..ad4413507 100644
@@ -321,7 +321,7 @@ rte_memzone_free(const struct rte_memzone *mz)
        struct rte_fbarray *arr;
        struct rte_memzone *found_mz;
        int ret = 0;
-       void *addr;
+       void *addr = NULL;
        unsigned idx;
 
        if (mz == NULL)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +1 -1
index 1008faed6..32b0d5133 100644
@@ -570,7 +570,7 @@ eal_memalloc_alloc_page_bulk(struct rte_memseg **ms, int n,
        unsigned int msl_idx;
        int cur_idx, start_idx, end_idx, i, j, ret = -1;
 #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
-       bool have_numa;
+       bool have_numa = false;
        int oldpolicy;
        struct bitmask *oldmask = numa_allocate_nodemask();
 #endif
lib/librte_eal/linuxapp/eal/eal_memory.c +2 -2
index f74291fb6..d37b4a59b 100644
@@ -1386,9 +1386,9 @@ eal_legacy_hugepage_attach(void)
        struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
        struct hugepage_file *hp = NULL;
        unsigned int num_hp = 0;
-       unsigned int i;
+       unsigned int i = 0;
        int ms_idx, msl_idx;
-       unsigned int cur_seg, max_seg;
+       unsigned int cur_seg, max_seg = 0;
        off_t size = 0;
        int fd, fd_hugepage = -1;
 

@Hemanth
Also, this patchset breaks dpaa/dpaa2 bus drivers (they rely on rte_eal_get_physmem_layout that is depricated
http://dpdk.org/dev/patchwork/patch/34002/)
So, generic arm64 linuxapp build is broken.

Regards,
Pavan.

Quoted 9 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

<snip>
--

Quoted 1 line

2.7.4

#125 lore raw
Quoted 6 lines · Pavan Nikhilesh

Hi Anatoly,

I am trying to verify this patchset and have encountered few issues.

Few -Werror=maybe-uninitialized errors in eal_memalloc.c/eal_memory.c/ eal_common_memzone.c files.

Thanks for the heads up, i'll fix those in the next revision. Out of curiousity, which compiler version are you using?

Quoted 45 lines
lib/librte_eal/common/eal_common_memzone.c +1 -1
index a7cfdaf03..ad4413507 100644
@@ -321,7 +321,7 @@ rte_memzone_free(const struct rte_memzone *mz)
         struct rte_fbarray *arr;
         struct rte_memzone *found_mz;
         int ret = 0;
-       void *addr;
+       void *addr = NULL;
         unsigned idx;
 
         if (mz == NULL)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +1 -1
index 1008faed6..32b0d5133 100644
@@ -570,7 +570,7 @@ eal_memalloc_alloc_page_bulk(struct rte_memseg **ms, int n,
         unsigned int msl_idx;
         int cur_idx, start_idx, end_idx, i, j, ret = -1;
  #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
-       bool have_numa;
+       bool have_numa = false;
         int oldpolicy;
         struct bitmask *oldmask = numa_allocate_nodemask();
  #endif
lib/librte_eal/linuxapp/eal/eal_memory.c +2 -2
index f74291fb6..d37b4a59b 100644
@@ -1386,9 +1386,9 @@ eal_legacy_hugepage_attach(void)
         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
         struct hugepage_file *hp = NULL;
         unsigned int num_hp = 0;
-       unsigned int i;
+       unsigned int i = 0;
         int ms_idx, msl_idx;
-       unsigned int cur_seg, max_seg;
+       unsigned int cur_seg, max_seg = 0;
         off_t size = 0;
         int fd, fd_hugepage = -1;
 
Quoted 5 lines

@Hemanth
Also, this patchset breaks dpaa/dpaa2 bus drivers (they rely on rte_eal_get_physmem_layout that is depricated
http://dpdk.org/dev/patchwork/patch/34002/)
So, generic arm64 linuxapp build is broken.

Should the deprecation notice have been accompanied with marking that function as __rte_deprecated?

Quoted 18 lines

Regards,
Pavan.

Quoted 9 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

<snip>
--

Quoted 1 line

2.7.4

Signature · 2 lines
Thanks,
Anatoly
#126 lore raw
Quoted 10 lines · Anatoly
Quoted 6 lines · Pavan Nikhilesh

Hi Anatoly,

I am trying to verify this patchset and have encountered few issues.

Few -Werror=maybe-uninitialized errors in eal_memalloc.c/eal_memory.c/ eal_common_memzone.c files.

Thanks for the heads up, i'll fix those in the next revision. Out of curiousity, which compiler version are you using?

I'm using gcc 5.3.0.

Quoted 46 lines
Quoted 46 lines
lib/librte_eal/common/eal_common_memzone.c +1 -1
index a7cfdaf03..ad4413507 100644
@@ -321,7 +321,7 @@ rte_memzone_free(const struct rte_memzone *mz)
         struct rte_fbarray *arr;
         struct rte_memzone *found_mz;
         int ret = 0;
-       void *addr;
+       void *addr = NULL;
         unsigned idx;
 
         if (mz == NULL)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +1 -1
index 1008faed6..32b0d5133 100644
@@ -570,7 +570,7 @@ eal_memalloc_alloc_page_bulk(struct rte_memseg **ms, int n,
         unsigned int msl_idx;
         int cur_idx, start_idx, end_idx, i, j, ret = -1;
  #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
-       bool have_numa;
+       bool have_numa = false;
         int oldpolicy;
         struct bitmask *oldmask = numa_allocate_nodemask();
  #endif
lib/librte_eal/linuxapp/eal/eal_memory.c +2 -2
index f74291fb6..d37b4a59b 100644
@@ -1386,9 +1386,9 @@ eal_legacy_hugepage_attach(void)
         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
         struct hugepage_file *hp = NULL;
         unsigned int num_hp = 0;
-       unsigned int i;
+       unsigned int i = 0;
         int ms_idx, msl_idx;
-       unsigned int cur_seg, max_seg;
+       unsigned int cur_seg, max_seg = 0;
         off_t size = 0;
         int fd, fd_hugepage = -1;
 
Quoted 8 lines
Quoted 5 lines

@Hemanth
Also, this patchset breaks dpaa/dpaa2 bus drivers (they rely on rte_eal_get_physmem_layout that is depricated
http://dpdk.org/dev/patchwork/patch/34002/)
So, generic arm64 linuxapp build is broken.

Should the deprecation notice have been accompanied with marking that function as __rte_deprecated?

Yup that's the general sequence.

Quoted 24 lines
Quoted 9 lines

Regards,
Pavan.

Quoted 3 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Quoted 10 lines
Quoted 6 lines

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

<snip>
--

Quoted 1 line

2.7.4

--
Thanks,
Anatoly

#127 lore raw

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform. The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL: VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument)
EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized

Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt

#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967
#1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988
#2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240
#3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177
#4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247
#5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327
#6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455
#7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491
#8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527
#9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54

#10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72 #11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81 #12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99 #13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81
#14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959
#15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop because rte_fbarray_find_next_used always return 0.

HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt

#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248
#1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700
#2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499
#4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601
#5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164
#7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249
#8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98

#10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Am I missing something here?

Thanks,
Pavan.

Quoted 95 lines · Pavan Nikhilesh
Quoted 10 lines · Anatoly
Quoted 6 lines · Pavan Nikhilesh

Hi Anatoly,

I am trying to verify this patchset and have encountered few issues.

Few -Werror=maybe-uninitialized errors in eal_memalloc.c/eal_memory.c/ eal_common_memzone.c files.

Thanks for the heads up, i'll fix those in the next revision. Out of curiousity, which compiler version are you using?

I'm using gcc 5.3.0.

Quoted 46 lines
Quoted 46 lines
lib/librte_eal/common/eal_common_memzone.c +1 -1
index a7cfdaf03..ad4413507 100644
@@ -321,7 +321,7 @@ rte_memzone_free(const struct rte_memzone *mz)
         struct rte_fbarray *arr;
         struct rte_memzone *found_mz;
         int ret = 0;
-       void *addr;
+       void *addr = NULL;
         unsigned idx;
 
         if (mz == NULL)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +1 -1
index 1008faed6..32b0d5133 100644
@@ -570,7 +570,7 @@ eal_memalloc_alloc_page_bulk(struct rte_memseg **ms, int n,
         unsigned int msl_idx;
         int cur_idx, start_idx, end_idx, i, j, ret = -1;
  #ifdef RTE_EAL_NUMA_AWARE_HUGEPAGES
-       bool have_numa;
+       bool have_numa = false;
         int oldpolicy;
         struct bitmask *oldmask = numa_allocate_nodemask();
  #endif
lib/librte_eal/linuxapp/eal/eal_memory.c +2 -2
index f74291fb6..d37b4a59b 100644
@@ -1386,9 +1386,9 @@ eal_legacy_hugepage_attach(void)
         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
         struct hugepage_file *hp = NULL;
         unsigned int num_hp = 0;
-       unsigned int i;
+       unsigned int i = 0;
         int ms_idx, msl_idx;
-       unsigned int cur_seg, max_seg;
+       unsigned int cur_seg, max_seg = 0;
         off_t size = 0;
         int fd, fd_hugepage = -1;
 
Quoted 8 lines
Quoted 5 lines

@Hemanth
Also, this patchset breaks dpaa/dpaa2 bus drivers (they rely on rte_eal_get_physmem_layout that is depricated
http://dpdk.org/dev/patchwork/patch/34002/)
So, generic arm64 linuxapp build is broken.

Should the deprecation notice have been accompanied with marking that function as __rte_deprecated?

Yup that's the general sequence.

Quoted 24 lines
Quoted 9 lines

Regards,
Pavan.

Quoted 3 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Quoted 10 lines
Quoted 6 lines

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

<snip>
--

Quoted 1 line

2.7.4

--
Thanks,
Anatoly

#128 lore raw
Quoted 77 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform. The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL: VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument)
EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized

Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt

#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967
#1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988
#2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240
#3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177
#4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247
#5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327
#6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455
#7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491
#8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527
#9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54

#10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72 #11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81 #12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99 #13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81
#14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959
#15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop because rte_fbarray_find_next_used always return
0. >

HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt

#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248
#1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700
#2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499
#4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601
#5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164
#7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249
#8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98
Quoted 4 lines

#10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

Signature · 2 lines
Thanks,
Anatoly
#129 lore raw
Quoted 87 lines · Anatoly
Quoted 80 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform. The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument)
EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt
#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967
#1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988
#2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240
#3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177 #4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247 #5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327 #6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455 #7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491 #8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527 #9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54
#10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72
#11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81
#12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99
#13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81
#14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959
#15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop  because rte_fbarray_find_next_used always return
0. >
HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt
#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248
#1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700 #2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499 #4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601
#5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164 #7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249
#8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98
#10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Quoted 1 line

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

Quoted 8 lines

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

I've looked into the failures.

The VFIO one is not actually a failure. It only prints out errors because rte_malloc is called before VFIO is initialized. However, once VFIO *is* initialized, all of that memory would be added to VFIO, so these error messages are harmless. Regardless, i've added a check to see if init is finished before printing out those errors, so they won't be printed out any more.

Second one is a typo on my part that got lost in one of the rebases.

I've pushed fixes for both into the github repo.

Signature · 2 lines
Thanks,
Anatoly
#130 lore raw
Quoted 97 lines · Anatoly
Quoted 87 lines · Anatoly
Quoted 80 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform. The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument)
EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt
#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967
#1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988
#2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240
#3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177 #4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247 #5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327 #6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455 #7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491 #8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527 #9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54
#10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72
#11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81
#12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99
#13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81
#14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959
#15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop  because rte_fbarray_find_next_used always return
0. >
HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt
#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248
#1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700 #2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499 #4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601
#5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164 #7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249
#8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98
#10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Quoted 1 line

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

Quoted 8 lines

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

Quoted 8 lines

I've looked into the failures.

The VFIO one is not actually a failure. It only prints out errors because rte_malloc is called before VFIO is initialized. However, once VFIO *is* initialized, all of that memory would be added to VFIO, so these error messages are harmless. Regardless, i've added a check to see if init is finished before printing out those errors, so they won't be printed out any more.

Second one is a typo on my part that got lost in one of the rebases.

I've pushed fixes for both into the github repo.

Although i do wonder where do the DMA remapping errors come from. The error message says "invalid argument", so that doesn't come from rte_service or anything to do with rte_malloc - this is us not providing valid arguments to VFIO. I'm not seeing these errors on my system. I'll check on others to be sure.

Signature · 2 lines
Thanks,
Anatoly
#131 lore raw
Quoted 170 lines · Anatoly
Quoted 169 lines · Anatoly
Quoted 151 lines · Anatoly
Quoted 136 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform.
The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument) EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt
#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967 #1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988 #2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240 #3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177 #4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247 #5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327 #6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455 #7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491 #8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527 #9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54 #10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72 #11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81 #12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99 #13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81 #14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959 #15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop  because rte_fbarray_find_next_used always return
0. >
HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt
#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248 #1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700 #2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499 #4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601 #5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164
#7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249 #8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98 #10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Quoted 1 line

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

Quoted 5 lines

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

I've looked into the failures.

The VFIO one is not actually a failure. It only prints out errors because rte_malloc is called before VFIO is initialized. However, once VFIO *is* initialized, all of that memory would be added to VFIO, so these error messages are harmless. Regardless, i've added a check to see if init is finished before printing out those errors, so they won't be printed out any more.

Second one is a typo on my part that got lost in one of the rebases.

Quoted 8 lines
Quoted 2 lines

I've pushed fixes for both into the github repo.

Although i do wonder where do the DMA remapping errors come from. The error message says "invalid argument", so that doesn't come from rte_service or anything to do with rte_malloc - this is us not providing valid arguments to VFIO. I'm not seeing these errors on my system. I'll check on others to be sure.

I have taken a look at the github tree the issues with VFIO are gone, Although compilation issues with dpaa/dpaa2 are still present due to their dependency on rte_eal_get_physmem_layout.

Quoted 4 lines

--
Thanks,
Anatoly

Thanks,
Pavan

#132 lore raw
Quoted 180 lines · Pavan Nikhilesh
Quoted 170 lines · Anatoly
Quoted 169 lines · Anatoly
Quoted 151 lines · Anatoly
Quoted 136 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform.
The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument) EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt
#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967 #1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988 #2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240 #3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177 #4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247 #5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327 #6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455 #7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491 #8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527 #9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54 #10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72 #11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81 #12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99 #13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81 #14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959 #15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop  because rte_fbarray_find_next_used always return
0. >
HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt
#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248 #1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700 #2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499 #4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601 #5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164
#7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249 #8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98 #10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Quoted 1 line

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

Quoted 5 lines

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

I've looked into the failures.

The VFIO one is not actually a failure. It only prints out errors because rte_malloc is called before VFIO is initialized. However, once VFIO *is* initialized, all of that memory would be added to VFIO, so these error messages are harmless. Regardless, i've added a check to see if init is finished before printing out those errors, so they won't be printed out any more.

Second one is a typo on my part that got lost in one of the rebases.

Quoted 8 lines
Quoted 2 lines

I've pushed fixes for both into the github repo.

Although i do wonder where do the DMA remapping errors come from. The error message says "invalid argument", so that doesn't come from rte_service or anything to do with rte_malloc - this is us not providing valid arguments to VFIO. I'm not seeing these errors on my system. I'll check on others to be sure.

Quoted 3 lines

I have taken a look at the github tree the issues with VFIO are gone, Although compilation issues with dpaa/dpaa2 are still present due to their dependency on rte_eal_get_physmem_layout.

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Also, you might want to know that dpaa bus driver references RTE_LIBRTE_DPAA_MAX_CRYPTODEV which is only found in config/common_armv8a_linuxapp but is not present in base config. Not sure if that's an issue.

Quoted 9 lines
Quoted 5 lines

--
Thanks,
Anatoly

Thanks,
Pavan

Signature · 2 lines
Thanks,
Anatoly
#133 lore raw
Quoted 185 lines · Anatoly
Quoted 180 lines · Pavan Nikhilesh
Quoted 170 lines · Anatoly
Quoted 169 lines · Anatoly
Quoted 151 lines · Anatoly
Quoted 136 lines · Pavan Nikhilesh

Hi Anatoly,

We are currently facing issues with running testpmd on thunderx platform.
The issue seems to be with vfio

EAL: Detected 24 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: No free hugepages reported in hugepages-2048kB
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   VFIO support not initialized

<snip>

EAL:   probe driver: 177d:a053 octeontx_fpavf
EAL: PCI device 0001:01:00.1 on NUMA socket 0
EAL:   probe driver: 177d:a034 net_thunderx
EAL:   using IOMMU type 1 (Type 1)
EAL:   cannot set up DMA remapping, error 22 (Invalid argument) EAL:   0001:01:00.1 DMA remapping failed, error 22 (Invalid argument)
EAL: Requested device 0001:01:00.1 cannot be used
EAL: PCI device 0001:01:00.2 on NUMA socket 0
<snip>
testpmd: No probed ethernet devices
testpmd: create a new mbuf pool <mbuf_pool_socket_0>: n=251456, size=2176, socket=0
testpmd: preferred mempool ops selected: ring_mp_mc
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
EAL:   VFIO support not initialized
Done

This is because rte_service_init() calls rte_calloc() before rte_bus_probe() and vfio_dma_mem_map fails because iommu type is not set.

Call stack:
gdb) bt
#0  vfio_dma_mem_map (vaddr=281439006359552, iova=11274289152, len=536870912, do_map=1) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:967 #1  0x00000000004fd974 in rte_vfio_dma_map (vaddr=281439006359552, iova=11274289152, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:988 #2  0x00000000004fbe78 in vfio_mem_event_callback (type=RTE_MEM_EVENT_ALLOC, addr=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal_vfio.c:240 #3  0x00000000005070ac in eal_memalloc_notify (event=RTE_MEM_EVENT_ALLOC, start=0xfff7a0000000, len=536870912) at /root/clean/dpdk/lib/librte_eal/common/eal_common_memalloc.c:177 #4  0x0000000000515c98 in try_expand_heap_primary (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:247 #5  0x0000000000515e94 in try_expand_heap (heap=0xffffb7fb167c, pg_sz=536870912, elt_size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:327 #6  0x00000000005163a0 in alloc_more_mem_on_socket (heap=0xffffb7fb167c, size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:455 #7  0x0000000000516514 in heap_alloc_on_socket (type=0x85bf90 "rte_services", size=8192, socket=0, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:491 #8  0x0000000000516664 in malloc_heap_alloc (type=0x85bf90 "rte_services", size=8192, socket_arg=-1, flags=0, align=128, bound=0, contig=false) at /root/clean/dpdk/lib/librte_eal/common/malloc_heap.c:527 #9  0x0000000000513b54 in rte_malloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket_arg=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:54 #10 0x0000000000513bc8 in rte_zmalloc_socket (type=0x85bf90 "rte_services", size=8192, align=128, socket=-1) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:72 #11 0x0000000000513c00 in rte_zmalloc (type=0x85bf90 "rte_services", size=8192, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:81 #12 0x0000000000513c90 in rte_calloc (type=0x85bf90 "rte_services", num=64, size=128, align=128) at /root/clean/dpdk/lib/librte_eal/common/rte_malloc.c:99 #13 0x0000000000518cec in rte_service_init () at /root/clean/dpdk/lib/librte_eal/common/rte_service.c:81 #14 0x00000000004f55f4 in rte_eal_init (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:959 #15 0x000000000045af5c in main (argc=3, argv=0xfffffffff488) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Also, I have tried running with --legacy-mem but I'm stuck in pci_find_max_end_va loop  because rte_fbarray_find_next_used always return
0. >
HugePages_Total:      15
HugePages_Free:       11
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:     524288 kB

Call Stack:
(gdb) bt
#0  find_next (arr=0xffffb7fb009c, start=0, used=true) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:248 #1  0x00000000005132a8 in rte_fbarray_find_next_used (arr=0xffffb7fb009c, start=0) at /root/clean/dpdk/lib/librte_eal/common/eal_common_fbarray.c:700 #2  0x000000000052d030 in pci_find_max_end_va () at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:138
#3  0x0000000000530ab8 in pci_vfio_map_resource_primary (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:499 #4  0x0000000000530ffc in pci_vfio_map_resource (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci_vfio.c:601 #5  0x000000000052ce90 in rte_pci_map_device (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/linux/pci.c:75
#6  0x0000000000531a20 in rte_pci_probe_one_driver (dr=0x997e20 <rte_nicvf_pmd>, dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:164
#7  0x0000000000531c68 in pci_probe_all_drivers (dev=0xeae700) at /root/clean/dpdk/drivers/bus/pci/pci_common.c:249 #8  0x0000000000531f68 in rte_pci_probe () at /root/clean/dpdk/drivers/bus/pci/pci_common.c:359
#9  0x000000000050a140 in rte_bus_probe () at /root/clean/dpdk/lib/librte_eal/common/eal_common_bus.c:98 #10 0x00000000004f55f4 in rte_eal_init (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/lib/librte_eal/linuxapp/eal/eal.c:967 #11 0x000000000045af5c in main (argc=1, argv=0xfffffffff498) at /root/clean/dpdk/app/test-pmd/testpmd.c:2483

Quoted 1 line

Am I missing something here?

I'll look into those, thanks!

Btw, i've now set up a github repo with the patchset applied:

https://github.com/anatolyburakov/dpdk

I will be pushing quick fixes there before spinning new revisions, so we can discover and fix bugs more rapidly. I'll fix compile issues reported earlier, then i'll take a look at your issues. The latter one seems like a typo, the former is probably a matter of moving things around a bit.

Quoted 5 lines

(also, pull requests welcome if you find it easier to fix things yourself and submit patches against my tree!)

Thanks for testing.

I've looked into the failures.

The VFIO one is not actually a failure. It only prints out errors because rte_malloc is called before VFIO is initialized. However, once VFIO *is* initialized, all of that memory would be added to VFIO, so these error messages are harmless. Regardless, i've added a check to see if init is finished before printing out those errors, so they won't be printed out any more.

Second one is a typo on my part that got lost in one of the rebases.

Quoted 8 lines
Quoted 2 lines

I've pushed fixes for both into the github repo.

Although i do wonder where do the DMA remapping errors come from. The error message says "invalid argument", so that doesn't come from rte_service or anything to do with rte_malloc - this is us not providing valid arguments to VFIO. I'm not seeing these errors on my system. I'll check on others to be sure.

Quoted 3 lines

I have taken a look at the github tree the issues with VFIO are gone, Although compilation issues with dpaa/dpaa2 are still present due to their dependency on rte_eal_get_physmem_layout.

Quoted 8 lines

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Also, you might want to know that dpaa bus driver references RTE_LIBRTE_DPAA_MAX_CRYPTODEV which is only found in config/common_armv8a_linuxapp but is not present in base config. Not sure if that's an issue.

Hi anatoly,

I've checkout your branch on github
commit 61e6876fd1d2 ("remove panic from memalloc")

I am compiling it with clang:
clang version 3.8.1-24 (tags/RELEASE_381/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

There are a lot of compilation errors not present on DPDK branch. They need to be fixed.

Thanks,

Signature · 2 lines
Nélio Laranjeiro
6WIND
#134 lore raw
In reply to Burakov, Anatoly

Hello Anatoly,

Quoted 1 line · Anatoly

On 09-Mar-18 9:15 AM, Pavan Nikhilesh wrote:

[...]

Quoted 9 lines
Quoted 7 lines

I have taken a look at the github tree the issues with VFIO are gone, Although
compilation issues with dpaa/dpaa2 are still present due to their dependency on
rte_eal_get_physmem_layout.

Quoted 3 lines

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Thanks. I will have a look at this.

Quoted 6 lines

Also, you might want to know that dpaa bus driver references RTE_LIBRTE_DPAA_MAX_CRYPTODEV which is only found in config/common_armv8a_linuxapp but is not present in base config. Not sure if that's an issue.

This might be an issue as very recently some patches updated the base config. I will cross check this as well.

-
Shreyansh

#135 lore raw

Hello Anatoly,

Quoted 17 lines · Shreyansh Jain

Hello Anatoly,

Quoted 1 line · Anatoly

On 09-Mar-18 9:15 AM, Pavan Nikhilesh wrote:

[...]

Quoted 9 lines
Quoted 7 lines

I have taken a look at the github tree the issues with VFIO are gone, Although
compilation issues with dpaa/dpaa2 are still present due to their dependency on
rte_eal_get_physmem_layout.

Quoted 5 lines
Quoted 3 lines

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Thanks. I will have a look at this.

Just a heads-up, DPAA2 is broken on top-of-tree (github:
784e041f6b520) as of now:

--->8---
root@ls2088ardb:~/shreyansh/07_dpdk_memory# ./arm64-dpaa2-linuxapp-gcc/app/testpmd -c 0xE -n 1 --log-level=eal,8 --log-level=mem,8 -- -i --portmask=0x3

EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Detected lcore 2 as core 0 on socket 0
EAL: Detected lcore 3 as core 1 on socket 0
EAL: Detected lcore 4 as core 0 on socket 0
EAL: Detected lcore 5 as core 1 on socket 0
EAL: Detected lcore 6 as core 0 on socket 0
EAL: Detected lcore 7 as core 1 on socket 0
EAL: Support maximum 16 logical core(s) by configuration.
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: VFIO PCI modules not loaded
EAL: DPAA Bus not present. Skipping.
EAL: Container: dprc.2 has VFIO iommu group id = 4
EAL: fslmc: Bus scan completed
EAL: Module /sys/module/rte_kni not found! error 2 (No such file or directory)
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL:   IOMMU type 1 (Type 1) is supported
EAL:   IOMMU type 7 (sPAPR) is not supported
EAL:   IOMMU type 8 (No-IOMMU) is not supported
EAL: VFIO support initialized
EAL: Mem event callback 'vfio_mem_event_clb' registered
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffff86cae000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873f000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xfff780000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873e000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffef40000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873d000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffe700000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873c000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffdec0000000 (size = 0x800000000)
EAL: TSC frequency is ~25000 KHz
EAL: Master lcore 1 is ready (tid=88742110;cpuset=[1])
EAL: lcore 3 is ready (tid=85cab910;cpuset=[3])
EAL: lcore 2 is ready (tid=864ab910;cpuset=[2])
EAL: eal_memalloc_alloc_page_bulk(): couldn't find suitable memseg_list

error allocating rte services array
EAL: FATAL: rte_service_init() failed

EAL: rte_service_init() failed

PANIC in main():
Cannot init EAL
1: [./arm64-dpaa2-linuxapp-gcc/app/testpmd(rte_dump_stack+0x38) [0x4f37a8]] Aborted
--->8--

Above is an initial output - still investigating. I will keep you posted.

Quoted 6 lines
Quoted 6 lines

Also, you might want to know that dpaa bus driver references RTE_LIBRTE_DPAA_MAX_CRYPTODEV which is only found in config/common_armv8a_linuxapp but is not present in base config. Not sure if that's an issue.

A recent patch from Hemant has fixed this (yet to be merged in master).

[...]

-
Shreyansh

#136 lore raw

Hello Anatoly,

This is not necessarily right chain to reply to, but reusing this email for another issue in DPAA2 so that all issues can be at a single place.

Quoted 89 lines · Shreyansh Jain

Hello Anatoly,

Quoted 17 lines · Shreyansh Jain

Hello Anatoly,

Quoted 1 line · Anatoly

On 09-Mar-18 9:15 AM, Pavan Nikhilesh wrote:

[...]

Quoted 9 lines
Quoted 7 lines

I have taken a look at the github tree the issues with VFIO are gone, Although
compilation issues with dpaa/dpaa2 are still present due to their dependency on
rte_eal_get_physmem_layout.

Quoted 5 lines
Quoted 3 lines

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Thanks. I will have a look at this.

Just a heads-up, DPAA2 is broken on top-of-tree (github:
784e041f6b520) as of now:

--->8---
root@ls2088ardb:~/shreyansh/07_dpdk_memory# ./arm64-dpaa2-linuxapp-gcc/app/testpmd -c 0xE -n 1 --log-level=eal,8 --log-level=mem,8 -- -i --portmask=0x3

EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Detected lcore 2 as core 0 on socket 0
EAL: Detected lcore 3 as core 1 on socket 0
EAL: Detected lcore 4 as core 0 on socket 0
EAL: Detected lcore 5 as core 1 on socket 0
EAL: Detected lcore 6 as core 0 on socket 0
EAL: Detected lcore 7 as core 1 on socket 0
EAL: Support maximum 16 logical core(s) by configuration.
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: VFIO PCI modules not loaded
EAL: DPAA Bus not present. Skipping.
EAL: Container: dprc.2 has VFIO iommu group id = 4
EAL: fslmc: Bus scan completed
EAL: Module /sys/module/rte_kni not found! error 2 (No such file or directory)
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL:   IOMMU type 1 (Type 1) is supported
EAL:   IOMMU type 7 (sPAPR) is not supported
EAL:   IOMMU type 8 (No-IOMMU) is not supported
EAL: VFIO support initialized
EAL: Mem event callback 'vfio_mem_event_clb' registered
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffff86cae000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873f000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xfff780000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873e000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffef40000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873d000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffe700000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873c000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffdec0000000 (size = 0x800000000)
EAL: TSC frequency is ~25000 KHz
EAL: Master lcore 1 is ready (tid=88742110;cpuset=[1])
EAL: lcore 3 is ready (tid=85cab910;cpuset=[3])
EAL: lcore 2 is ready (tid=864ab910;cpuset=[2])
EAL: eal_memalloc_alloc_page_bulk(): couldn't find suitable memseg_list

error allocating rte services array
EAL: FATAL: rte_service_init() failed

EAL: rte_service_init() failed

Quoted 8 lines

PANIC in main():
Cannot init EAL
1: [./arm64-dpaa2-linuxapp-gcc/app/testpmd(rte_dump_stack+0x38) [0x4f37a8]] Aborted
--->8--

Above is an initial output - still investigating. I will keep you posted.

While working on issue reported in [1], I have found another issue which I might need you help.

[1] http://dpdk.org/ml/archives/dev/2018-March/093202.html

For [1], I bypassed by changing the mempool_add_elem code for time being - it now allows non-contiguous (not explicitly demanded contiguous) allocations to go through rte_mempool_populate_iova. With that, I was able to get DPAA2 working.

Problem is:
1. When I am working with 1GB pages, I/O is working fine.
2. When using 2MB pages (1024 num), the initialization somewhere after VFIO layer fails.

All with IOVA=VA mode.

Some logs:

This is the output of the virtual memory layout demanded by DPDK:

--->8---
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffffb6561000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xffffb6508000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfffbb6400000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfffbb62af000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff7b6200000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff7b6056000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff3b6000000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff3b5dfd000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xffefb5c00000 (size = 0x400000000) --->8---

Then, somehow VFIO mapping is able to find only a single page to map

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Then, these logs appear probably when DPAA2 code requests for memory. I am not sure why it repeats the same '...expanded by 10MB'.

--->8---
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 2MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
LPM or EM none selected, default LPM on
Initializing port 0 ...
--->8---

l3fwd is stuck at this point. What I observe is that DPAA2 driver has gone ahead to register the queues (queue_setup) with hardware and the memory has either overrun (smaller than requested size mapped) or the addresses are corrupt (that is, not dma-able). (I get SMMU faults, indicating one of these cases)

There is some change from you in the fslmc/fslmc_vfio.c file (rte_fslmc_vfio_dmamap()). Ideally, that code should have walked over all the available pages for mapping but that didn't happen and only a single virtual area got dma-mapped.

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

I am looking into this but if there is some hint which come to your mind, it might help.

Regards,
Shreyansh

#137 lore raw
Quoted 205 lines · Shreyansh Jain

Hello Anatoly,

This is not necessarily right chain to reply to, but reusing this email for another issue in DPAA2 so that all issues can be at a single place.

Quoted 89 lines · Shreyansh Jain

Hello Anatoly,

Quoted 17 lines · Shreyansh Jain

Hello Anatoly,

Quoted 1 line · Anatoly

On 09-Mar-18 9:15 AM, Pavan Nikhilesh wrote:

[...]

Quoted 9 lines
Quoted 7 lines

I have taken a look at the github tree the issues with VFIO are gone, Although
compilation issues with dpaa/dpaa2 are still present due to their dependency on
rte_eal_get_physmem_layout.

Quoted 5 lines
Quoted 3 lines

I've fixed the dpaa compile issue and pushed it to github. I've tried to keep the semantics the same as before, but i can't compile-test (let alone test-test) them as i don't have access to a system with dpaa bus.

Thanks. I will have a look at this.

Just a heads-up, DPAA2 is broken on top-of-tree (github:
784e041f6b520) as of now:

--->8---
root@ls2088ardb:~/shreyansh/07_dpdk_memory# ./arm64-dpaa2-linuxapp-gcc/app/testpmd -c 0xE -n 1 --log-level=eal,8 --log-level=mem,8 -- -i --portmask=0x3

EAL: Detected lcore 0 as core 0 on socket 0
EAL: Detected lcore 1 as core 1 on socket 0
EAL: Detected lcore 2 as core 0 on socket 0
EAL: Detected lcore 3 as core 1 on socket 0
EAL: Detected lcore 4 as core 0 on socket 0
EAL: Detected lcore 5 as core 1 on socket 0
EAL: Detected lcore 6 as core 0 on socket 0
EAL: Detected lcore 7 as core 1 on socket 0
EAL: Support maximum 16 logical core(s) by configuration.
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: VFIO PCI modules not loaded
EAL: DPAA Bus not present. Skipping.
EAL: Container: dprc.2 has VFIO iommu group id = 4
EAL: fslmc: Bus scan completed
EAL: Module /sys/module/rte_kni not found! error 2 (No such file or directory)
EAL: Multi-process socket /var/run/.rte_unix
EAL: Probing VFIO support...
EAL:   IOMMU type 1 (Type 1) is supported
EAL:   IOMMU type 7 (sPAPR) is not supported
EAL:   IOMMU type 8 (No-IOMMU) is not supported
EAL: VFIO support initialized
EAL: Mem event callback 'vfio_mem_event_clb' registered
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffff86cae000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873f000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xfff780000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873e000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffef40000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873d000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffe700000000 (size = 0x800000000)
EAL: Ask a virtual area of 0x1000 bytes
EAL: Virtual area found at 0xffff8873c000 (size = 0x1000)
EAL: Memseg list allocated: 0x100000kB at socket 0
EAL: Ask a virtual area of 0x800000000 bytes
EAL: Virtual area found at 0xffdec0000000 (size = 0x800000000)
EAL: TSC frequency is ~25000 KHz
EAL: Master lcore 1 is ready (tid=88742110;cpuset=[1])
EAL: lcore 3 is ready (tid=85cab910;cpuset=[3])
EAL: lcore 2 is ready (tid=864ab910;cpuset=[2])
EAL: eal_memalloc_alloc_page_bulk(): couldn't find suitable memseg_list

error allocating rte services array
EAL: FATAL: rte_service_init() failed

EAL: rte_service_init() failed

Quoted 8 lines

PANIC in main():
Cannot init EAL
1: [./arm64-dpaa2-linuxapp-gcc/app/testpmd(rte_dump_stack+0x38) [0x4f37a8]] Aborted
--->8--

Above is an initial output - still investigating. I will keep you posted.

While working on issue reported in [1], I have found another issue which I might need you help.

[1] http://dpdk.org/ml/archives/dev/2018-March/093202.html

For [1], I bypassed by changing the mempool_add_elem code for time being - it now allows non-contiguous (not explicitly demanded contiguous) allocations to go through rte_mempool_populate_iova. With that, I was able to get DPAA2 working.

Problem is:
1. When I am working with 1GB pages, I/O is working fine.
2. When using 2MB pages (1024 num), the initialization somewhere after VFIO layer fails.

All with IOVA=VA mode.

Some logs:

This is the output of the virtual memory layout demanded by DPDK:

--->8---
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffffb6561000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xffffb6508000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfffbb6400000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfffbb62af000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff7b6200000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff7b6056000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff3b6000000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff3b5dfd000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xffefb5c00000 (size = 0x400000000) --->8---

Then, somehow VFIO mapping is able to find only a single page to map

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Then, these logs appear probably when DPAA2 code requests for memory. I am not sure why it repeats the same '...expanded by 10MB'.

--->8---
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 2MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request: mp_malloc_sync
EAL: Heap on socket 0 was expanded by 10MB
LPM or EM none selected, default LPM on
Initializing port 0 ...
--->8---

l3fwd is stuck at this point. What I observe is that DPAA2 driver has gone ahead to register the queues (queue_setup) with hardware and the memory has either overrun (smaller than requested size mapped) or the addresses are corrupt (that is, not dma-able). (I get SMMU faults, indicating one of these cases)

There is some change from you in the fslmc/fslmc_vfio.c file (rte_fslmc_vfio_dmamap()). Ideally, that code should have walked over all the available pages for mapping but that didn't happen and only a single virtual area got dma-mapped.

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Quoted 6 lines

I am looking into this but if there is some hint which come to your mind, it might help.

Regards,
Shreyansh

Hi Shreyansh,

Thanks for the feedback.

The "heap on socket 0 was expanded by 10MB" has to do with synchronization requests in primary/secondary processes. I can see you're allocating LPM tables - that's most likely what these allocations are about (it's hotplugging memory).

I think i might have an idea what is going on. I am assuming that you are starting up your DPDK application without any -m or --socket-mem flags, which means you are starting with empty heap.

During initialization, certain DPDK features (such as service cores, PMD's) allocate memory. Most likely you have essentially started up with 1 2M page, which is what you see in fslmc logs: this page gets mapped for VFIO.

Then, you allocate a bunch of LPM tables, which trigger more memory allocation, and trigger memory allocation callbacks registered through rte_mem_event_register_callback(). One of these callbacks is a VFIO callback, which is registered in eal_vfio.c:rte_vfio_enable(). However, since fslmc bus has its own VFIO implementation that is independent of what happens in EAL VFIO code, what probably happens is that the fslmc bus misses the necessary messages from the memory hotplug to map additional resources for DMA.

Try adding a rte_mem_event_register_callback() somewhere in fslmc init so that it calls necessary map function. eal_vfio.c:vfio_mem_event_callback() should provide a good template on how to approach creating such a callback. Let me know if this works!

(as a side note, how can we extend VFIO to move this stuff back into EAL and expose it as an API?)

Signature · 2 lines
Thanks,
Anatoly
#138 lore raw

Hello Anatoly,

Quoted 7 lines

-----Original Message-----
From: Burakov, Anatoly [mailto:[email protected]]
Sent: Wednesday, March 21, 2018 8:18 PM
To: Shreyansh Jain <[email protected]>
Cc: [email protected]; Hemant Agrawal <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v2 00/41] Memory Hotplug for DPDK

[...]

Quoted 124 lines
Quoted 6 lines
Quoted 1 line

While working on issue reported in [1], I have found another issue which I might need you help.

[1]

https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdpdk.o
rg%2Fml%2Farchives%2Fdev%2F2018- March%2F093202.html&data=02%7C01%7Cshreyansh.jain%40nxp.com%7C5faee716e6 fc4908bdb608d58f3ad1e5%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6365 72405182868376&sdata=WohDdktHHAuNDnss1atuixSa%2FqC7HRMSDVCtFC9Vnto%3D&re served=0

Quoted 52 lines

For [1], I bypassed by changing the mempool_add_elem code for time being - it now allows non-contiguous (not explicitly demanded contiguous) allocations to go through rte_mempool_populate_iova. With that, I was able to get DPAA2 working.

Problem is:
1. When I am working with 1GB pages, I/O is working fine.
2. When using 2MB pages (1024 num), the initialization somewhere after VFIO layer fails.

All with IOVA=VA mode.

Some logs:

This is the output of the virtual memory layout demanded by DPDK:

--->8---
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffffb6561000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xffffb6508000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfffbb6400000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfffbb62af000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff7b6200000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff7b6056000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff3b6000000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff3b5dfd000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xffefb5c00000 (size = 0x400000000) --->8---

Then, somehow VFIO mapping is able to find only a single page to map

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Quoted 5 lines

Then, these logs appear probably when DPAA2 code requests for memory. I am not sure why it repeats the same '...expanded by 10MB'.

--->8---
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 2MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 23 lines

EAL: Heap on socket 0 was expanded by 10MB
LPM or EM none selected, default LPM on
Initializing port 0 ...
--->8---

l3fwd is stuck at this point. What I observe is that DPAA2 driver has gone ahead to register the queues (queue_setup) with hardware and the memory has either overrun (smaller than requested size mapped) or the addresses are corrupt (that is, not dma-able). (I get SMMU faults, indicating one of these cases)

There is some change from you in the fslmc/fslmc_vfio.c file (rte_fslmc_vfio_dmamap()). Ideally, that code should have walked over all the available pages for mapping but that didn't happen and only a single virtual area got dma-mapped.

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Quoted 6 lines

I am looking into this but if there is some hint which come to your mind, it might help.

Regards,
Shreyansh

Quoted 8 lines

Hi Shreyansh,

Thanks for the feedback.

The "heap on socket 0 was expanded by 10MB" has to do with synchronization requests in primary/secondary processes. I can see you're allocating LPM tables - that's most likely what these allocations are about (it's hotplugging memory).

I get that but why same message multiple times without any change in the expansion. Further, I don't have multiple process - in fact, I'm working with a single datapath thread. Anyways, I will look through the code for this.

Quoted 4 lines

I think i might have an idea what is going on. I am assuming that you are starting up your DPDK application without any -m or --socket-mem flags, which means you are starting with empty heap.

Yes, no specific --socket-mem passed as argument.

Quoted 5 lines

During initialization, certain DPDK features (such as service cores, PMD's) allocate memory. Most likely you have essentially started up with 1 2M page, which is what you see in fslmc logs: this page gets mapped for VFIO.

Agree.

Quoted 9 lines

Then, you allocate a bunch of LPM tables, which trigger more memory allocation, and trigger memory allocation callbacks registered through rte_mem_event_register_callback(). One of these callbacks is a VFIO callback, which is registered in eal_vfio.c:rte_vfio_enable(). However, since fslmc bus has its own VFIO implementation that is independent of what happens in EAL VFIO code, what probably happens is that the fslmc bus misses the necessary messages from the memory hotplug to map additional resources for DMA.

Makes sense

Quoted 5 lines

Try adding a rte_mem_event_register_callback() somewhere in fslmc init so that it calls necessary map function. eal_vfio.c:vfio_mem_event_callback() should provide a good template on how to approach creating such a callback. Let me know if this works!

OK. I will give this a try and update you.

Quoted 3 lines

(as a side note, how can we extend VFIO to move this stuff back into EAL and expose it as an API?)

The problem is that FSLMC VFIO driver is slightly different from generic VFIO layer in the sense that device in a VFIO container is actually another level of container. Anyways, I will have a look how much generalization is possible. Or else, I will work with the vfio_mem_event_callback() as suggested above.

Thanks for suggestions.

Quoted 4 lines

--
Thanks,
Anatoly

#139 lore raw
Quoted 140 lines · Shreyansh Jain

Hello Anatoly,

Quoted 7 lines

-----Original Message-----
From: Burakov, Anatoly [mailto:[email protected]]
Sent: Wednesday, March 21, 2018 8:18 PM
To: Shreyansh Jain <[email protected]>
Cc: [email protected]; Hemant Agrawal <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v2 00/41] Memory Hotplug for DPDK

[...]

Quoted 128 lines
Quoted 6 lines
Quoted 1 line

While working on issue reported in [1], I have found another issue which I might need you help.

[1]

https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdpdk.o
rg%2Fml%2Farchives%2Fdev%2F2018- March%2F093202.html&data=02%7C01%7Cshreyansh.jain%40nxp.com%7C5faee716e6 fc4908bdb608d58f3ad1e5%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6365 72405182868376&sdata=WohDdktHHAuNDnss1atuixSa%2FqC7HRMSDVCtFC9Vnto%3D&re served=0

Quoted 52 lines

For [1], I bypassed by changing the mempool_add_elem code for time being - it now allows non-contiguous (not explicitly demanded contiguous) allocations to go through rte_mempool_populate_iova. With that, I was able to get DPAA2 working.

Problem is:
1. When I am working with 1GB pages, I/O is working fine.
2. When using 2MB pages (1024 num), the initialization somewhere after VFIO layer fails.

All with IOVA=VA mode.

Some logs:

This is the output of the virtual memory layout demanded by DPDK:

--->8---
EAL: Ask a virtual area of 0x2e000 bytes
EAL: Virtual area found at 0xffffb6561000 (size = 0x2e000)
EAL: Setting up physically contiguous memory...
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xffffb6508000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfffbb6400000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfffbb62af000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff7b6200000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff7b6056000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xfff3b6000000 (size = 0x400000000)
EAL: Ask a virtual area of 0x59000 bytes
EAL: Virtual area found at 0xfff3b5dfd000 (size = 0x59000)
EAL: Memseg list allocated: 0x800kB at socket 0
EAL: Ask a virtual area of 0x400000000 bytes
EAL: Virtual area found at 0xffefb5c00000 (size = 0x400000000) --->8---

Then, somehow VFIO mapping is able to find only a single page to map

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Quoted 5 lines

Then, these logs appear probably when DPAA2 code requests for memory. I am not sure why it repeats the same '...expanded by 10MB'.

--->8---
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 2MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 2 lines

EAL: Heap on socket 0 was expanded by 10MB
EAL: Calling mem event callback vfio_mem_event_clbEAL: request:

mp_malloc_sync

Quoted 23 lines

EAL: Heap on socket 0 was expanded by 10MB
LPM or EM none selected, default LPM on
Initializing port 0 ...
--->8---

l3fwd is stuck at this point. What I observe is that DPAA2 driver has gone ahead to register the queues (queue_setup) with hardware and the memory has either overrun (smaller than requested size mapped) or the addresses are corrupt (that is, not dma-able). (I get SMMU faults, indicating one of these cases)

There is some change from you in the fslmc/fslmc_vfio.c file (rte_fslmc_vfio_dmamap()). Ideally, that code should have walked over all the available pages for mapping but that didn't happen and only a single virtual area got dma-mapped.

--->8---
EAL: Device (dpci.1) abstracted from VFIO
EAL: -->Initial SHM Virtual ADDR FFFBB6400000
EAL: -----> DMA size 0x200000
EAL: Total 1 segments found.
--->8---

Quoted 6 lines

I am looking into this but if there is some hint which come to your mind, it might help.

Regards,
Shreyansh

Hi Shreyansh,

Thanks for the feedback.

Quoted 8 lines
Quoted 4 lines

The "heap on socket 0 was expanded by 10MB" has to do with synchronization requests in primary/secondary processes. I can see you're allocating LPM tables - that's most likely what these allocations are about (it's hotplugging memory).

I get that but why same message multiple times without any change in the expansion. Further, I don't have multiple process - in fact, I'm working with a single datapath thread. Anyways, I will look through the code for this.

Hi Shreyansh,

I've misspoke - this has nothing to do with multiprocess. The "request: mp_malloc_sync" does, but it's an attempt to notify other processes of the allocation - if there are no processes, nothing happens.

However, multiple heap expansions do correspond to multiple allocations. If you allocate an LPM table that takes up 10M of hugepage memory - you expand heap by 10M. If you do it multiple times (e.g. per-NIC?), you do multiple heap expansions. This message will be triggered on every heap expansion.

Quoted 33 lines
Quoted 4 lines

I think i might have an idea what is going on. I am assuming that you are starting up your DPDK application without any -m or --socket-mem flags, which means you are starting with empty heap.

Yes, no specific --socket-mem passed as argument.

Quoted 5 lines

During initialization, certain DPDK features (such as service cores, PMD's) allocate memory. Most likely you have essentially started up with 1 2M page, which is what you see in fslmc logs: this page gets mapped for VFIO.

Agree.

Quoted 9 lines

Then, you allocate a bunch of LPM tables, which trigger more memory allocation, and trigger memory allocation callbacks registered through rte_mem_event_register_callback(). One of these callbacks is a VFIO callback, which is registered in eal_vfio.c:rte_vfio_enable(). However, since fslmc bus has its own VFIO implementation that is independent of what happens in EAL VFIO code, what probably happens is that the fslmc bus misses the necessary messages from the memory hotplug to map additional resources for DMA.

Makes sense

Quoted 5 lines

Try adding a rte_mem_event_register_callback() somewhere in fslmc init so that it calls necessary map function. eal_vfio.c:vfio_mem_event_callback() should provide a good template on how to approach creating such a callback. Let me know if this works!

Quoted 7 lines

OK. I will give this a try and update you.

Quoted 3 lines

(as a side note, how can we extend VFIO to move this stuff back into EAL and expose it as an API?)

The problem is that FSLMC VFIO driver is slightly different from generic VFIO layer in the sense that device in a VFIO container is actually another level of container. Anyways, I will have a look how much generalization is possible. Or else, I will work with the vfio_mem_event_callback() as suggested above.

This can wait :) The callback is probably the proper way to do it right now.

Quoted 7 lines

Thanks for suggestions.

Quoted 4 lines

--
Thanks,
Anatoly

Signature · 2 lines
Thanks,
Anatoly
#140 lore raw
In reply to Anatoly Burakov

Hi Anatoly,

Quoted 46 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [6]
- EAL NUMA node count changes [7]

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
* Integrated Pawel Wodkowski's patch for registering/unregistering memory with VFIO [8]
* Callbacks for registering memory allocations
* 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.

Quoted 3 lines

For v1 and v2, the following limitations are present:
- FreeBSD does not even compile, let alone run
- No 32-bit support

I just read on [email protected] [1] that an early merge to this series is expected. So, would this limitation be fixed before merge? Or, has it already been fixed in github repo?

[1] http://dpdk.org/ml/archives/announce/2018-March/000182.html

[...]

-
Shreyansh

#141 lore raw
Quoted 58 lines · Shreyansh Jain

Hi Anatoly,

Quoted 46 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC bugfixes patchset [2]
- IPC improvements patchset [3]
- IPC asynchronous request API patch [4]
- Function to return number of sockets [5]

Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [6]
- EAL NUMA node count changes [7]

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
* Integrated Pawel Wodkowski's patch for registering/unregistering memory with VFIO [8]
* Callbacks for registering memory allocations
* 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.

Quoted 3 lines

For v1 and v2, the following limitations are present:
- FreeBSD does not even compile, let alone run
- No 32-bit support

I just read on [email protected] [1] that an early merge to this series is expected. So, would this limitation be fixed before merge? Or, has it already been fixed in github repo?

Quoted 7 lines

[1] http://dpdk.org/ml/archives/announce/2018-March/000182.html

[...]

-
Shreyansh

Hi Shreyansh,

It will be fixed before merge, yes. I would expect this code to arrive in Github in the next few days.

Signature · 2 lines
Thanks,
Anatoly
#142 lore raw

Hello Anatoly,

Quoted 10 lines

-----Original Message-----
From: Burakov, Anatoly [mailto:[email protected]]
Sent: Tuesday, March 20, 2018 3:38 PM
To: Shreyansh Jain <[email protected]>
Cc: [email protected]; Thomas Monjalon <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v2 00/41] Memory Hotplug for DPDK

Quoted 2 lines · Shreyansh Jain

Hi Anatoly,

[...]

Quoted 11 lines
Quoted 6 lines

[...]

-
Shreyansh

Hi Shreyansh,

It will be fixed before merge, yes. I would expect this code to arrive in Github in the next few days.

I have been integrating with this patchset for considerable time now - attempting to get it working on dpaa2 and dpaa.

Thanks to your quick responses on IRC, at least the VA part of DPAA2 is functional now.

Unfortunately, I am observing a degradation in performance with the patches.

Compared to | % Impact
master (20526313ba4) |
----------------------------------------------

DPAA2 IOVA=VA (hotplug patch) |  ~ -4.0%
DPAA2 IOVA=VA --legacy-mem    |  ~ -4.5%
DPAA2 (Physical)              |  Pending
DPAA  (Physical)              |  Pending

Theoretically, I agree with the discussion on a similar observation in [1] - but, at least as of writing this, I have no idea why the drop is occurring.

[1] http://dpdk.org/ml/archives/dev/2018-March/093685.html

As a side note - the base for hotplug memory patches and master has some differences (since c06ddf9698e0) - though, I don't see any patch in there which might impact performance. But, it might be good idea to rebase - just to remove that doubt.

I noticed that you have already fixed the issues related to IOVA==PA mapping in your recent code. I haven't had the chance to completely integrate my code against those. I will look through the patches in coming days.

Regards,
Shreyansh

#143 lore raw

v3 cover Memory Hotplug for DPDK

In reply to Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC asynchronous request API patch [2]
- Function to return number of sockets [3]
- EAL IOVA fix [4]

Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [5]
- EAL NUMA node count changes [6]

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 [7]
* 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 v3, the following limitations are present:
- VFIO support is only smoke-tested (but is expected to work), VFIO support with secondary processes is not tested; work is ongoing to validate VFIO for all use cases
- FSLMC bus VFIO code is not yet integrated, work is in progress

For testing, it is recommended to use the GitHub repository [8], as it will have all of the dependencies already integrated.

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/IPC_Async_Request/
[3] http://dpdk.org/dev/patchwork/bundle/aburakov/Num_Sockets/
[4] http://dpdk.org/dev/patchwork/bundle/aburakov/IOVA_mode_fixes/
[5] http://dpdk.org/dev/patchwork/patch/34002/
[6] http://dpdk.org/dev/patchwork/patch/33853/
[7] http://dpdk.org/dev/patchwork/patch/24484/
[8] https://github.com/anatolyburakov/dpdk

Anatoly Burakov (68):
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/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 net/bnxt: 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 net/mlx4: use virt2memseg instead of iteration net/mlx5: use virt2memseg instead of iteration crypto/dpaa_sec: 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
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_vfio.c                    |   80 +-
 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/Makefile                       |    3 +
 drivers/crypto/qat/meson.build                    |    3 +
 drivers/crypto/qat/qat_qp.c                       |   23 +-
 drivers/event/dpaa/Makefile                       |    3 +
 drivers/event/dpaa2/Makefile                      |    3 +
 drivers/mempool/dpaa/Makefile                     |    3 +
 drivers/mempool/dpaa2/Makefile                    |    3 +
 drivers/net/avf/Makefile                          |    3 +
 drivers/net/avf/avf_ethdev.c                      |    2 +-
 drivers/net/bnx2x/Makefile                        |    3 +
 drivers/net/bnx2x/bnx2x.c                         |    2 +-
 drivers/net/bnx2x/bnx2x_rxtx.c                    |    3 +-
 drivers/net/bnxt/Makefile                         |    3 +
 drivers/net/bnxt/bnxt_ethdev.c                    |    6 +-
 drivers/net/bnxt/bnxt_ring.c                      |    3 +-
 drivers/net/bnxt/bnxt_vnic.c                      |    2 +-
 drivers/net/cxgbe/Makefile                        |    3 +
 drivers/net/cxgbe/sge.c                           |    3 +-
 drivers/net/dpaa/Makefile                         |    3 +
 drivers/net/dpaa2/Makefile                        |    3 +
 drivers/net/dpaa2/meson.build                     |    3 +
 drivers/net/ena/Makefile                          |    3 +
 drivers/net/ena/base/ena_plat_dpdk.h              |    7 +-
 drivers/net/ena/ena_ethdev.c                      |   10 +-
 drivers/net/enic/Makefile                         |    3 +
 drivers/net/enic/enic_main.c                      |    4 +-
 drivers/net/i40e/Makefile                         |    3 +
 drivers/net/i40e/i40e_ethdev.c                    |    2 +-
 drivers/net/i40e/i40e_rxtx.c                      |    2 +-
 drivers/net/i40e/meson.build                      |    3 +
 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/octeontx/Makefile                     |    3 +
 drivers/net/qede/Makefile                         |    3 +
 drivers/net/qede/base/bcm_osal.c                  |    5 +-
 drivers/net/virtio/virtio_ethdev.c                |    8 +-
 drivers/net/virtio/virtio_user/vhost_kernel.c     |   83 +-
 drivers/net/vmxnet3/Makefile                      |    3 +
 drivers/net/vmxnet3/vmxnet3_ethdev.c              |    7 +-
 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         |  804 ++++++++++++++-
 lib/librte_eal/common/eal_common_memzone.c        |  274 +++--
 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        |  232 ++++-
 lib/librte_eal/common/include/rte_memzone.h       |  159 ++-
 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            |  491 +++++++--
 lib/librte_eal/linuxapp/eal/eal_vfio.h            |   12 +
 lib/librte_eal/linuxapp/eal/meson.build           |    1 +
 lib/librte_eal/rte_eal_version.map                |   33 +-
 lib/librte_ether/rte_ethdev.c                     |    3 +-
 lib/librte_mempool/Makefile                       |    3 +
 lib/librte_mempool/meson.build                    |    3 +
 lib/librte_mempool/rte_mempool.c                  |  138 ++-
 test/test/commands.c                              |    3 +
 test/test/test_malloc.c                           |   30 +-
 test/test/test_memory.c                           |   27 +-
 test/test/test_memzone.c                          |   62 +-
 104 files changed, 8434 insertions(+), 1263 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
#144 lore raw

PATCH v3 1/68 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
index 852f3bb..5b8ced4 100644
@@ -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
index 0b28770..3fed436 100644
@@ -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
#145 lore raw

PATCH v3 2/68 eal: move all locking to heap

In reply to Anatoly Burakov

Down 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
index 0cadc8a..ea041e2 100644
@@ -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
index 7aafc88..7d8d70a 100644
@@ -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
index e0defa7..ab0005c 100644
@@ -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
index e0e0d0b..970813e 100644
@@ -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
#146 lore raw

PATCH v3 3/68 eal: make malloc heap a doubly-linked list

In reply to Anatoly Burakov

As 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.

---
 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
index ba99ed9..d43fa90 100644
@@ -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
index f4c1c7a..238e451 100644
@@ -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
index 7d8d70a..9c95166 100644
@@ -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
#147 lore raw

Re: [PATCH v3 03/68] eal: make malloc heap a doubly-linked list

Quoted 10 lines · On Wed, 4 Apr 2018 00:21:15 +0100 Anatoly Burakov <[email protected]>…

As 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.

Dummy element at end of heap could be helpful for purify/valgrind style verification that code does not exceed allocation.

#148 lore raw

Re: [PATCH v3 03/68] eal: make malloc heap a doubly-linked list

Quoted 12 lines · Stephen Hemminger
Quoted 9 lines · On Wed, 4 Apr 2018 00:21:15 +0100 Anatoly Burakov <[email protected]>…

As 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.

Quoted 5 lines
Quoted 1 line

Dummy element at end of heap could be helpful for purify/valgrind style verification that code does not exceed allocation.

It would interfere with removing pages from memory :) Dummy element needs to be stored somewhere - if it's stored in a page, that means that page cannot be freed. Moreover, with pages being added/removed dynamically, the dummy element will have to be moved back and forth, so "at the end of the heap" is not a fixed location.

Signature · 2 lines
Thanks,
Anatoly
#149 lore raw

PATCH v3 4/68 eal: add function to dump malloc heap contents

In reply to Anatoly Burakov

Malloc 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
index f02a8ba..a9fb7e4 100644
@@ -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
index eb41200..e02ed88 100644
@@ -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
index 238e451..40e8eb5 100644
@@ -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
index 9c95166..44538d7 100644
@@ -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
index ab0005c..bb28422 100644
@@ -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
index 970813e..f11a822 100644
@@ -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
index dd38783..d9fc458 100644
@@ -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
#150 lore raw

PATCH v3 5/68 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
index cf0b726..6bfdc02 100644
@@ -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
#151 lore raw

PATCH v3 6/68 eal: make malloc_elem_join_adjacent_free public

In reply to Anatoly Burakov

We need this function to join newly allocated segments with the heap.

---
 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
index e02ed88..2291ee1 100644
@@ -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
index 40e8eb5..99921d2 100644
@@ -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
#152 lore raw

PATCH v3 7/68 eal: make malloc free list remove public

In reply to Anatoly Burakov
---
 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
index 2291ee1..008f5a3 100644
@@ -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
index 99921d2..46e2383 100644
@@ -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
#153 lore raw

PATCH v3 8/68 eal: make malloc free return resulting malloc element

In reply to Anatoly Burakov

This 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
index 008f5a3..c18f050 100644
@@ -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
index 46e2383..9c1614c 100644
@@ -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
index 44538d7..a2c2e4c 100644
@@ -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
#154 lore raw

PATCH v3 9/68 eal: replace panics with error messages in malloc

In reply to Anatoly Burakov
---
 lib/librte_eal/common/rte_malloc.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
lib/librte_eal/common/rte_malloc.c +5 -3
index f11a822..2cda48e 100644
@@ -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
#155 lore raw

PATCH v3 10/68 eal: add backend support for contiguous allocation

In reply to Anatoly Burakov

No major changes, just add some checks in a few key places, and a new parameter to pass around.

Also, add a dummy 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
index 1ab3ade..16a2e7a 100644
@@ -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
index 9c1614c..34bd268 100644
@@ -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
index a2c2e4c..564b61a 100644
@@ -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
index bb28422..c57b59a 100644
@@ -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
index 2cda48e..436818a 100644
@@ -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
#156 lore raw

PATCH v3 11/68 eal: enable reserving physically contiguous memzones

In reply to Anatoly Burakov

This adds a new set of _contig API's to rte_memzone. For now, hugepage memory is always contiguous, but we need to prepare the drivers for the switch.

---

Notes:
v3:
- Moved this patch earlier

 lib/librte_eal/common/eal_common_memzone.c  |  44 ++++++++
 lib/librte_eal/common/include/rte_memzone.h | 158 ++++++++++++++++++++++++++++
 lib/librte_eal/rte_eal_version.map          |   3 +
 3 files changed, 205 insertions(+)
lib/librte_eal/common/eal_common_memzone.c +44 -0
index 16a2e7a..36d2553 100644
@@ -171,6 +171,12 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
 		socket_id = SOCKET_ID_ANY;
 
 	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 {
@@ -272,6 +278,19 @@ rte_memzone_reserve_bounded(const char *name, size_t len, int socket_id,
 
 /*
  * Return a pointer to a correctly filled memzone descriptor (with a
+ * specified alignment and boundary). If the allocation cannot be done,
+ * return NULL.
+ */
+__rte_experimental const struct rte_memzone *
+rte_memzone_reserve_bounded_contig(const char *name, size_t len, int socket_id,
+		unsigned int flags, unsigned int align, unsigned int bound)
+{
+	return rte_memzone_reserve_thread_safe(name, len, socket_id, flags,
+					       align, bound, true);
+}
+
+/*
+ * Return a pointer to a correctly filled memzone descriptor (with a
  * specified alignment). If the allocation cannot be done, return NULL.
  */
 const struct rte_memzone *
@@ -283,6 +302,18 @@ rte_memzone_reserve_aligned(const char *name, size_t len, int socket_id,
 }
 
 /*
+ * Return a pointer to a correctly filled memzone descriptor (with a
+ * specified alignment). If the allocation cannot be done, return NULL.
+ */
+__rte_experimental const struct rte_memzone *
+rte_memzone_reserve_aligned_contig(const char *name, size_t len, int socket_id,
+		unsigned int flags, unsigned int align)
+{
+	return rte_memzone_reserve_thread_safe(name, len, socket_id, flags,
+					       align, 0, true);
+}
+
+/*
  * Return a pointer to a correctly filled memzone descriptor. If the
  * allocation cannot be done, return NULL.
  */
@@ -295,6 +326,19 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id,
 					       false);
 }
 
+/*
+ * Return a pointer to a correctly filled memzone descriptor. If the
+ * allocation cannot be done, return NULL.
+ */
+__rte_experimental const struct rte_memzone *
+rte_memzone_reserve_contig(const char *name, size_t len, int socket_id,
+		unsigned int flags)
+{
+	return rte_memzone_reserve_thread_safe(name, len, socket_id,
+					       flags, RTE_CACHE_LINE_SIZE, 0,
+					       true);
+}
+
 int
 rte_memzone_free(const struct rte_memzone *mz)
 {
lib/librte_eal/common/include/rte_memzone.h +158 -0

170 lines not on this page · raw message

lib/librte_eal/rte_eal_version.map +3 -0
index d9fc458..25e00de 100644
@@ -223,6 +223,9 @@ EXPERIMENTAL {
 	rte_eal_mbuf_user_pool_ops;
 	rte_log_register_type_and_pick_level;
 	rte_malloc_dump_heaps;
+	rte_memzone_reserve_contig;
+	rte_memzone_reserve_aligned_contig;
+	rte_memzone_reserve_bounded_contig;
 	rte_mp_action_register;
 	rte_mp_action_unregister;
 	rte_mp_reply;
Signature · 1 line
2.7.4
#157 lore raw

Re: [PATCH v3 11/68] eal: enable reserving physically contiguous memzones

Quoted 5 lines · On Wed, 4 Apr 2018 00:21:23 +0100 Anatoly Burakov <[email protected]>…

This adds a new set of _contig API's to rte_memzone. For now, hugepage memory is always contiguous, but we need to prepare the drivers for the switch.

Why not make fragmentation an optional flag to the memzone_reserved rather than a new API. That way less drivers need to be changed.

#define RTE_MEMZONE_SPARSE 0x00100000 /* Allow zone to be non-contiguous */

#158 lore raw

Re: [PATCH v3 11/68] eal: enable reserving physically contiguous memzones

Quoted 7 lines · Stephen Hemminger
Quoted 4 lines · On Wed, 4 Apr 2018 00:21:23 +0100 Anatoly Burakov <[email protected]>…

This adds a new set of _contig API's to rte_memzone. For now, hugepage memory is always contiguous, but we need to prepare the drivers for the switch.

Quoted 7 lines
Quoted 1 line

Why not make fragmentation an optional flag to the memzone_reserved rather than a new API. That way less drivers need to be changed.

#define RTE_MEMZONE_SPARSE 0x00100000 /* Allow zone to be non-contiguous */

That is a good idea, however, i would perhaps do it the other way around. Most of the time we are reserving memzones, we do not need those to be IOVA-contiguous (i.e. creating rings, hashtables etc.). So it would rather be a RTE_MEMZONE_CONTIG (or some such) flag.

Signature · 2 lines
Thanks,
Anatoly
#159 lore raw

PATCH v3 12/68 ethdev: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

This fixes the following drivers in one go:

grep -Rl rte_eth_dma_zone_reserve drivers/

drivers/net/avf/avf_rxtx.c
drivers/net/thunderx/nicvf_ethdev.c
drivers/net/e1000/igb_rxtx.c
drivers/net/e1000/em_rxtx.c
drivers/net/fm10k/fm10k_ethdev.c
drivers/net/vmxnet3/vmxnet3_rxtx.c
drivers/net/liquidio/lio_rxtx.c
drivers/net/i40e/i40e_rxtx.c
drivers/net/sfc/sfc.c
drivers/net/ixgbe/ixgbe_rxtx.c
drivers/net/nfp/nfp_net.c

---

Notes:
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
index 2c74f7e..10cfa20 100644
@@ -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_contig(z_name, size, socket_id, 0,
+			align);
 }
 
 int
Signature · 1 line
2.7.4
#160 lore raw

PATCH v3 13/68 crypto/qat: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

Also, remove the weird page alignment code.

---

Notes:
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/Makefile    |  3 +++
 drivers/crypto/qat/meson.build |  3 +++
 drivers/crypto/qat/qat_qp.c    | 23 ++---------------------
 3 files changed, 8 insertions(+), 21 deletions(-)
drivers/crypto/qat/Makefile +3 -0
index 260912d..a93fad8 100644
@@ -13,6 +13,9 @@ LIBABIVER := 1
 CFLAGS += $(WERROR_FLAGS)
 CFLAGS += -O3
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 # external library include paths
 CFLAGS += -I$(SRCDIR)/qat_adf
 LDLIBS += -lcrypto
drivers/crypto/qat/meson.build +3 -0
index 7b90463..ff0c239 100644
@@ -12,3 +12,6 @@ includes += include_directories('qat_adf')
 deps += ['bus_pci']
 ext_deps += dep
 pkgconfig_extra_libs += '-lcrypto'
+
+# contig memzone allocation is not yet part of stable API
+allow_experimental_apis = true
drivers/crypto/qat/qat_qp.c +2 -21
index 87b9ce0..2ba28cf 100644
@@ -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_contig(queue_name, queue_size,
+		socket_id, 0, queue_size);
 }
 
 int qat_crypto_sym_qp_setup(struct rte_cryptodev *dev, uint16_t queue_pair_id,
Signature · 1 line
2.7.4
#161 lore raw

PATCH v3 14/68 net/avf: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile

 drivers/net/avf/Makefile     | 3 +++
 drivers/net/avf/avf_ethdev.c | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/net/avf/Makefile +3 -0
index 3f815bb..678d49c 100644
@@ -20,6 +20,9 @@ EXPORT_MAP := rte_pmd_avf_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 #
 # Add extra flags for base driver files (also known as shared code)
 # to disable warnings
drivers/net/avf/avf_ethdev.c +1 -1
index 4442c3c..739ab92 100644
@@ -1365,7 +1365,7 @@ 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,
+	mz = rte_memzone_reserve_bounded_contig(z_name, size, SOCKET_ID_ANY, 0,
 					 alignment, RTE_PGSIZE_2M);
 	if (!mz)
 		return AVF_ERR_NO_MEMORY;
Signature · 1 line
2.7.4
#162 lore raw

PATCH v3 15/68 net/bnx2x: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile

 drivers/net/bnx2x/Makefile     | 3 +++
 drivers/net/bnx2x/bnx2x.c      | 2 +-
 drivers/net/bnx2x/bnx2x_rxtx.c | 3 ++-
 3 files changed, 6 insertions(+), 2 deletions(-)
drivers/net/bnx2x/Makefile +3 -0
index 90ff8b1..d9b3ffd 100644
@@ -17,6 +17,9 @@ EXPORT_MAP := rte_pmd_bnx2x_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
 CFLAGS += -wd188 #188: enumerated type mixed with another type
 endif
drivers/net/bnx2x/bnx2x.c +1 -1
index fb02d0f..81f5dae 100644
@@ -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
index a0d4ac9..325b94d 100644
@@ -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_contig(z_name, ring_size, socket_id,
+			0, BNX2X_PAGE_SIZE);
 }
 
 static void
Signature · 1 line
2.7.4
#163 lore raw

PATCH v3 16/68 net/cxgbe: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the makefile

 drivers/net/cxgbe/Makefile | 3 +++
 drivers/net/cxgbe/sge.c    | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)
drivers/net/cxgbe/Makefile +3 -0
index 8fba1a5..0042f5e 100644
@@ -18,6 +18,9 @@ EXPORT_MAP := rte_pmd_cxgbe_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
 #
 # CFLAGS for icc
drivers/net/cxgbe/sge.c +2 -1
index 83e26d0..0cd3e56 100644
@@ -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_contig(z_name, len, socket_id, 0,
+			4096);
 	if (!tz)
 		return NULL;
 
Signature · 1 line
2.7.4
#164 lore raw

PATCH v3 17/68 net/ena: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API's in the Makefile

 drivers/net/ena/Makefile             | 3 +++
 drivers/net/ena/base/ena_plat_dpdk.h | 7 ++++---
 2 files changed, 7 insertions(+), 3 deletions(-)
drivers/net/ena/Makefile +3 -0
index f9bfe05..01c3823 100644
@@ -43,6 +43,9 @@ INCLUDES :=-I$(SRCDIR) -I$(SRCDIR)/base/ena_defs -I$(SRCDIR)/base
 EXPORT_MAP := rte_pmd_ena_version.map
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 VPATH += $(SRCDIR)/base
 #
 # all source are stored in SRCS-y
drivers/net/ena/base/ena_plat_dpdk.h +4 -3
index 8cba319..c1ebf00 100644
@@ -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_contig(z_name,			\
+				size, SOCKET_ID_ANY, 0);		\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 		phys = mz->iova;					\
@@ -206,7 +207,7 @@ 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_contig(z_name, size, node, 0);	\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 		phys = mz->iova;					\
@@ -219,7 +220,7 @@ 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_contig(z_name, size, node, 0);	\
 		memset(mz->addr, 0, size);				\
 		virt = mz->addr;					\
 	} while (0)
Signature · 1 line
2.7.4
#165 lore raw

PATCH v3 18/68 net/enic: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
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/Makefile    | 3 +++
 drivers/net/enic/enic_main.c | 4 ++--
 2 files changed, 5 insertions(+), 2 deletions(-)
drivers/net/enic/Makefile +3 -0
index 7c6c29c..f117c96 100644
@@ -13,6 +13,9 @@ EXPORT_MAP := rte_pmd_enic_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 CFLAGS += -I$(SRCDIR)/base/
 CFLAGS += -I$(SRCDIR)
 CFLAGS += -O3
drivers/net/enic/enic_main.c +2 -2
index 69ad425..d19033e 100644
@@ -343,7 +343,7 @@ 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,
+	rz = rte_memzone_reserve_aligned_contig((const char *)name,
 					 size, SOCKET_ID_ANY, 0, ENIC_ALIGN);
 	if (!rz) {
 		pr_err("%s : Failed to allocate memory requested for %s\n",
@@ -887,7 +887,7 @@ int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
 		 "vnic_cqmsg-%s-%d-%d", enic->bdf_name, queue_idx,
 		instance++);
 
-	wq->cqmsg_rz = rte_memzone_reserve_aligned((const char *)name,
+	wq->cqmsg_rz = rte_memzone_reserve_aligned_contig((const char *)name,
 						   sizeof(uint32_t),
 						   SOCKET_ID_ANY, 0,
 						   ENIC_ALIGN);
Signature · 1 line
2.7.4
#166 lore raw

PATCH v3 19/68 net/i40e: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in the build system

 drivers/net/i40e/Makefile      | 3 +++
 drivers/net/i40e/i40e_ethdev.c | 2 +-
 drivers/net/i40e/i40e_rxtx.c   | 2 +-
 drivers/net/i40e/meson.build   | 3 +++
 4 files changed, 8 insertions(+), 2 deletions(-)
drivers/net/i40e/Makefile +3 -0
index 5663f5b..bbc33b8 100644
@@ -19,6 +19,9 @@ EXPORT_MAP := rte_pmd_i40e_version.map
 
 LIBABIVER := 2
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 #
 # Add extra flags for base driver files (also known as shared code)
 # to disable warnings
drivers/net/i40e/i40e_ethdev.c +1 -1
index d0bf4e3..6d72726 100644
@@ -4053,7 +4053,7 @@ 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,
+	mz = rte_memzone_reserve_bounded_contig(z_name, size, SOCKET_ID_ANY, 0,
 					 alignment, RTE_PGSIZE_2M);
 	if (!mz)
 		return I40E_ERR_NO_MEMORY;
drivers/net/i40e/i40e_rxtx.c +1 -1
index 1217e5a..6b2b40e 100644
@@ -2189,7 +2189,7 @@ i40e_memzone_reserve(const char *name, uint32_t len, int socket_id)
 	if (mz)
 		return mz;
 
-	mz = rte_memzone_reserve_aligned(name, len,
+	mz = rte_memzone_reserve_aligned_contig(name, len,
 					 socket_id, 0, I40E_RING_BASE_ALIGN);
 	return mz;
 }
drivers/net/i40e/meson.build +3 -0
index 197e611..e418791 100644
@@ -46,3 +46,6 @@ endif
 includes += include_directories('base')
 
 install_headers('rte_pmd_i40e.h')
+
+# contig memzone allocation is not yet part of stable API
+allow_experimental_apis = true
Signature · 1 line
2.7.4
#167 lore raw

PATCH v3 20/68 net/qede: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved the patch earlier in the patchset
- Allowed experimental API in Makefile

 drivers/net/qede/Makefile        | 3 +++
 drivers/net/qede/base/bcm_osal.c | 5 +++--
 2 files changed, 6 insertions(+), 2 deletions(-)
drivers/net/qede/Makefile +3 -0
index ccbffa4..83a4b8c 100644
@@ -21,6 +21,9 @@ EXPORT_MAP := rte_pmd_qede_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 #
 # OS
 #
drivers/net/qede/base/bcm_osal.c +3 -2
index 91017b8..3a0a9aa 100644
@@ -135,7 +135,7 @@ 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,
+	mz = rte_memzone_reserve_aligned_contig(mz_name, size,
 					 socket_id, 0, RTE_CACHE_LINE_SIZE);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
@@ -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_contig(mz_name, size, socket_id, 0,
+			align);
 	if (!mz) {
 		DP_ERR(p_dev, "Unable to allocate DMA memory "
 		       "of size %zu bytes - %s\n",
Signature · 1 line
2.7.4
#168 lore raw

PATCH v3 21/68 net/virtio: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
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
index 2ef213d..bdd5e87 100644
@@ -390,7 +390,7 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
 	PMD_INIT_LOG(DEBUG, "vring_size: %d, rounded_vring_size: %d",
 		     size, vq->vq_ring_size);
 
-	mz = rte_memzone_reserve_aligned(vq_name, vq->vq_ring_size,
+	mz = rte_memzone_reserve_aligned_contig(vq_name, vq->vq_ring_size,
 					 SOCKET_ID_ANY,
 					 0, VIRTIO_PCI_VRING_ALIGN);
 	if (mz == NULL) {
@@ -416,9 +416,9 @@ virtio_init_queue(struct rte_eth_dev *dev, uint16_t vtpci_queue_idx)
 	if (sz_hdr_mz) {
 		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);
+		hdr_mz = rte_memzone_reserve_aligned_contig(vq_hdr_name,
+				sz_hdr_mz, SOCKET_ID_ANY, 0,
+				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
#169 lore raw

PATCH v3 22/68 net/vmxnet3: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
v3:
- Moved patch earlier in the patchset
- Allowed experimental API in Makefile

 drivers/net/vmxnet3/Makefile         | 3 +++
 drivers/net/vmxnet3/vmxnet3_ethdev.c | 7 ++++---
 2 files changed, 7 insertions(+), 3 deletions(-)
drivers/net/vmxnet3/Makefile +3 -0
index 6bfbf01..7f76086 100644
@@ -45,6 +45,9 @@ EXPORT_MAP := rte_pmd_vmxnet3_version.map
 
 LIBABIVER := 1
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 #
 # all source are stored in SRCS-y
 #
drivers/net/vmxnet3/vmxnet3_ethdev.c +4 -3
index 4260087..3f323a0 100644
@@ -149,14 +149,15 @@ gpa_zone_reserve(struct rte_eth_dev *dev, uint32_t size,
 	if (!reuse) {
 		if (mz)
 			rte_memzone_free(mz);
-		return rte_memzone_reserve_aligned(z_name, size, socket_id,
-						   0, align);
+		return rte_memzone_reserve_aligned_contig(z_name, size,
+				socket_id, 0, align);
 	}
 
 	if (mz)
 		return mz;
 
-	return rte_memzone_reserve_aligned(z_name, size, socket_id, 0, align);
+	return rte_memzone_reserve_aligned_contig(z_name, size, socket_id, 0,
+			align);
 }
 
 /*
Signature · 1 line
2.7.4
#170 lore raw

PATCH v3 23/68 net/bnxt: use contiguous allocation for DMA memory

In reply to Anatoly Burakov

---

Notes:
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/Makefile      | 3 +++
 drivers/net/bnxt/bnxt_ethdev.c | 6 ++++--
 drivers/net/bnxt/bnxt_ring.c   | 3 ++-
 drivers/net/bnxt/bnxt_vnic.c   | 2 +-
 4 files changed, 10 insertions(+), 4 deletions(-)
drivers/net/bnxt/Makefile +3 -0
index 2aa0441..b443d29 100644
@@ -42,6 +42,9 @@ EXPORT_MAP := rte_pmd_bnxt_version.map
 
 LIBABIVER := 2
 
+# contiguous memzone reserve API are not yet stable
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
drivers/net/bnxt/bnxt_ethdev.c +4 -2
index 0b21653..5a7143c 100644
@@ -3146,7 +3146,8 @@ bnxt_dev_init(struct rte_eth_dev *eth_dev)
 		total_alloc_len = RTE_CACHE_LINE_ROUNDUP(
 				sizeof(struct rx_port_stats) + 512);
 		if (!mz) {
-			mz = rte_memzone_reserve(mz_name, total_alloc_len,
+			mz = rte_memzone_reserve_contig(mz_name,
+						 total_alloc_len,
 						 SOCKET_ID_ANY,
 						 RTE_MEMZONE_2MB |
 						 RTE_MEMZONE_SIZE_HINT_ONLY);
@@ -3181,7 +3182,8 @@ 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,
+			mz = rte_memzone_reserve_contig(mz_name,
+						 total_alloc_len,
 						 SOCKET_ID_ANY,
 						 RTE_MEMZONE_2MB |
 						 RTE_MEMZONE_SIZE_HINT_ONLY);
drivers/net/bnxt/bnxt_ring.c +2 -1
index 8fb8972..e8127de 100644
@@ -165,7 +165,8 @@ int bnxt_alloc_rings(struct bnxt *bp, uint16_t qidx,
 	mz_name[RTE_MEMZONE_NAMESIZE - 1] = 0;
 	mz = rte_memzone_lookup(mz_name);
 	if (!mz) {
-		mz = rte_memzone_reserve_aligned(mz_name, total_alloc_len,
+		mz = rte_memzone_reserve_aligned_contig(mz_name,
+					 total_alloc_len,
 					 SOCKET_ID_ANY,
 					 RTE_MEMZONE_2MB |
 					 RTE_MEMZONE_SIZE_HINT_ONLY,
drivers/net/bnxt/bnxt_vnic.c +1 -1
index d4aeb4c..611ce66 100644
@@ -184,7 +184,7 @@ int bnxt_alloc_vnic_attributes(struct bnxt *bp)
 	mz_name[RTE_MEMZONE_NAMESIZE - 1] = 0;
 	mz = rte_memzone_lookup(mz_name);
 	if (!mz) {
-		mz = rte_memzone_reserve(mz_name,
+		mz = rte_memzone_reserve_contig(mz_name,
 					 entry_length * max_vnics,
 					 SOCKET_ID_ANY,
 					 RTE_MEMZONE_2MB |
Signature · 1 line
2.7.4
#171 lore raw

PATCH v3 24/68 mempool: add support for the new allocation methods

In reply to Anatoly Burakov

If 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.

Existing mempool size calculation function also doesn't give us expected results, because it will return memzone sizes aligned to page size (e.g. a 1MB mempool will reserve the entire 1GB page if all user has are 1GB pages), so add a new one that will give us results more in line with what we would expect.

---

Notes:
v3:
- Fixed mempool size calculation
- Fixed handling of contiguous memzones
- Moved earlier in the patchset

 lib/librte_mempool/Makefile      |   3 +
 lib/librte_mempool/meson.build   |   3 +
 lib/librte_mempool/rte_mempool.c | 137 ++++++++++++++++++++++++++++++++-------
 3 files changed, 121 insertions(+), 22 deletions(-)
lib/librte_mempool/Makefile +3 -0
index 24e735a..cfc69b4 100644
@@ -13,6 +13,9 @@ EXPORT_MAP := rte_mempool_version.map
 
 LIBABIVER := 3
 
+# uses new contiguous memzone allocation that isn't yet in stable ABI
+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
index 712720f..5916a0f 100644
@@ -5,3 +5,6 @@ version = 3
 sources = files('rte_mempool.c', 'rte_mempool_ops.c')
 headers = files('rte_mempool.h')
 deps += ['ring']
+
+# contig memzone allocation is not yet part of stable API
+allow_experimental_apis = true
lib/librte_mempool/rte_mempool.c +115 -22

196 lines not on this page · raw message

Signature · 1 line
2.7.4
#172 lore raw

PATCH v3 25/68 eal: add function to walk all memsegs

In reply to Anatoly Burakov

For 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
index 5b8ced4..947db1f 100644
@@ -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
index 302f865..93eadaa 100644
@@ -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
index 25e00de..7e9900d 100644
@@ -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_memzone_reserve_contig;
 	rte_memzone_reserve_aligned_contig;
 	rte_memzone_reserve_bounded_contig;
Signature · 1 line
2.7.4
#173 lore raw

PATCH v3 26/68 bus/fslmc: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 drivers/bus/fslmc/fslmc_vfio.c | 78 ++++++++++++++++++++++--------------------
 drivers/event/dpaa2/Makefile   |  3 ++
 drivers/mempool/dpaa2/Makefile |  3 ++
 drivers/net/dpaa2/Makefile     |  3 ++
 drivers/net/dpaa2/meson.build  |  3 ++
 drivers/net/octeontx/Makefile  |  3 ++
 6 files changed, 56 insertions(+), 37 deletions(-)
drivers/bus/fslmc/fslmc_vfio.c +41 -37
index 1310190..ccdbeff 100644
@@ -193,17 +193,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) {
+		FSLMC_VFIO_LOG(ERR, "Container is not connected ");
+		return -1;
+	}
+
+	FSLMC_VFIO_LOG(DEBUG, "-->Initial SHM Virtual ADDR %llX",
+		     dma_map.vaddr);
+	FSLMC_VFIO_LOG(DEBUG, "-----> DMA size 0x%llX", dma_map.size);
+	ret = ioctl(group->container->fd, VFIO_IOMMU_MAP_DMA,
+			&dma_map);
+	if (ret) {
+		FSLMC_VFIO_LOG(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;
@@ -214,51 +248,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) {
-			FSLMC_VFIO_LOG(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) {
-			FSLMC_VFIO_LOG(ERR, "Container is not connected ");
-			return -1;
-		}
-
-		FSLMC_VFIO_LOG(DEBUG, "-->Initial SHM Virtual ADDR %llX",
-			     dma_map.vaddr);
-		FSLMC_VFIO_LOG(DEBUG, "-----> DMA size 0x%llX", dma_map.size);
-		ret = ioctl(group->container->fd, VFIO_IOMMU_MAP_DMA,
-			    &dma_map);
-		if (ret) {
-			FSLMC_VFIO_LOG(ERR, "VFIO_IOMMU_MAP_DMA API(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) {
 		FSLMC_VFIO_LOG(ERR, "No Segments found for VFIO Mapping");
 		return -1;
 	}
+	FSLMC_VFIO_LOG(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;
 
drivers/event/dpaa2/Makefile +3 -0
index b26862c..a5b68b4 100644
@@ -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
index efaac96..c1cc2a3 100644
@@ -27,6 +27,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/net/dpaa2/Makefile +3 -0
index 068e9d3..cc5627c 100644
@@ -33,6 +33,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
index ad1724d..8e96b5a 100644
@@ -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
drivers/net/octeontx/Makefile +3 -0
index 3e4a106..5f488b9 100644
@@ -16,6 +16,9 @@ EXPORT_MAP := rte_pmd_octeontx_version.map
 
 LIBABIVER := 1
 
+# depends on fslmc bus which uses experimental API
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 OBJS_BASE_DRIVER=$(patsubst %.c,%.o,$(notdir $(wildcard $(SRCDIR)/base/*.c)))
 $(foreach obj, $(OBJS_BASE_DRIVER), $(eval CFLAGS_$(obj)+=$(CFLAGS_BASE_DRIVER)))
 
Signature · 1 line
2.7.4
Acked-by on v3 26/68
#174 lore raw

Re: [PATCH v3 26/68] bus/fslmc: use memseg walk instead of iteration

Hello Anatoly,

Quoted 15 lines · Anatoly Burakov
---
  drivers/bus/fslmc/fslmc_vfio.c | 78 ++++++++++++++++++++++--------------------
  drivers/event/dpaa2/Makefile   |  3 ++
  drivers/mempool/dpaa2/Makefile |  3 ++
  drivers/net/dpaa2/Makefile     |  3 ++
  drivers/net/dpaa2/meson.build  |  3 ++
  drivers/net/octeontx/Makefile  |  3 ++
  6 files changed, 56 insertions(+), 37 deletions(-)
drivers/bus/fslmc/fslmc_vfio.c +0 -0
index 1310190..ccdbeff 100644

drivers/bus/fslmc/fslmc_vfio.c static int vfio_map_irq_region(struct fslmc_vfio_group *group) · line 193

Quoted 1 line
drivers/bus/fslmc/fslmc_vfio.c +0 -0
@@ -193,17 +193,51 @@ static int vfio_map_irq_region(struct fslmc_vfio_group *group)
  	return -errno;

[...]

I will send an incremental patch, in reply to this, which fixes dpaa2 for va cases.

Though, I think this patch can be completely replaced by that - if you prefer that, let me know and I will send it non-incremental (master based).

Quoted 16 lines
drivers/net/dpaa2/meson.build +3 -0
index ad1724d..8e96b5a 100644
@@ -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
drivers/net/octeontx/Makefile +0 -0
index 3e4a106..5f488b9 100644

drivers/net/octeontx/Makefile EXPORT_MAP := rte_pmd_octeontx_version.map · line 19

Quoted 4 lines
drivers/net/octeontx/Makefile +1 -0
@@ -16,6 +16,9 @@ EXPORT_MAP := rte_pmd_octeontx_version.map
 
  LIBABIVER := 1
 
+# depends on fslmc bus which uses experimental API

I think you wanted to say "octeontx" rather than fslmc here. Also, this is not part of 'bus/fslmc' patch.

drivers/net/octeontx/Makefile EXPORT_MAP := rte_pmd_octeontx_version.map · line 24

Quoted 6 lines
drivers/net/octeontx/Makefile +2 -0
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
  OBJS_BASE_DRIVER=$(patsubst %.c,%.o,$(notdir $(wildcard $(SRCDIR)/base/*.c)))
  $(foreach obj, $(OBJS_BASE_DRIVER), $(eval CFLAGS_$(obj)+=$(CFLAGS_BASE_DRIVER)))
 

If the Octeon part is removed from above, and incremental patch is merged here, please use my Ack:

#175 lore raw

PATCH 1/1 bus/fslmc: support for hotplugging of memory

In reply to Anatoly Burakov

Restructure VFIO DMA code for handling hotplug memory events (callbacks) and --legacy case.

---

###
This is based on the 16fbfef04a3 github repository. This is assuming that changes already exists as done in patch 26/68.
Though, this can be a standalone, replacing 26/88. Though, the Makefile changes don't exist in this.
Also, this just a first draft. I will push any review changes after this incrementally over v4.
###

 drivers/bus/fslmc/fslmc_bus.c    |  15 ++++
 drivers/bus/fslmc/fslmc_vfio.c   | 161 +++++++++++++++++++++++++++++++++++----
 drivers/bus/fslmc/fslmc_vfio.h   |   1 +
 drivers/net/dpaa2/dpaa2_ethdev.c |   1 -
 4 files changed, 163 insertions(+), 15 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +15 -0
index 5ee0beb85..50884ff3a 100644
@@ -266,6 +266,21 @@ rte_fslmc_probe(void)
 		return 0;
 	}
 
+	if (rte_log_get_global_level() >= RTE_LOG_DEBUG)
+		rte_dump_physmem_layout(stdout);
+
+	/* Map existing segments as well as, in case of hotpluggable memory,
+	 * install callback handler.
+	 */
+	ret = rte_fslmc_vfio_dmamap();
+	if (ret) {
+		FSLMC_BUS_LOG(ERR, "Unable to DMA map existing VAs: (%d)",
+			      ret);
+		/* Not continuing ahead */
+		FSLMC_BUS_LOG(ERR, "FSLMC VFIO Mapping failed");
+		return 0;
+	}
+
 	ret = fslmc_vfio_process_group();
 	if (ret) {
 		FSLMC_BUS_LOG(ERR, "Unable to setup devices %d", ret);
drivers/bus/fslmc/fslmc_vfio.c +147 -14

213 lines not on this page · raw message

drivers/bus/fslmc/fslmc_vfio.h +1 -0
index e8fb3445f..e77e4c4ac 100644
@@ -9,6 +9,7 @@
 #define _FSLMC_VFIO_H_
 
 #include <rte_vfio.h>
+#include <rte_memory.h>
 
 #include "eal_vfio.h"
 
drivers/net/dpaa2/dpaa2_ethdev.c +0 -1
index 2fb7b2da7..962b90035 100644
@@ -1850,7 +1850,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();
 
 	RTE_LOG(INFO, PMD, "%s: netdev created\n", eth_dev->data->name);
 	return 0;
Signature · 1 line
2.14.1
#176 lore raw

Re: [PATCH] bus/fslmc: support for hotplugging of memory

Quoted 6 lines · Shreyansh Jain

Restructure VFIO DMA code for handling hotplug memory events (callbacks) and --legacy case.

---

Quoted 8 lines

###
This is based on the 16fbfef04a3 github repository. This is assuming that changes already exists as done in patch 26/68.
Though, this can be a standalone, replacing 26/88. Though, the Makefile changes don't exist in this.
Also, this just a first draft. I will push any review changes after this incrementally over v4.
###

Hi Shreyansh,

I think we can keep the 26/68 as it still works within the context of the patchset. I would like to add these changes closer to the end, where we enable support for callbacks in VFIO (this could/should come as the next patch).

That said, i took some liberties when integrating this patch, hopefully for the better. I know you mentioned it's a draft, so you can post any comments for the inevitable v4 :)

Quoted 12 lines
  drivers/bus/fslmc/fslmc_bus.c    |  15 ++++
  drivers/bus/fslmc/fslmc_vfio.c   | 161 +++++++++++++++++++++++++++++++++++----
  drivers/bus/fslmc/fslmc_vfio.h   |   1 +
  drivers/net/dpaa2/dpaa2_ethdev.c |   1 -
  4 files changed, 163 insertions(+), 15 deletions(-)
drivers/bus/fslmc/fslmc_bus.c +0 -0
index 5ee0beb85..50884ff3a 100644

drivers/bus/fslmc/fslmc_bus.c rte_fslmc_probe(void) · line 270

Quoted 5 lines
drivers/bus/fslmc/fslmc_bus.c +2 -0
@@ -266,6 +266,21 @@ rte_fslmc_probe(void)
  		return 0;
  	}
 
+	if (rte_log_get_global_level() >= RTE_LOG_DEBUG)
+		rte_dump_physmem_layout(stdout);

Presumably, this is not needed - just debug leftovers?

drivers/bus/fslmc/fslmc_bus.c rte_fslmc_probe(void) · line 283

Quoted 13 lines
drivers/bus/fslmc/fslmc_bus.c +13 -0
+
+	/* Map existing segments as well as, in case of hotpluggable memory,
+	 * install callback handler.
+	 */
+	ret = rte_fslmc_vfio_dmamap();
+	if (ret) {
+		FSLMC_BUS_LOG(ERR, "Unable to DMA map existing VAs: (%d)",
+			      ret);
+		/* Not continuing ahead */
+		FSLMC_BUS_LOG(ERR, "FSLMC VFIO Mapping failed");
+		return 0;
+	}
+

What happens if there are no devices on the bus that can be used by DPDK? As far as i can tell, it would return error, which may or may not be desirable (failing to map anything because there aren't any fslmc devices is not an error?).

For "regular" VFIO, the container is an empty shell unless you add groups into it - does fslmc VFIO support work differently, and container is already working/initialized by the time we reach this point?

Anyway, i'll leave this as is.

Quoted 12 lines
drivers/bus/fslmc/fslmc_bus.c +0 -0
  	ret = fslmc_vfio_process_group();
  	if (ret) {
  		FSLMC_BUS_LOG(ERR, "Unable to setup devices %d", ret);
drivers/bus/fslmc/fslmc_vfio.c +1 -0
index 31831e3ce..60725fb70 100644
@@ -30,6 +30,7 @@
  #include <rte_kvargs.h>
  #include <rte_dev.h>
  #include <rte_bus.h>
+#include <rte_eal_memconfig.h>

<...>

drivers/bus/fslmc/fslmc_vfio.c static int vfio_map_irq_region(struct fslmc_vfio_group *group) · line 257

Quoted 10 lines
drivers/bus/fslmc/fslmc_vfio.c +7 -2
+}
+
  static int
-fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused,
-		const struct rte_memseg *ms, void *arg)
+#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA
+fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr, size_t len)
+#else
+fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr __rte_unused, size_t len)
+#endif

I think i'll leave this as just "rte_iova_t iovaaddr __rte_unused" :)

Quoted 13 lines
  {
drivers/bus/fslmc/fslmc_vfio.c +2 -3
-	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),
@@ -205,10 +263,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;

<...>

Quoted 4 lines

if (is_dma_done)
return 0;

I suspect this check was needed because you've done VFIO mapping on device probe as opposed to bus probe, so VFIO mapping function could've been called multiple times. Is that still the case, or is this check no longer needed? I took the liberty to remove it.

Quoted 4 lines
drivers/bus/fslmc/fslmc_vfio.c +3 -1
-	if (rte_memseg_walk(fslmc_vfio_map, &i) < 0)
+	/* Lock before parsing and registering callback to memory subsystem */
+	rte_rwlock_read_lock(mem_lock);
+

<...>

drivers/bus/fslmc/fslmc_vfio.h line 15

Quoted 13 lines

return 0;

drivers/bus/fslmc/fslmc_vfio.h +1 -0
index e8fb3445f..e77e4c4ac 100644
@@ -9,6 +9,7 @@
  #define _FSLMC_VFIO_H_
 
  #include <rte_vfio.h>
+#include <rte_memory.h>
 
  #include "eal_vfio.h"
 

I suspect this change is not needed? I took the liberty to remove it.

Signature · 2 lines
Thanks,
Anatoly
#177 lore raw

Re: [PATCH] bus/fslmc: support for hotplugging of memory

Hello Anatoly,

Quoted 16 lines · Anatoly
Quoted 6 lines · Shreyansh Jain

Restructure VFIO DMA code for handling hotplug memory events (callbacks) and --legacy case.

---

Quoted 8 lines

###
This is based on the 16fbfef04a3 github repository. This is assuming that changes already exists as done in patch 26/68.
Though, this can be a standalone, replacing 26/88. Though, the Makefile changes don't exist in this.
Also, this just a first draft. I will push any review changes after this incrementally over v4.
###

Quoted 3 lines

Hi Shreyansh,

I think we can keep the 26/68 as it still works within the context of the patchset. I would like to add these changes closer to the end, where we enable support for callbacks in VFIO (this could/should come as the next patch).

But then it would also mean that dpaa2 would be broken within the memory hotplug patches? I think it would be broken once the memseg ceases to be continuous physical sets.

Quoted 11 lines

That said, i took some liberties when integrating this patch, hopefully for the better. I know you mentioned it's a draft, so you can post any comments for the inevitable v4 :)

Quoted 8 lines

  drivers/bus/fslmc/fslmc_bus.c    |  15 ++++
  drivers/bus/fslmc/fslmc_vfio.c   | 161
+++++++++++++++++++++++++++++++++++----
  drivers/bus/fslmc/fslmc_vfio.h   |   1 +
  drivers/net/dpaa2/dpaa2_ethdev.c |   1 -

  4 files changed, 163 insertions(+), 15 deletions(-)
Quoted 11 lines

drivers/bus/fslmc/fslmc_bus.c rte_fslmc_probe(void) · line 269

Quoted 9 lines
drivers/bus/fslmc/fslmc_bus.c +2 -0
index 5ee0beb85..50884ff3a 100644
@@ -266,6 +266,21 @@ rte_fslmc_probe(void)
           return 0;
       }
+    if (rte_log_get_global_level() >= RTE_LOG_DEBUG)
+        rte_dump_physmem_layout(stdout);

Presumably, this is not needed - just debug leftovers?

Yes, and can be removed.

Quoted 16 lines
Quoted 4 lines
drivers/bus/fslmc/fslmc_bus.c +3 -0
+
+    /* Map existing segments as well as, in case of hotpluggable memory,
+     * install callback handler.

drivers/bus/fslmc/fslmc_bus.c rte_fslmc_probe(void) · line 283

Quoted 10 lines
drivers/bus/fslmc/fslmc_bus.c +10 -0
+     */
+    ret = rte_fslmc_vfio_dmamap();
+    if (ret) {
+        FSLMC_BUS_LOG(ERR, "Unable to DMA map existing VAs: (%d)",
+                  ret);
+        /* Not continuing ahead */
+        FSLMC_BUS_LOG(ERR, "FSLMC VFIO Mapping failed");
+        return 0;
+    }
+

What happens if there are no devices on the bus that can be used by DPDK? As far as i can tell, it would return error, which may or may not be desirable (failing to map anything because there aren't any fslmc devices is not an error?).

## If no devices found on the bus:
Call wouldn't have reached here. There is a jump out in rte_fslmc_probe in case no devices were scanned on the bus.

--->8--- rte_fslmc_probe() ---
...

        if (TAILQ_EMPTY(&rte_fslmc_bus.device_list))
                return 0;

...
--->8---

## Assuming you are pointing to 'return 0':
So, the rte_eal_scan/probe doesn't expect to be interrupted just because one of the buses had issues (whether no devices found, not a real issue). It would continue ahead with scan/probe.

But, I think error should be returned so that rte_eal_probe can dump to logs the error and continue ahead normally. I will fix this.

Quoted 2 lines

For "regular" VFIO, the container is an empty shell unless you add groups into it - does fslmc VFIO support work differently, and container is already working/initialized by the time we reach this point?

FSLMC VFIO Container is not much different from generic container. But, at this point in code, the container is already initialized (group is connected to it, and relevant device fds extracted). Only thing pending beyond this point is to look into the container and initialize various fslmc specific devices contained *within* the group. And, dma mapping of regions which is done using the newly introduced code.

Quoted 2 lines

Anyway, i'll leave this as is.

OK.

Quoted 16 lines
Quoted 13 lines
drivers/bus/fslmc/fslmc_bus.c +0 -0
       ret = fslmc_vfio_process_group();
       if (ret) {
           FSLMC_BUS_LOG(ERR, "Unable to setup devices %d", ret);
drivers/bus/fslmc/fslmc_vfio.c +1 -0
index 31831e3ce..60725fb70 100644
@@ -30,6 +30,7 @@
   #include <rte_kvargs.h>
   #include <rte_dev.h>
   #include <rte_bus.h>
+#include <rte_eal_memconfig.h>

<...>

Quoted 13 lines
Quoted 11 lines
drivers/bus/fslmc/fslmc_vfio.c +2 -0
+}
+

  static int

drivers/bus/fslmc/fslmc_vfio.c +4 -2
-fslmc_vfio_map(const struct rte_memseg_list *msl __rte_unused,
-        const struct rte_memseg *ms, void *arg)
+#ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA
+fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr, size_t len)
+#else
+fslmc_map_dma(uint64_t vaddr, rte_iova_t iovaddr __rte_unused, size_t 

len)
+#endif

I think i'll leave this as just "rte_iova_t iovaaddr __rte_unused" :)

Hmm, it is harmless if used without the enclosing #defines.
But, i don't know if any compiler has any side-effects attached to this - for example, clang reporting this as error, etc.

Quoted 17 lines
Quoted 14 lines

  {
-    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),

drivers/bus/fslmc/fslmc_vfio.c +2 -2
@@ -205,10 +263,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;

<...>

Quoted 4 lines
Quoted 2 lines

      if (is_dma_done)
          return 0;

I suspect this check was needed because you've done VFIO mapping on device probe as opposed to bus probe, so VFIO mapping function could've been called multiple times. Is that still the case, or is this check no longer needed? I took the liberty to remove it.

Yes, that is correct. Now that device probe vfio is disabled, it is safe to remove this check.

Quoted 9 lines
Quoted 6 lines

-    if (rte_memseg_walk(fslmc_vfio_map, &i) < 0)
+    /* Lock before parsing and registering callback to memory subsystem */
+    rte_rwlock_read_lock(mem_lock);
+

<...>

Quoted 13 lines

drivers/bus/fslmc/fslmc_vfio.h line 12

Quoted 10 lines

      return 0;

drivers/bus/fslmc/fslmc_vfio.h +1 -0
index e8fb3445f..e77e4c4ac 100644
@@ -9,6 +9,7 @@
   #define _FSLMC_VFIO_H_
   #include <rte_vfio.h>
+#include <rte_memory.h>
   #include "eal_vfio.h"

I suspect this change is not needed? I took the liberty to remove it.

I remember when I was using your initial patch, this I added based on structures being unresolved. It is possible that is not longer the case (and that I too have moved a lot of code beyond the first internal draft). If it compiles OK, no need for this.

-
Shreyansh

#178 lore raw

Re: [PATCH] bus/fslmc: support for hotplugging of memory

Quoted 19 lines · Shreyansh Jain

Hello Anatoly,

Quoted 16 lines · Anatoly
Quoted 14 lines · Shreyansh Jain

Restructure VFIO DMA code for handling hotplug memory events (callbacks) and --legacy case.

---

###
This is based on the 16fbfef04a3 github repository. This is assuming that changes already exists as done in patch 26/68.
Though, this can be a standalone, replacing 26/88. Though, the Makefile changes don't exist in this.
Also, this just a first draft. I will push any review changes after this incrementally over v4.
###

Quoted 7 lines
Quoted 3 lines

Hi Shreyansh,

I think we can keep the 26/68 as it still works within the context of the patchset. I would like to add these changes closer to the end, where we enable support for callbacks in VFIO (this could/should come as the next patch).

But then it would also mean that dpaa2 would be broken within the memory hotplug patches? I think it would be broken once the memseg ceases to be continuous physical sets.

Hi Shreyansh,

Why would it be broken? Even when memseg change comes into effect, legacy mem is not enabled until much later in the patchset, when all of the callback/multiprocess business is in place. For all intents and purposes, this stays valid for legacy mode, hence not broken.

We later enable callbacks etc. on VFIO, but technically they still aren't enabled until 65 (67 in v4), when it becomes possible to actually run DPDK in non-legacy mode.

So, for the duration of this patchset, dpaa2 is not broken, as far as i can tell. Keeping in mind that only legacy mode will be available until patch 65/67, what exactly is being broken here?

Signature · 2 lines
Thanks,
Anatoly
#179 lore raw

Re: [PATCH] bus/fslmc: support for hotplugging of memory

Quoted 44 lines

-----Original Message-----
From: Burakov, Anatoly [mailto:[email protected]]
Sent: Monday, April 9, 2018 9:20 PM
To: Shreyansh Jain <[email protected]>
Cc: [email protected]
Subject: Re: [dpdk-dev] [PATCH] bus/fslmc: support for hotplugging of memory

Quoted 14 lines · Shreyansh Jain

Hello Anatoly,

Quoted 11 lines · Anatoly
Quoted 10 lines · Shreyansh Jain

Restructure VFIO DMA code for handling hotplug memory events (callbacks) and --legacy case.

---

###
This is based on the 16fbfef04a3 github repository. This is assuming that changes already exists as done in patch 26/68. Though, this can be a standalone, replacing 26/88. Though, the

Makefile

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

changes don't exist in this.
Also, this just a first draft. I will push any review changes after

this

Quoted 11 lines
Quoted 9 lines
Quoted 2 lines

incrementally over v4.
###

Hi Shreyansh,

I think we can keep the 26/68 as it still works within the context of the patchset. I would like to add these changes closer to the end, where we enable support for callbacks in VFIO (this could/should come as the next patch).

But then it would also mean that dpaa2 would be broken within the

memory

Quoted 4 lines

hotplug patches?
I think it would be broken once the memseg ceases to be continuous physical sets.

Quoted 6 lines

Hi Shreyansh,

Why would it be broken? Even when memseg change comes into effect, legacy mem is not enabled until much later in the patchset, when all of the callback/multiprocess business is in place. For all intents and purposes, this stays valid for legacy mode, hence not broken.

Ok. Then, I am mistaken. I was under the impression that as soon as memseg lists are introduced, when memseg stop being contiguous blocks, DPAA2 would have stopped working. I just didn't put an effort to check this.

Quoted 4 lines

We later enable callbacks etc. on VFIO, but technically they still aren't enabled until 65 (67 in v4), when it becomes possible to actually run DPDK in non-legacy mode.

Got it. Thanks.

Quoted 5 lines

So, for the duration of this patchset, dpaa2 is not broken, as far as i can tell. Keeping in mind that only legacy mode will be available until patch 65/67, what exactly is being broken here?

Nothing, just a misunderstanding.

Quoted 3 lines

--
Thanks,
Anatoly

#180 lore raw

PATCH v3 27/68 bus/pci: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 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
index f3df1c4..804a198 100644
@@ -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
index abde641..6dda054 100644
@@ -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
index 12756a4..72939e5 100644
@@ -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
#181 lore raw

PATCH v3 28/68 net/mlx5: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 drivers/net/mlx5/Makefile |  3 +++
 drivers/net/mlx5/mlx5.c   | 24 +++++++++++++++---------
 2 files changed, 18 insertions(+), 9 deletions(-)
drivers/net/mlx5/Makefile +3 -0
index afda411..25c8e10 100644
@@ -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
index 7d58d66..1724b65 100644
@@ -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
#182 lore raw

PATCH v3 29/68 eal: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 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
index 4eafcb5..8e25d78 100644
@@ -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
index 564b61a..79914fc 100644
@@ -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 @@ int
 rte_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
index 2ecd07b..77f6cb7 100644
@@ -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
#183 lore raw

PATCH v3 30/68 mempool: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 lib/librte_mempool/rte_mempool.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)
lib/librte_mempool/rte_mempool.c +12 -12
index e147180..bb33c3a 100644
@@ -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
#184 lore raw

PATCH v3 31/68 test: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 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
index d23192c..578ad04 100644
@@ -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, &param) > 0)
+		return param.socket;
 	return -1;
 }
 
test/test/test_memory.c +12 -11
index 972321f..c9b287c 100644
@@ -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
#185 lore raw

PATCH v3 32/68 vfio/type1: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 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
index 2421d51..2a34ae9 100644
@@ -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
#186 lore raw

PATCH v3 33/68 vfio/spapr: use memseg walk instead of iteration

In reply to Anatoly Burakov
---
 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
index 2a34ae9..fb41e82 100644
@@ -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, &reg);
+	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(&param, 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, &param);
 
 	/* 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, &reg);
-		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
#187 lore raw

PATCH v3 34/68 eal: add contig walk function

In reply to Anatoly Burakov

For now, this function is identical to memseg walk function, but it is meant to walk over first segment of each VA contiguous group of memsegs. The difference will become apparent when memseg lists will come into play.

Again, 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
index 4f588c7..4b528b0 100644
@@ -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
index 93eadaa..45d067f 100644
@@ -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
index 7e9900d..8409a3a 100644
@@ -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_memzone_reserve_contig;
 	rte_memzone_reserve_aligned_contig;
Signature · 1 line
2.7.4
#188 lore raw

PATCH v3 35/68 virtio: use memseg contig walk instead of iteration

In reply to Anatoly Burakov
---
 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
index 1711ead..93d7efe 100644
@@ -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
#189 lore raw

PATCH v3 36/68 eal: add iova2virt function

In reply to Anatoly Burakov

This 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
index 4b528b0..ea3c5a7 100644
@@ -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
index 45d067f..5c60b91 100644
@@ -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
index 8409a3a..83b1635 100644
@@ -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_memzone_reserve_contig;
Signature · 1 line
2.7.4
#190 lore raw

PATCH v3 37/68 bus/dpaa: use iova2virt instead of memseg iteration

In reply to Anatoly Burakov
---
 drivers/bus/dpaa/rte_dpaa_bus.h | 12 +-----------
 drivers/event/dpaa/Makefile     |  3 +++
 drivers/mempool/dpaa/Makefile   |  3 +++
 drivers/net/dpaa/Makefile       |  3 +++
 4 files changed, 10 insertions(+), 11 deletions(-)
drivers/bus/dpaa/rte_dpaa_bus.h +1 -11
index 718701b..89aeac2 100644
@@ -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/event/dpaa/Makefile +3 -0
index ddd8552..df3cae8 100644
@@ -26,6 +26,9 @@ EXPORT_MAP := rte_pmd_dpaa_event_version.map
 
 LIBABIVER := 1
 
+# depends on dpaa bus which uses experimental API
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+
 # Interfaces with DPDK
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_DPAA_EVENTDEV) += dpaa_eventdev.c
 
drivers/mempool/dpaa/Makefile +3 -0
index 4c0d7aa..da8da1e 100644
@@ -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/net/dpaa/Makefile +3 -0
index 9c2a5ea..d7a0a50 100644
@@ -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
#191 lore raw

PATCH v3 38/68 bus/fslmc: use iova2virt instead of memseg iteration

In reply to Anatoly Burakov
---
 drivers/bus/fslmc/portal/dpaa2_hw_pvt.h | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/bus/fslmc/portal/dpaa2_hw_pvt.h +1 -12
index 4a19d42..d38fc49 100644
@@ -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));
Signature · 1 line
2.7.4
#192 lore raw

PATCH v3 39/68 crypto/dpaa_sec: use iova2virt instead of memseg iteration

In reply to Anatoly Burakov
---
 drivers/crypto/dpaa_sec/dpaa_sec.c | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)
drivers/crypto/dpaa_sec/dpaa_sec.c +1 -10
index c5191ce..b04510f 100644
@@ -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
#193 lore raw

PATCH v3 40/68 eal: add virt2memseg function

In reply to Anatoly Burakov

This 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
index ea3c5a7..fd78d2f 100644
@@ -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
index 5c60b91..b3d7e61 100644
@@ -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
index 83b1635..70ec778 100644
@@ -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_memzone_reserve_contig;
Signature · 1 line
2.7.4
#194 lore raw

PATCH v3 41/68 bus/fslmc: use virt2memseg instead of iteration

In reply to Anatoly Burakov
---
 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
index d38fc49..45fd41e 100644
@@ -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
#195 lore raw

PATCH v3 42/68 net/mlx4: use virt2memseg instead of iteration

In reply to Anatoly Burakov
---
 drivers/net/mlx4/mlx4_mr.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)
drivers/net/mlx4/mlx4_mr.c +7 -10
index 9a1e4de..47dd542 100644
@@ -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
#196 lore raw

PATCH v3 43/68 net/mlx5: use virt2memseg instead of iteration

In reply to Anatoly Burakov
---
 drivers/net/mlx5/mlx5_mr.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/net/mlx5/mlx5_mr.c +8 -10
index 2bf1f9c..d8c04dc 100644
@@ -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
#197 lore raw

PATCH v3 44/68 crypto/dpaa_sec: use virt2memseg instead of iteration

In reply to Anatoly Burakov
---
 drivers/crypto/dpaa_sec/dpaa_sec.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)
drivers/crypto/dpaa_sec/dpaa_sec.c +5 -14
index b04510f..a14e669 100644
@@ -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
#198 lore raw

PATCH v3 45/68 eal: use memzone walk instead of iteration

In reply to Anatoly Burakov
---
 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
index 36d2553..88f401f 100644
@@ -395,31 +395,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
#199 lore raw

PATCH v3 46/68 vfio: allow to map other memory regions

In reply to Anatoly Burakov

Currently 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
index 8e25d78..032a5ea 100644
@@ -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
index 249095e..bd4663c 100644
@@ -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
index 8059577..549f442 100644
@@ -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
index 70ec778..fe4a9c9 100644
@@ -266,5 +266,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
#200 lore raw

Re: [PATCH v3 46/68] vfio: allow to map other memory regions

Quoted 10 lines · Anatoly Burakov

Currently 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.

---

There's a larger issue raised by this patch. We do support hotplug for VFIO devices, and VFIO will drop all maps whenever last device used by VFIO is unplugged. Since primary use case for this API is mapping non-DPDK-owned memory for DMA, this presents a problem, because we're not tracking the mapped areas anywhere, which means that on last device hot-unplug followed by first device hotplug event, whatever DMA maps user has set up, will be gone - only DPDK-owned memory will be remapped.

One way we could solve it is to store user maps in a local tailq and remap those on hotplug. Another way would be to not solve it and just document this limitation - that using this API in conjunction with hotplug will result in undefined behavior. I would tend to favor the first way.

Signature · 2 lines
Thanks,
Anatoly
#201 lore raw

Re: [PATCH v3 46/68] vfio: allow to map other memory regions

In reply to Anatoly Burakov
Quoted 9 lines · Anatoly Burakov

Currently 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.

---

@Gowrishankar,

We've discussed this privately already, but just to make sure it is publicly stated: as it is, parts of this patchset for PPC64 have potential issues with them.

Unmapping and remapping the entire segment list on alloc introduces a race condition - what if a DMA request comes in while we're in the middle of remapping? We cannot realistically stop NICs from doing DMA while some other thread is allocating memory.

There is also a larger issue that i've raised in a previous response to this patch [1], and PPC64 will will have this problem worse, because not only the described issue will happen on hot-unplug/hotplug, but it may also happen during regular allocations, because PPC64 IOMMU will drop all mappings on window resize.

[1] http://dpdk.org/ml/archives/dev/2018-April/095182.html

Signature · 2 lines
Thanks,
Anatoly
#202 lore raw

PATCH v3 47/68 eal: add "legacy memory" option

In reply to Anatoly Burakov

This 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
index 032a5ea..f44b904 100644
@@ -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
index 8a51ade..fb5ea03 100644
@@ -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
index a0082d1..fda087b 100644
@@ -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
index e86c711..d301d0b 100644
@@ -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
index 77f6cb7..b34e57a 100644
@@ -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
index 5642cc8..1d3defe 100644
@@ -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
#203 lore raw

PATCH v3 48/68 eal: add rte_fbarray

In reply to Anatoly Burakov

rte_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
index ed1d17b..1b43d77 100644
@@ -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
index ea824a3..48f870f 100644
@@ -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
index 4708dd5..1c6048b 100644
@@ -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
index 82b8910..7d02191 100644
@@ -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
index b9c7727..c407a43 100644
@@ -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
index fe4a9c9..3a12112 100644
@@ -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
#204 lore raw

PATCH v3 49/68 eal: replace memseg with memseg lists

In reply to Anatoly Burakov

Before, 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:
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         | 581 ++++++++++++--
 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, 1563 insertions(+), 589 deletions(-)
config/common_base +14 -1
index 7abf7c6..0ca1a06 100644
@@ -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
index a42ba4f..1178fe3 100644
@@ -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
index 144ba0a..f096e22 100644
@@ -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
index b6206a5..57d000d 100644
@@ -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
index 72c0aa2..e42be1c 100644
@@ -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_LEVEL RTE_LOG_INFO
doc/guides/rel_notes/deprecation.rst +0 -9
index ec70b5f..c9f2703 100644
@@ -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
index ccdbeff..31831e3 100644
@@ -194,7 +194,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;
@@ -236,18 +237,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) {
-		FSLMC_VFIO_LOG(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
index 45fd41e..72aae43 100644
@@ -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
index 6dda054..4630a80 100644
@@ -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
index a14e669..b685220 100644
@@ -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
index 47dd542..2ba609e 100644
@@ -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
index 1724b65..e228356 100644
@@ -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
index d8c04dc..6638185 100644
@@ -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
index 93d7efe..b244409 100644
@@ -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
index f44b904..d009cf0 100644
@@ -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
index be2dbf0..ba44da0 100644
@@ -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 +495 -86

674 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
index 1d519bb..ad1b0b6 100644
@@ -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
index fda087b..5cf7102 100644
@@ -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
index 29fa0b6..b745e18 100644
@@ -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
index ef3a4dd..6d4bdf1 100644
@@ -67,7 +67,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
index 87695b9..685aac4 100644
@@ -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
index 34bd268..620dd44 100644
@@ -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
index 436818a..c6d3e57 100644
@@ -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
index b34e57a..ffcbd71 100644
@@ -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
index 8bbf771..afebd42 100644
@@ -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
index f6fe93e..2c27063 100644
@@ -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
index 3a12112..df5802d 100644
@@ -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_memzone_reserve_contig;
 	rte_memzone_reserve_aligned_contig;
lib/librte_mempool/rte_mempool.c +5 -4
index bb33c3a..38fb1ba 100644
@@ -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
index 578ad04..805bf04 100644
@@ -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;
-	}
-	return 0;
-}
 
 /*
  * Find what socket a memory address is on. Only works for addresses within
@@ -744,10 +729,9 @@ find_socket(const struct rte_memseg *ms, void *arg)
 static int32_t
 addr_to_socket(void * addr)
 {
-	struct walk_param param = {.addr = addr, .socket = 0};
-	if (rte_memseg_walk(find_socket, &param) > 0)
-		return param.socket;
-	return -1;
+	const struct rte_memseg *ms = rte_mem_virt2memseg(addr, NULL);
+	return ms == NULL ? -1 : ms->socket_id;
+
 }
 
 /* Test using rte_[c|m|zm]alloc_socket() on a specific socket */
test/test/test_memory.c +7 -3
index c9b287c..b96bca7 100644
@@ -5,8 +5,11 @@
 #include <stdio.h>
 #include <stdint.h>
 
+#include <rte_eal.h>
+#include <rte_eal_memconfig.h>
 #include <rte_memory.h>
 #include <rte_common.h>
+#include <rte_memzone.h>
 
 #include "test.h"
 
@@ -23,12 +26,13 @@
  */
 
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

test/test/test_memzone.c +6 -6
index cbf0cfa..0046f04 100644

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.

#205 lore raw

PATCH v3 50/68 eal: replace memzone array with fbarray

In reply to Anatoly Burakov

It'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:
v3:
- Moved earlier in patchset
- Fixed compiled issues
- Removed rte_panic() calls

 drivers/net/ena/ena_ethdev.c                      |  10 +-
 lib/librte_eal/bsdapp/eal/eal.c                   |  14 ++-
 lib/librte_eal/common/eal_common_memzone.c        | 109 ++++++++++++----------
 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 +-
 7 files changed, 99 insertions(+), 64 deletions(-)
drivers/net/ena/ena_ethdev.c +7 -3
index 34b2a8d..f7bfc7a 100644
@@ -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
index d009cf0..54330e1 100644
@@ -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 +59 -50

203 lines not on this page · raw message

lib/librte_eal/common/include/rte_eal_memconfig.h +1 -3
index b745e18..88cde8c 100644
@@ -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
index 0ef2c45..d798675 100644
@@ -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
index ffcbd71..9832551 100644
@@ -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
index 0046f04..efcf732 100644
@@ -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 int
 test_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
#206 lore raw

Re: [PATCH v3 50/68] eal: replace memzone array with fbarray

Quoted 18 lines · Anatoly Burakov

It'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:
v3:
- Moved earlier in patchset
- Fixed compiled issues
- Removed rte_panic() calls

[...]

Quoted 20 lines
lib/librte_eal/common/eal_common_memzone.c +4 -2
index 529b36f..aed9331 100644
@@ -28,42 +28,31 @@
  static inline const struct rte_memzone *
  memzone_lookup_thread_unsafe(const char *name)
  {
-	const struct rte_mem_config *mcfg;
+	struct rte_mem_config *mcfg;
+	struct rte_fbarray *arr;
  	const struct rte_memzone *mz;
-	unsigned i = 0;
+	int i = 0;
 
  	/* get pointer to global configuration */
  	mcfg = rte_eal_get_configuration()->mem_config;
+	arr = &mcfg->memzones;
 
  	/*

lib/librte_eal/common/eal_common_memzone.c line 46

Quoted 10 lines
lib/librte_eal/common/eal_common_memzone.c +3 -4
  	 * the algorithm is not optimal (linear), but there are few
  	 * zones and this function should be called at init only
  	 */
-	for (i = 0; i < RTE_MAX_MEMZONE; i++) {
-		mz = &mcfg->memzone[i];
-		if (mz->addr != NULL && !strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
-			return &mcfg->memzone[i];
+	i = rte_fbarray_find_next_used(arr, 0);
+	while (i >= 0) {
+		mz = rte_fbarray_get(arr, i++);
                                         ^^^^^^^^

As discussed offline, this needs to be changed. Double increment of 'i' leading to skips over lookup.

lib/librte_eal/common/eal_common_memzone.c line 55

Quoted 9 lines
lib/librte_eal/common/eal_common_memzone.c +4 -0
+		if (mz->addr != NULL &&
+				!strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
+			return mz;
+		i = rte_fbarray_find_next_used(arr, i + 1);
  	}
 
  	return NULL;
  }
 

[..]

-
Shreyansh

#207 lore raw

PATCH v3 51/68 eal: add support for mapping hugepages at runtime

In reply to Anatoly Burakov

Nothing 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
index 1b43d77..19f9322 100644
@@ -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
new file mode 100644
index 0000000..8c30670
@@ -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
index e83fc91..4b40223 100644
@@ -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
new file mode 100644
index 0000000..f628514
@@ -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
index c407a43..af6b9be 100644
@@ -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
index 03974ff..5254c6c 100644
@@ -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
#208 lore raw

PATCH v3 52/68 eal: add support for unmapping pages at runtime

In reply to Anatoly Burakov

This 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
index 8c30670..e7bcd2b 100644
@@ -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
index f628514..6017345 100644
@@ -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
#209 lore raw

PATCH v3 53/68 eal: add "single file segments" command-line option

In reply to Anatoly Burakov

Currently, 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
index fb5ea03..5b5da5f 100644
@@ -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
index 5cf7102..9d33cf4 100644
@@ -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
index d301d0b..211ae06 100644
@@ -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
index 9832551..2c12811 100644
@@ -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
#210 lore raw

PATCH v3 54/68 eal: add API to check if memory is contiguous

In reply to Anatoly Burakov

For 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
index 19f9322..907e30d 100644
@@ -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
index 6017345..2413c6c 100644
@@ -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
index 685aac4..9db416f 100644
@@ -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
index 7d02191..a1ada24 100644
@@ -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
index af6b9be..5380ba8 100644
@@ -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
#211 lore raw

PATCH v3 55/68 eal: prepare memseg lists for multiprocess sync

In reply to Anatoly Burakov

In 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:
- 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
index e7bcd2b..461732f 100644
@@ -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
index 2413c6c..4a7b45c 100644
@@ -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
index 88cde8c..a781793 100644
@@ -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
#212 lore raw

PATCH v3 56/68 eal: read hugepage counts from node-specific sysfs path

In reply to Anatoly Burakov

For 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
index afebd42..2e0819f 100644
@@ -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
#213 lore raw

PATCH v3 57/68 eal: make use of memory hotplug for init

In reply to Anatoly Burakov

Add 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
index d38fb68..c51d598 100644
@@ -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
#214 lore raw

PATCH v3 58/68 eal: share hugepage info primary and secondary

In reply to Anatoly Burakov

Since 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
index 54330e1..727adc5 100644
@@ -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
index 6692b3d..3064605 100644
@@ -240,23 +240,10 @@ int
 rte_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
index 5b5da5f..04a4476 100644
@@ -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
index 1c6048b..ad059ef 100644
@@ -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
index ad1b0b6..4582f19 100644
@@ -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
index 9d33cf4..c4cbf3a 100644
@@ -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
index 2c12811..e7c6dcf 100644
@@ -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
index c51d598..efa1202 100644
@@ -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
#215 lore raw

PATCH v3 59/68 eal: add secondary process init with memory hotplug

In reply to Anatoly Burakov

Secondary 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
index 0a6d678..8db085e 100644
@@ -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
index efa1202..7ec7129 100644
@@ -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
#216 lore raw

PATCH v3 60/68 eal: enable memory hotplug support in rte_malloc

In reply to Anatoly Burakov

This 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        |  86 +++++++
 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, 433 insertions(+), 64 deletions(-)
lib/librte_eal/common/eal_common_memzone.c +3 -23
index aed9331..d522883 100644
@@ -94,7 +94,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;
 
 	/* get pointer to global configuration */
 	mcfg = rte_eal_get_configuration()->mem_config;
@@ -179,29 +179,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 +86 -0

92 lines not on this page · raw message

lib/librte_eal/common/malloc_elem.h +3 -0
index 620dd44..8f4aef8 100644
@@ -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
index c57b59a..03b8014 100644
@@ -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
index c6d3e57..b51a6d1 100644
@@ -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
#217 lore raw

PATCH v3 61/68 eal: add support for multiprocess memory hotplug

In reply to Anatoly Burakov

This 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_elem.c               | 124 ++--
 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 +-
 lib/librte_eal/linuxapp/eal/eal_vfio.c            |  40 +-
 11 files changed, 1229 insertions(+), 125 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
index 907e30d..250d5c1 100644
@@ -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
index a781793..aff0688 100644
@@ -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_elem.c +65 -59

139 lines not on this page · raw message

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
index a1ada24..8a3dcfe 100644
@@ -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
index 5380ba8..542bf7e 100644
@@ -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
index ce242b1..8202a1b 100644
@@ -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;
 }
lib/librte_eal/linuxapp/eal/eal_vfio.c +38 -2
index 2c27063..cbfe3c9 100644
@@ -53,6 +53,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)
 {
@@ -884,7 +920,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(&param, 0, sizeof(param));
 
-	if (rte_memseg_walk(vfio_spapr_window_size_walk, &param) < 0) {
+	if (memseg_walk_thread_unsafe(vfio_spapr_window_size_walk, &param) < 0) {
 		RTE_LOG(ERR, EAL, "Could not get window size\n");
 		return -1;
 	}
@@ -902,7 +938,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
#218 lore raw

PATCH v3 62/68 eal: add support for callbacks on memory hotplug

In reply to Anatoly Burakov

Each 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.

---

Notes:
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  |  49 ++++++++++
 lib/librte_eal/rte_eal_version.map          |   2 +
 5 files changed, 223 insertions(+)
lib/librte_eal/common/eal_common_memalloc.c +133 -0
index 607ec3f..2d2d46f 100644
@@ -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
index 0c4c1f5..e3ce69c 100644
@@ -604,6 +604,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
index 4a7b45c..4d27403 100644
@@ -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 +49 -0

55 lines not on this page · raw message

lib/librte_eal/rte_eal_version.map +2 -0
index df5802d..0460edb 100644
@@ -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
#219 lore raw

PATCH v3 63/68 eal: enable callbacks on malloc/free and mp sync

In reply to Anatoly Burakov

Callbacks 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
index be39250..18c7b69 100644
@@ -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
index 8202a1b..87c1bdb 100644
@@ -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
index cbfe3c9..8b5f8fd 100644
@@ -931,6 +931,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,
@@ -946,9 +947,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
#220 lore raw

PATCH v3 64/68 vfio: enable support for mem event callbacks

In reply to Anatoly Burakov

Enable callbacks on first device attach, disable callbacks on last device attach.

---

Notes:
v3:
- Moved callbacks to attach/detach as opposed to init

 lib/librte_eal/linuxapp/eal/eal_vfio.c | 83 +++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 6 deletions(-)
lib/librte_eal/linuxapp/eal/eal_vfio.c +77 -6
index 8b5f8fd..eb1a024 100644
@@ -18,6 +18,8 @@
 
 #ifdef VFIO_PRESENT
 
+#define VFIO_MEM_EVENT_CLB_NAME "vfio_mem_event_clb"
+
 /* per-process VFIO config */
 static struct vfio_config vfio_cfg;
 
@@ -250,6 +252,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)
 {
@@ -312,6 +346,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)
 	};
@@ -399,6 +435,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,
@@ -406,10 +446,17 @@ 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 */
+			rte_mem_event_callback_register(VFIO_MEM_EVENT_CLB_NAME,
+					vfio_mem_event_callback);
+			/* unlock memory hotplug */
+			rte_rwlock_read_unlock(mem_lock);
 		}
 	}
 
@@ -447,6 +494,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)
 	};
@@ -454,13 +503,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 */
@@ -468,7 +524,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
@@ -480,7 +537,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
@@ -492,17 +550,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
Signature · 1 line
2.7.4
#221 lore raw

PATCH v3 65/68 eal: enable non-legacy memory mode

In reply to Anatoly Burakov

Now 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
index e7c6dcf..99c2242 100644
@@ -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
#222 lore raw

PATCH v3 66/68 eal: add memory validator callback

In reply to Anatoly Burakov

This 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.

---
 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  |  59 ++++++++++++
 lib/librte_eal/rte_eal_version.map          |   2 +
 5 files changed, 234 insertions(+), 1 deletion(-)
lib/librte_eal/common/eal_common_memalloc.c +137 -1
index 2d2d46f..49fd53c 100644
@@ -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
index e3ce69c..d221240 100644
@@ -632,6 +632,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
index 4d27403..6bec52c 100644
@@ -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 +59 -0

65 lines not on this page · raw message

lib/librte_eal/rte_eal_version.map +2 -0
index 0460edb..b94c48c 100644
@@ -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
#223 lore raw

PATCH v3 67/68 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
index 18c7b69..f8daf84 100644
@@ -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
#224 lore raw

PATCH v3 68/68 eal: prevent preallocated pages from being freed

In reply to Anatoly Burakov

It 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
index 0318bfe..58b607b 100644
@@ -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
index f8daf84..41c14a8 100644
@@ -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
index 87c1bdb..0da2e3c 100644
@@ -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
index 7ec7129..2bd9c30 100644
@@ -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
#225 lore raw
In reply to Anatoly Burakov

Hello Anatoly,

Quoted 67 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC asynchronous request API patch [2]
- Function to return number of sockets [3]
- EAL IOVA fix [4]

Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [5]
- EAL NUMA node count changes [6]

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 [7]
* 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 v3, the following limitations are present:
- VFIO support is only smoke-tested (but is expected to work), VFIO support with secondary processes is not tested; work is ongoing to validate VFIO for all use cases
- FSLMC bus VFIO code is not yet integrated, work is in progress

For testing, it is recommended to use the GitHub repository [8], as it will have all of the dependencies already integrated.

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

Quoted 9 lines

[1] http://dpdk.org/dev/patchwork/bundle/aburakov/Memory_RFC/
[2] http://dpdk.org/dev/patchwork/bundle/aburakov/IPC_Async_Request/
[3] http://dpdk.org/dev/patchwork/bundle/aburakov/Num_Sockets/
[4] http://dpdk.org/dev/patchwork/bundle/aburakov/IOVA_mode_fixes/
[5] http://dpdk.org/dev/patchwork/patch/34002/
[6] http://dpdk.org/dev/patchwork/patch/33853/
[7] http://dpdk.org/dev/patchwork/patch/24484/
[8] https://github.com/anatolyburakov/dpdk

Thanks for the huge work and continuously answering my barrage of questions. Here is the update for dpaa/dpaa2. Incremental to [1]:

Note: Results based on github repo (16fbfef04a37bb9d714), rather than this series over master. Though, it shouldn't make that big a difference.

PA: Physical Addressing mode
VA: Virtual Addressing mode

1. DPAA2 PA and VA work OK over the github repo
a. Almost equal performance for VA cases as compared to non-hotplug.
Whether in --legacy-mem or without it. ($ see below)
b. 70~90% drops in performance for PA case, depending on page size
used (# see below)

2. DPAA PA (there is no VA mode) works with a minor fix over v3 which Anatoly knows about might incorporate in v4 (Patch 50/68) a. 70-90% performance drop. (# see below)

($)
There are some changes in dpaa2 code base which I will share against relevant patch in this series. That can be incorporated into v4 to enable dpaa2 in VA mode.

(#)
Physical addressing cases for both, dpaa/dpaa2, depend heavily on the fact that physical addressing was the base and was available in sorted manner. This is reversed/negated with hotplugging support. So, rework of both the drivers is required from this perspective. There are some suggestions floated by Anatoly and internally, but work still needs to be done.
It also impacts a lot of use-cases for virtualization (no-iommu).

[1] http://dpdk.org/ml/archives/dev/2018-March/094184.html

#226 lore raw

05/04/2018 16:24, Shreyansh Jain:

Quoted 7 lines

Physical addressing cases for both, dpaa/dpaa2, depend heavily on the fact that physical addressing was the base and was available in sorted manner. This is reversed/negated with hotplugging support. So, rework of both the drivers is required from this perspective. There are some suggestions floated by Anatoly and internally, but work still needs to be done.
It also impacts a lot of use-cases for virtualization (no-iommu).

So what is your recommendation?
Can you rework PA case in dpaa/dpaa2 drivers within 18.05 timeframe?

#227 lore raw

HI Thomas,

Quoted 25 lines

-----Original Message-----
From: Thomas Monjalon [mailto:[email protected]]
Sent: Thursday, April 05, 2018 7:43 PM
To: Shreyansh Jain <[email protected]>
Cc: Anatoly Burakov <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Hemant Agrawal <[email protected]>; [email protected]; [email protected]
Subject: Re: [dpdk-dev] [PATCH v3 00/68] Memory Hotplug for DPDK
Importance: High

05/04/2018 16:24, Shreyansh Jain:

Quoted 7 lines

Physical addressing cases for both, dpaa/dpaa2, depend heavily on the fact that physical addressing was the base and was available in sorted manner. This is reversed/negated with hotplugging support. So, rework of both the drivers is required from this perspective. There are some suggestions floated by Anatoly and internally, but work still needs to be done.
It also impacts a lot of use-cases for virtualization (no-iommu).

Quoted 3 lines

So what is your recommendation?
Can you rework PA case in dpaa/dpaa2 drivers within 18.05 timeframe?

We will like 2-3 more days on this before we can ack/nack this patch. We are working on priority on this. PA case rework is not a trivial change.

Regards,
Hemant

Tested-by
#228 lore raw

Hi Thomas

Quoted 25 lines
Quoted 25 lines

-----Original Message-----
From: Thomas Monjalon [mailto:[email protected]]
Sent: Thursday, April 05, 2018 7:43 PM
To: Shreyansh Jain <[email protected]>
Cc: Anatoly Burakov <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Hemant Agrawal <[email protected]>; [email protected]; [email protected]
Subject: Re: [dpdk-dev] [PATCH v3 00/68] Memory Hotplug for DPDK
Importance: High

05/04/2018 16:24, Shreyansh Jain:

Quoted 7 lines

Physical addressing cases for both, dpaa/dpaa2, depend heavily on the fact that physical addressing was the base and was available in sorted manner. This is reversed/negated with hotplugging support. So, rework of both the drivers is required from this perspective. There are some suggestions floated by Anatoly and internally, but work still needs to be done.
It also impacts a lot of use-cases for virtualization (no-iommu).

Quoted 5 lines
Quoted 3 lines

So what is your recommendation?
Can you rework PA case in dpaa/dpaa2 drivers within 18.05 timeframe?

We will like 2-3 more days on this before we can ack/nack this patch. We are working on priority on this. PA case rework is not a trivial change.

The patch is good to go. However, we will be making changes in dpaa/dpaa2 drivers to fix the PA issues shortly (within 18.05 timeframe)

Anatoly needs to take care of following:
1. Comment by Shreyansh on " Re: [dpdk-dev] [PATCH v3 50/68] eal: replace memzone array with fbarray"
2. I could not apply the patches cleanly on current master.

Quoted 3 lines

Regards,
Hemant

#229 lore raw
Quoted 27 lines · Hemant Agrawal

Hi Thomas

Quoted 25 lines
Quoted 25 lines

-----Original Message-----
From: Thomas Monjalon [mailto:[email protected]]
Sent: Thursday, April 05, 2018 7:43 PM
To: Shreyansh Jain <[email protected]>
Cc: Anatoly Burakov <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; Hemant Agrawal <[email protected]>; [email protected]; [email protected]
Subject: Re: [dpdk-dev] [PATCH v3 00/68] Memory Hotplug for DPDK
Importance: High

05/04/2018 16:24, Shreyansh Jain:

Quoted 7 lines

Physical addressing cases for both, dpaa/dpaa2, depend heavily on the fact that physical addressing was the base and was available in sorted manner. This is reversed/negated with hotplugging support. So, rework of both the drivers is required from this perspective. There are some suggestions floated by Anatoly and internally, but work still needs to be done.
It also impacts a lot of use-cases for virtualization (no-iommu).

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

So what is your recommendation?
Can you rework PA case in dpaa/dpaa2 drivers within 18.05 timeframe?

We will like 2-3 more days on this before we can ack/nack this patch. We are working on priority on this. PA case rework is not a trivial change.

The patch is good to go. However, we will be making changes in dpaa/dpaa2 drivers to fix the PA issues shortly (within 18.05 timeframe)

That's great to hear!

Quoted 3 lines

Anatoly needs to take care of following:
1. Comment by Shreyansh on " Re: [dpdk-dev] [PATCH v3 50/68] eal: replace memzone array with fbarray"

Yes, that is already fixed in both github and upcoming v4.

Quoted 1 line

2. I could not apply the patches cleanly on current master.

The patchset has dependencies, listed in the cover letter. I'll rebase on latest master before sending v4 just in case.

Quoted 8 lines
Quoted 3 lines

Regards,
Hemant

Signature · 2 lines
Thanks,
Anatoly
Tested-by on the v3 series
#230 lore raw
In reply to Anatoly Burakov

Hi Anatoly,

Quoted 64 lines · Anatoly Burakov

This patchset introduces dynamic memory allocation for DPDK (aka memory hotplug). Based upon RFC submitted in December [1].

Dependencies (to be applied in specified order):
- IPC asynchronous request API patch [2]
- Function to return number of sockets [3]
- EAL IOVA fix [4]

Deprecation notices relevant to this patchset:
- General outline of memory hotplug changes [5]
- EAL NUMA node count changes [6]

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 [7]
* 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 v3, the following limitations are present:
- VFIO support is only smoke-tested (but is expected to work), VFIO support with secondary processes is not tested; work is ongoing to validate VFIO for all use cases
- FSLMC bus VFIO code is not yet integrated, work is in progress

For testing, it is recommended to use the GitHub repository [8], as it will have all of the dependencies already integrated.

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

Quoted 2 lines

v2: - fixed deadlock at init
- reverted rte_panic changes at init, this is now handled inside IPC