From 84934303a17c4844d662ad08d9f4cec74d11bce6 Mon Sep 17 00:00:00 2001 From: Matan Azrad Date: Mon, 22 Jan 2018 16:38:20 +0000 Subject: [PATCH] ethdev: synchronize port allocation Ethernet port allocation was not thread safe, means 2 threads which tried to allocate a new port at the same time might get an identical port identifier and caused to memory overwrite. Actually, all the port configurations were not thread safe from ethdev point of view. The port ownership mechanism added to the ethdev is a good point to redefine the synchronization rules in ethdev: 1. The port allocation and port release synchronization will be managed by ethdev. 2. The port usage synchronization will be managed by the port owner. 3. The port ownership synchronization will be managed by ethdev. Add port allocation synchronization to complete the new rules. Signed-off-by: Matan Azrad Acked-by: Konstantin Ananyev --- lib/librte_ether/rte_ethdev.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c index b1d38cf776..78bed1a16b 100644 --- a/lib/librte_ether/rte_ethdev.c +++ b/lib/librte_ether/rte_ethdev.c @@ -268,20 +268,23 @@ struct rte_eth_dev * rte_eth_dev_allocate(const char *name) { uint16_t port_id; - struct rte_eth_dev *eth_dev; + struct rte_eth_dev *eth_dev = NULL; + + rte_eth_dev_shared_data_prepare(); + + /* Synchronize port creation between primary and secondary threads. */ + rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock); port_id = rte_eth_dev_find_free_port(); if (port_id == RTE_MAX_ETHPORTS) { RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports\n"); - return NULL; + goto unlock; } - rte_eth_dev_shared_data_prepare(); - if (rte_eth_dev_allocated(name) != NULL) { RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already allocated!\n", name); - return NULL; + goto unlock; } eth_dev = eth_dev_get(port_id); @@ -289,7 +292,11 @@ rte_eth_dev_allocate(const char *name) eth_dev->data->port_id = port_id; eth_dev->data->mtu = ETHER_MTU; - _rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_NEW, NULL); +unlock: + rte_spinlock_unlock(&rte_eth_dev_shared_data->ownership_lock); + + if (eth_dev != NULL) + _rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_NEW, NULL); return eth_dev; } @@ -303,10 +310,13 @@ struct rte_eth_dev * rte_eth_dev_attach_secondary(const char *name) { uint16_t i; - struct rte_eth_dev *eth_dev; + struct rte_eth_dev *eth_dev = NULL; rte_eth_dev_shared_data_prepare(); + /* Synchronize port attachment to primary port creation and release. */ + rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock); + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { if (strcmp(rte_eth_dev_shared_data->data[i].name, name) == 0) break; @@ -315,12 +325,12 @@ rte_eth_dev_attach_secondary(const char *name) RTE_PMD_DEBUG_TRACE( "device %s is not driven by the primary process\n", name); - return NULL; + } else { + eth_dev = eth_dev_get(i); + RTE_ASSERT(eth_dev->data->port_id == i); } - eth_dev = eth_dev_get(i); - RTE_ASSERT(eth_dev->data->port_id == i); - + rte_spinlock_unlock(&rte_eth_dev_shared_data->ownership_lock); return eth_dev; }