Added prevention not overwrite device data in array rte_eth_dev_data[].
Secondary process appends in the first free place rather than at the
beginning. This behavior prevents overwriting devices of primary process
by secondary process.

Signed-off-by: Marcin Kerlin <marcinx.kerlin at intel.com>
---
 lib/librte_ether/rte_ethdev.c          | 90 +++++++++++++++++++++++++++++++---
 lib/librte_ether/rte_ethdev.h          | 24 +++++++++
 lib/librte_ether/rte_ether_version.map |  7 +++
 3 files changed, 113 insertions(+), 8 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 382c959..dadd77a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -176,6 +176,19 @@ rte_eth_dev_allocated(const char *name)
        return NULL;
 }

+struct rte_eth_dev_data *
+rte_eth_dev_data_allocated(const char *name)
+{
+       unsigned int i;
+
+       for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+               if (strcmp(rte_eth_dev_data[i].name, name) == 0)
+                       return &rte_eth_dev_data[i];
+       }
+
+       return NULL;
+}
+
 static uint8_t
 rte_eth_dev_find_free_port(void)
 {
@@ -188,10 +201,43 @@ rte_eth_dev_find_free_port(void)
        return RTE_MAX_ETHPORTS;
 }

+static uint8_t
+rte_eth_dev_find_free_dev_data_id(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+               if (!strlen(rte_eth_dev_data[i].name))
+                       return i;
+       }
+       return RTE_MAX_ETHPORTS;
+}
+
+int
+rte_eth_dev_release_dev_data(uint8_t port_id)
+{
+       char device[RTE_ETH_NAME_MAX_LEN];
+       struct rte_eth_dev_data *eth_dev_data = NULL;
+
+       /* get device name by port id */
+       if (rte_eth_dev_get_name_by_port(port_id, device))
+               return -EINVAL;
+
+       /* look for an entry in the device data */
+       eth_dev_data = rte_eth_dev_data_allocated(device);
+       if (eth_dev_data == NULL)
+               return -EINVAL;
+
+       /* clear an entry in the device data */
+       memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data));
+
+       return 0;
+}
+
 struct rte_eth_dev *
 rte_eth_dev_allocate(const char *name, enum rte_eth_dev_type type)
 {
-       uint8_t port_id;
+       uint8_t port_id, dev_data_id;
        struct rte_eth_dev *eth_dev;

        port_id = rte_eth_dev_find_free_port();
@@ -203,17 +249,35 @@ rte_eth_dev_allocate(const char *name, enum 
rte_eth_dev_type type)
        if (rte_eth_dev_data == NULL)
                rte_eth_dev_data_alloc();

+       do {
+               dev_data_id = rte_eth_dev_find_free_dev_data_id();
+       } while (!rte_spinlock_trylock(&rte_eth_dev_data[dev_data_id].lock)
+                       && dev_data_id < RTE_MAX_ETHPORTS);
+
+       if (dev_data_id == RTE_MAX_ETHPORTS) {
+               RTE_PMD_DEBUG_TRACE("Reached maximum number of Ethernet ports 
by all "
+                               "the processes\n");
+               return NULL;
+       }
+
        if (rte_eth_dev_allocated(name) != NULL) {
                RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already 
allocated!\n",
                                name);
                return NULL;
        }

+       if (rte_eth_dev_data_allocated(name) != NULL) {
+               RTE_PMD_DEBUG_TRACE("Ethernet Device with name %s already 
allocated by "
+                               "another process!\n", name);
+               return NULL;
+       }
+
        eth_dev = &rte_eth_devices[port_id];
-       eth_dev->data = &rte_eth_dev_data[port_id];
+       eth_dev->data = &rte_eth_dev_data[dev_data_id];
        snprintf(eth_dev->data->name, sizeof(eth_dev->data->name), "%s", name);
        eth_dev->data->port_id = port_id;
        eth_dev->attached = DEV_ATTACHED;
+       rte_spinlock_unlock(&eth_dev->data->lock);
        eth_dev->dev_type = type;
        nb_ports++;
        return eth_dev;
@@ -417,9 +481,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
                return -EINVAL;
        }

-       /* shouldn't check 'rte_eth_devices[i].data',
-        * because it might be overwritten by VDEV PMD */
-       tmp = rte_eth_dev_data[port_id].name;
+       tmp = rte_eth_devices[port_id].data->name;
        strcpy(name, tmp);
        return 0;
 }
@@ -438,9 +500,7 @@ rte_eth_dev_get_port_by_name(const char *name, uint8_t 
*port_id)

        for (i = 0; i < RTE_MAX_ETHPORTS; i++) {

-               if (!strncmp(name,
-                       rte_eth_dev_data[i].name, strlen(name))) {
-
+               if (!strncmp(name, rte_eth_devices[i].data->name, 
strlen(name))) {
                        *port_id = i;

                        return 0;
@@ -631,6 +691,8 @@ int
 rte_eth_dev_detach(uint8_t port_id, char *name)
 {
        struct rte_pci_addr addr;
+       struct rte_eth_dev_data *eth_dev_data = NULL;
+       char device[RTE_ETH_NAME_MAX_LEN];
        int ret = -1;

        if (name == NULL) {
@@ -642,6 +704,15 @@ rte_eth_dev_detach(uint8_t port_id, char *name)
        if (rte_eth_dev_is_detachable(port_id))
                goto err;

+       /* get device name by port id */
+       if (rte_eth_dev_get_name_by_port(port_id, device))
+               goto err;
+
+       /* look for an entry in the shared device data */
+       eth_dev_data = rte_eth_dev_data_allocated(device);
+       if (eth_dev_data == NULL)
+               goto err;
+
        if (rte_eth_dev_get_device_type(port_id) == RTE_ETH_DEV_PCI) {
                ret = rte_eth_dev_get_addr_by_port(port_id, &addr);
                if (ret < 0)
@@ -661,6 +732,9 @@ rte_eth_dev_detach(uint8_t port_id, char *name)
                        goto err;
        }

+       /* clear an entry in the shared device data */
+       memset(eth_dev_data, 0, sizeof(struct rte_eth_dev_data));
+
        return 0;

 err:
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 96575e8..541e44e 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1708,6 +1708,7 @@ struct rte_eth_dev_data {
        enum rte_kernel_driver kdrv;    /**< Kernel driver passthrough */
        int numa_node;  /**< NUMA node connection */
        const char *drv_name;   /**< Driver name */
+       rte_spinlock_t lock; /** Lock on allocate eth device */
 };

 /** Device supports hotplug detach */
@@ -1752,6 +1753,29 @@ struct rte_eth_dev *rte_eth_dev_allocated(const char 
*name);

 /**
  * @internal
+ * Returns a shared device data slot specified by the unique identifier name.
+ *
+ * @param      name
+ *  The pointer to the Unique identifier name for each shared Ethernet device
+ *  between multiple processes.
+ * @return
+ *   - The pointer to the device data slot, on success. NULL on error
+ */
+struct rte_eth_dev_data *rte_eth_dev_data_allocated(const char *name);
+
+/**
+ * @internal
+ * Release device data kept in shared memory for all processes.
+ *
+ * @param      port_id
+ *   The port identifier of the device to release device data.
+ * @return
+ *   - 0 on success, negative on error
+ */
+int rte_eth_dev_release_dev_data(uint8_t port_id);
+
+/**
+ * @internal
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
  * to that slot for the driver to use.
  *
diff --git a/lib/librte_ether/rte_ether_version.map 
b/lib/librte_ether/rte_ether_version.map
index 45ddf44..f37a15c 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -139,3 +139,10 @@ DPDK_16.07 {
        rte_eth_dev_get_port_by_name;
        rte_eth_xstats_get_names;
 } DPDK_16.04;
+
+DPDK_16.11 {
+       global:
+
+       rte_eth_dev_data_allocated;
+       rte_eth_dev_release_dev_data;
+} DPDK_16.07;
-- 
1.9.1

Reply via email to