mirror of
https://github.com/openvswitch/ovs
synced 2025-09-02 07:15:17 +00:00
netdev-dpdk: Free mempool only when no in-use mbufs.
DPDK mempools are freed when they are no longer needed.
This can happen when a port is removed or a port's mtu
is reconfigured so that a new mempool is used.
It is possible that an mbuf is attempted to be returned
to a freed mempool from NIC Tx queues and this can lead
to a segfault.
In order to prevent this, only free mempools when they
are not needed and have no in-use mbufs. As this might
not be possible immediately, sweep the mempools anytime
a port tries to get a mempool.
Fixes: 8d38823bdf
("netdev-dpdk: fix memory leak")
Cc: mark.b.kavanagh81@gmail.com
Cc: Ilya Maximets <i.maximets@samsung.com>
Reported-by: Venkatesan Pradeep <venkatesan.pradeep@ericsson.com>
Signed-off-by: Kevin Traynor <ktraynor@redhat.com>
Signed-off-by: Ian Stokes <ian.stokes@intel.com>
This commit is contained in:
committed by
Ian Stokes
parent
66c9360fb9
commit
c77f6920de
@@ -590,32 +590,69 @@ dpdk_mp_create(int socket_id, int mtu)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dpdk_mp_full(const struct rte_mempool *mp) OVS_REQUIRES(dpdk_mp_mutex)
|
||||||
|
{
|
||||||
|
unsigned ring_count;
|
||||||
|
/* This logic is needed because rte_mempool_full() is not guaranteed to
|
||||||
|
* be atomic and mbufs could be moved from mempool cache --> mempool ring
|
||||||
|
* during the call. However, as no mbufs will be taken from the mempool
|
||||||
|
* at this time, we can work around it by also checking the ring entries
|
||||||
|
* separately and ensuring that they have not changed.
|
||||||
|
*/
|
||||||
|
ring_count = rte_mempool_ops_get_count(mp);
|
||||||
|
if (rte_mempool_full(mp) && rte_mempool_ops_get_count(mp) == ring_count) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free unused mempools. */
|
||||||
|
static void
|
||||||
|
dpdk_mp_sweep(void) OVS_REQUIRES(dpdk_mp_mutex)
|
||||||
|
{
|
||||||
|
struct dpdk_mp *dmp, *next;
|
||||||
|
|
||||||
|
LIST_FOR_EACH_SAFE (dmp, next, list_node, &dpdk_mp_list) {
|
||||||
|
if (!dmp->refcount && dpdk_mp_full(dmp->mp)) {
|
||||||
|
ovs_list_remove(&dmp->list_node);
|
||||||
|
rte_mempool_free(dmp->mp);
|
||||||
|
rte_free(dmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct dpdk_mp *
|
static struct dpdk_mp *
|
||||||
dpdk_mp_get(int socket_id, int mtu)
|
dpdk_mp_get(int socket_id, int mtu)
|
||||||
{
|
{
|
||||||
struct dpdk_mp *dmp;
|
struct dpdk_mp *dmp;
|
||||||
|
bool reuse = false;
|
||||||
|
|
||||||
ovs_mutex_lock(&dpdk_mp_mutex);
|
ovs_mutex_lock(&dpdk_mp_mutex);
|
||||||
LIST_FOR_EACH (dmp, list_node, &dpdk_mp_list) {
|
LIST_FOR_EACH (dmp, list_node, &dpdk_mp_list) {
|
||||||
if (dmp->socket_id == socket_id && dmp->mtu == mtu) {
|
if (dmp->socket_id == socket_id && dmp->mtu == mtu) {
|
||||||
dmp->refcount++;
|
dmp->refcount++;
|
||||||
goto out;
|
reuse = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Sweep mempools after reuse or before create. */
|
||||||
|
dpdk_mp_sweep();
|
||||||
|
|
||||||
|
if (!reuse) {
|
||||||
dmp = dpdk_mp_create(socket_id, mtu);
|
dmp = dpdk_mp_create(socket_id, mtu);
|
||||||
if (dmp) {
|
if (dmp) {
|
||||||
ovs_list_push_back(&dpdk_mp_list, &dmp->list_node);
|
ovs_list_push_back(&dpdk_mp_list, &dmp->list_node);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
out:
|
|
||||||
|
|
||||||
ovs_mutex_unlock(&dpdk_mp_mutex);
|
ovs_mutex_unlock(&dpdk_mp_mutex);
|
||||||
|
|
||||||
return dmp;
|
return dmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release an existing mempool. */
|
/* Decrement reference to a mempool. */
|
||||||
static void
|
static void
|
||||||
dpdk_mp_put(struct dpdk_mp *dmp)
|
dpdk_mp_put(struct dpdk_mp *dmp)
|
||||||
{
|
{
|
||||||
@@ -625,12 +662,7 @@ dpdk_mp_put(struct dpdk_mp *dmp)
|
|||||||
|
|
||||||
ovs_mutex_lock(&dpdk_mp_mutex);
|
ovs_mutex_lock(&dpdk_mp_mutex);
|
||||||
ovs_assert(dmp->refcount);
|
ovs_assert(dmp->refcount);
|
||||||
|
dmp->refcount--;
|
||||||
if (!--dmp->refcount) {
|
|
||||||
ovs_list_remove(&dmp->list_node);
|
|
||||||
rte_mempool_free(dmp->mp);
|
|
||||||
rte_free(dmp);
|
|
||||||
}
|
|
||||||
ovs_mutex_unlock(&dpdk_mp_mutex);
|
ovs_mutex_unlock(&dpdk_mp_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user