From 8a5a0aad5d3e4f4f75ca81932eb247de94765685 Mon Sep 17 00:00:00 2001 From: Thomas Monjalon Date: Fri, 16 Oct 2020 15:32:59 +0200 Subject: [PATCH] ethdev: allow close function to return an error The API function rte_eth_dev_close() was returning void. The return type is changed to int for notifying of errors. If an error happens during a close operation, the status of the port is undefined, a maximum of resources having been freed. Signed-off-by: Thomas Monjalon Reviewed-by: Liron Himi Acked-by: Stephen Hemminger Acked-by: Andrew Rybchenko Reviewed-by: Ferruh Yigit --- doc/guides/rel_notes/deprecation.rst | 1 - doc/guides/rel_notes/release_20_11.rst | 2 ++ drivers/net/cxgbe/cxgbe_ethdev.c | 5 +++-- drivers/net/cxgbe/cxgbevf_ethdev.c | 5 +++-- drivers/net/failsafe/failsafe_ether.c | 6 +++++- drivers/net/failsafe/failsafe_ops.c | 25 +++++++++++++++++-------- drivers/net/memif/rte_eth_memif.c | 4 +--- drivers/net/mlx5/mlx5.c | 7 ++++--- drivers/net/mvneta/mvneta_ethdev.c | 5 +++-- drivers/net/mvpp2/mrvl_ethdev.c | 5 +++-- drivers/net/netvsc/hn_ethdev.c | 6 ++++-- drivers/net/netvsc/hn_var.h | 2 +- drivers/net/netvsc/hn_vf.c | 7 +++++-- drivers/net/virtio/virtio_user_ethdev.c | 4 +--- lib/librte_ethdev/rte_ethdev.c | 16 +++++++++++----- lib/librte_ethdev/rte_ethdev.h | 5 ++++- 16 files changed, 67 insertions(+), 38 deletions(-) diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst index 6b191aaf69..b5582491ff 100644 --- a/doc/guides/rel_notes/deprecation.rst +++ b/doc/guides/rel_notes/deprecation.rst @@ -128,7 +128,6 @@ Deprecation Notices invalid port ID, unsupported operation, failed operation): - ``rte_eth_dev_stop`` - - ``rte_eth_dev_close`` * ethdev: New offload flags ``DEV_RX_OFFLOAD_FLOW_MARK`` will be added in 19.11. This will allow application to enable or disable PMDs from updating diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst index f0337a16ff..5f1ef125ba 100644 --- a/doc/guides/rel_notes/release_20_11.rst +++ b/doc/guides/rel_notes/release_20_11.rst @@ -422,6 +422,8 @@ API Changes * ethdev: Added capability to query age flow action. +* ethdev: Added ``int`` return type to ``rte_eth_dev_close()``. + * ethdev: Renamed internal functions: * ``_rte_eth_dev_callback_process()`` -> ``rte_eth_dev_callback_process()`` diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c index 16beb2d435..fe488231a7 100644 --- a/drivers/net/cxgbe/cxgbe_ethdev.c +++ b/drivers/net/cxgbe/cxgbe_ethdev.c @@ -1296,12 +1296,13 @@ static int eth_cxgbe_dev_uninit(struct rte_eth_dev *eth_dev) { struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); uint16_t port_id; + int err = 0; /* Free up other ports and all resources */ RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device) - rte_eth_dev_close(port_id); + err |= rte_eth_dev_close(port_id); - return 0; + return err == 0 ? 0 : -EIO; } static int eth_cxgbe_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, diff --git a/drivers/net/cxgbe/cxgbevf_ethdev.c b/drivers/net/cxgbe/cxgbevf_ethdev.c index 947fcdd406..c2918f5356 100644 --- a/drivers/net/cxgbe/cxgbevf_ethdev.c +++ b/drivers/net/cxgbe/cxgbevf_ethdev.c @@ -183,12 +183,13 @@ static int eth_cxgbevf_dev_uninit(struct rte_eth_dev *eth_dev) { struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); uint16_t port_id; + int err = 0; /* Free up other ports and all resources */ RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device) - rte_eth_dev_close(port_id); + err |= rte_eth_dev_close(port_id); - return 0; + return err == 0 ? 0 : -EIO; } static int eth_cxgbevf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, diff --git a/drivers/net/failsafe/failsafe_ether.c b/drivers/net/failsafe/failsafe_ether.c index f18935a7e2..c6066c76a3 100644 --- a/drivers/net/failsafe/failsafe_ether.c +++ b/drivers/net/failsafe/failsafe_ether.c @@ -287,7 +287,11 @@ fs_dev_remove(struct sub_device *sdev) /* fallthrough */ case DEV_ACTIVE: failsafe_eth_dev_unregister_callbacks(sdev); - rte_eth_dev_close(PORT_ID(sdev)); + ret = rte_eth_dev_close(PORT_ID(sdev)); + if (ret < 0) { + ERROR("Port close failed for sub-device %u", + PORT_ID(sdev)); + } sdev->state = DEV_PROBED; /* fallthrough */ case DEV_PROBED: diff --git a/drivers/net/failsafe/failsafe_ops.c b/drivers/net/failsafe/failsafe_ops.c index 0ce7dfc8a6..5c606ff077 100644 --- a/drivers/net/failsafe/failsafe_ops.c +++ b/drivers/net/failsafe/failsafe_ops.c @@ -638,7 +638,7 @@ failsafe_eth_dev_close(struct rte_eth_dev *dev) { struct sub_device *sdev; uint8_t i; - int ret; + int err, ret = 0; fs_lock(dev, 0); failsafe_hotplug_alarm_cancel(dev); @@ -648,29 +648,38 @@ failsafe_eth_dev_close(struct rte_eth_dev *dev) FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { DEBUG("Closing sub_device %d", i); failsafe_eth_dev_unregister_callbacks(sdev); - rte_eth_dev_close(PORT_ID(sdev)); + err = rte_eth_dev_close(PORT_ID(sdev)); + if (err) { + ret = ret ? ret : err; + ERROR("Error while closing sub-device %u", + PORT_ID(sdev)); + } sdev->state = DEV_ACTIVE - 1; } rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_NEW, failsafe_eth_new_event_callback, dev); if (rte_eal_process_type() != RTE_PROC_PRIMARY) { fs_unlock(dev, 0); - return 0; + return ret; } fs_dev_free_queues(dev); - ret = failsafe_eal_uninit(dev); - if (ret) + err = failsafe_eal_uninit(dev); + if (err) { + ret = ret ? ret : err; ERROR("Error while uninitializing sub-EAL"); + } failsafe_args_free(dev); rte_free(PRIV(dev)->subs); rte_free(PRIV(dev)->mcast_addrs); /* mac_addrs must not be freed alone because part of dev_private */ dev->data->mac_addrs = NULL; fs_unlock(dev, 0); - ret = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex); - if (ret) + err = pthread_mutex_destroy(&PRIV(dev)->hotplug_mutex); + if (err) { + ret = ret ? ret : err; ERROR("Error while destroying hotplug mutex"); - return 0; + } + return ret; } static int diff --git a/drivers/net/memif/rte_eth_memif.c b/drivers/net/memif/rte_eth_memif.c index d71d9aae48..fe72a01612 100644 --- a/drivers/net/memif/rte_eth_memif.c +++ b/drivers/net/memif/rte_eth_memif.c @@ -1850,9 +1850,7 @@ rte_pmd_memif_remove(struct rte_vdev_device *vdev) if (eth_dev == NULL) return 0; - rte_eth_dev_close(eth_dev->data->port_id); - - return 0; + return rte_eth_dev_close(eth_dev->data->port_id); } static struct rte_vdev_driver pmd_memif_drv = { diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 44822ad1d9..77aeac85c5 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -2042,6 +2042,7 @@ static int mlx5_pci_remove(struct rte_pci_device *pci_dev) { uint16_t port_id; + int ret = 0; RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device) { /* @@ -2049,11 +2050,11 @@ mlx5_pci_remove(struct rte_pci_device *pci_dev) * call the close function explicitly for secondary process. */ if (rte_eal_process_type() == RTE_PROC_SECONDARY) - mlx5_dev_close(&rte_eth_devices[port_id]); + ret |= mlx5_dev_close(&rte_eth_devices[port_id]); else - rte_eth_dev_close(port_id); + ret |= rte_eth_dev_close(port_id); } - return 0; + return ret == 0 ? 0 : -EIO; } static const struct rte_pci_id mlx5_pci_id_map[] = { diff --git a/drivers/net/mvneta/mvneta_ethdev.c b/drivers/net/mvneta/mvneta_ethdev.c index 3c0332ab4d..1574bf35a8 100644 --- a/drivers/net/mvneta/mvneta_ethdev.c +++ b/drivers/net/mvneta/mvneta_ethdev.c @@ -966,14 +966,15 @@ static int rte_pmd_mvneta_remove(struct rte_vdev_device *vdev) { uint16_t port_id; + int ret = 0; RTE_ETH_FOREACH_DEV(port_id) { if (rte_eth_devices[port_id].device != &vdev->device) continue; - rte_eth_dev_close(port_id); + ret |= rte_eth_dev_close(port_id); } - return 0; + return ret == 0 ? 0 : -EIO; } static struct rte_vdev_driver pmd_mvneta_drv = { diff --git a/drivers/net/mvpp2/mrvl_ethdev.c b/drivers/net/mvpp2/mrvl_ethdev.c index a230a96840..df9f336fab 100644 --- a/drivers/net/mvpp2/mrvl_ethdev.c +++ b/drivers/net/mvpp2/mrvl_ethdev.c @@ -3022,14 +3022,15 @@ static int rte_pmd_mrvl_remove(struct rte_vdev_device *vdev) { uint16_t port_id; + int ret = 0; RTE_ETH_FOREACH_DEV(port_id) { if (rte_eth_devices[port_id].device != &vdev->device) continue; - rte_eth_dev_close(port_id); + ret |= rte_eth_dev_close(port_id); } - return 0; + return ret == 0 ? 0 : -EIO; } static struct rte_vdev_driver pmd_mrvl_drv = { diff --git a/drivers/net/netvsc/hn_ethdev.c b/drivers/net/netvsc/hn_ethdev.c index 8743e6e69a..40e6d25f34 100644 --- a/drivers/net/netvsc/hn_ethdev.c +++ b/drivers/net/netvsc/hn_ethdev.c @@ -842,14 +842,16 @@ hn_dev_stop(struct rte_eth_dev *dev) static int hn_dev_close(struct rte_eth_dev *dev) { + int ret; + PMD_INIT_FUNC_TRACE(); if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; - hn_vf_close(dev); + ret = hn_vf_close(dev); hn_dev_free_queues(dev); - return 0; + return ret; } static const struct eth_dev_ops hn_eth_dev_ops = { diff --git a/drivers/net/netvsc/hn_var.h b/drivers/net/netvsc/hn_var.h index 4b63f87607..74f30669ac 100644 --- a/drivers/net/netvsc/hn_var.h +++ b/drivers/net/netvsc/hn_var.h @@ -217,7 +217,7 @@ const uint32_t *hn_vf_supported_ptypes(struct rte_eth_dev *dev); int hn_vf_start(struct rte_eth_dev *dev); void hn_vf_reset(struct rte_eth_dev *dev); void hn_vf_stop(struct rte_eth_dev *dev); -void hn_vf_close(struct rte_eth_dev *dev); +int hn_vf_close(struct rte_eth_dev *dev); int hn_vf_allmulticast_enable(struct rte_eth_dev *dev); int hn_vf_allmulticast_disable(struct rte_eth_dev *dev); diff --git a/drivers/net/netvsc/hn_vf.c b/drivers/net/netvsc/hn_vf.c index f5f15c0462..d29eee7627 100644 --- a/drivers/net/netvsc/hn_vf.c +++ b/drivers/net/netvsc/hn_vf.c @@ -316,18 +316,21 @@ void hn_vf_reset(struct rte_eth_dev *dev) VF_ETHDEV_FUNC(dev, rte_eth_dev_reset); } -void hn_vf_close(struct rte_eth_dev *dev) +int hn_vf_close(struct rte_eth_dev *dev) { struct hn_data *hv = dev->data->dev_private; uint16_t vf_port; + int ret = 0; rte_rwlock_read_lock(&hv->vf_lock); vf_port = hv->vf_port; if (vf_port != HN_INVALID_PORT) - rte_eth_dev_close(vf_port); + ret = rte_eth_dev_close(vf_port); hv->vf_port = HN_INVALID_PORT; rte_rwlock_read_unlock(&hv->vf_lock); + + return ret; } int hn_vf_stats_reset(struct rte_eth_dev *dev) diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c index f56fc238c4..042665bc09 100644 --- a/drivers/net/virtio/virtio_user_ethdev.c +++ b/drivers/net/virtio/virtio_user_ethdev.c @@ -881,9 +881,7 @@ virtio_user_pmd_remove(struct rte_vdev_device *vdev) return rte_eth_dev_release_port(eth_dev); /* make sure the device is stopped, queues freed */ - rte_eth_dev_close(eth_dev->data->port_id); - - return 0; + return rte_eth_dev_close(eth_dev->data->port_id); } static int virtio_user_pmd_dma_map(struct rte_vdev_device *vdev, void *addr, diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index 2b56dd76a6..9e838be8bc 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -1772,19 +1772,25 @@ rte_eth_dev_set_link_down(uint16_t port_id) return eth_err(port_id, (*dev->dev_ops->dev_set_link_down)(dev)); } -void +int rte_eth_dev_close(uint16_t port_id) { struct rte_eth_dev *dev; + int firsterr, binerr; + int *lasterr = &firsterr; - RTE_ETH_VALID_PORTID_OR_RET(port_id); + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV); dev = &rte_eth_devices[port_id]; - RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_close); - (*dev->dev_ops->dev_close)(dev); + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -ENOTSUP); + *lasterr = (*dev->dev_ops->dev_close)(dev); + if (*lasterr != 0) + lasterr = &binerr; rte_ethdev_trace_close(port_id); - rte_eth_dev_release_port(dev); + *lasterr = rte_eth_dev_release_port(dev); + + return eth_err(port_id, firsterr); } int diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index 0a134b697f..f4c0624308 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2513,8 +2513,11 @@ int rte_eth_dev_set_link_down(uint16_t port_id); * * @param port_id * The port identifier of the Ethernet device. + * @return + * - Zero if the port is closed successfully. + * - Negative if something went wrong. */ -void rte_eth_dev_close(uint16_t port_id); +int rte_eth_dev_close(uint16_t port_id); /** * Reset a Ethernet device and keep its port id.