During a proactive device reset, a polling thread may attempt to stop and start the device outside of the main EAL thread. Guard against contention by having device start, stop, and reset callbacks acquire and release the mutex.
Signed-off-by: Jasper Tran O'Leary <[email protected]> Reviewed-by: Joshua Washington <[email protected]> --- drivers/net/gve/gve_ethdev.c | 35 +++++++++++++++++++++++++------ drivers/net/gve/gve_ethdev.h | 2 ++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c index 44810b864..391e7923f 100644 --- a/drivers/net/gve/gve_ethdev.c +++ b/drivers/net/gve/gve_ethdev.c @@ -558,16 +558,19 @@ gve_dev_start(struct rte_eth_dev *dev) return -EPERM; } + priv = dev->data->dev_private; + + pthread_mutex_lock(&priv->reset_lock); + ret = gve_start_queues(dev); if (ret != 0) { PMD_DRV_LOG(ERR, "Failed to start queues"); - return ret; + goto unlock_and_return; } dev->data->dev_started = 1; gve_link_update(dev, 0); - priv = dev->data->dev_private; /* No stats available yet for Dqo. */ if (gve_is_gqi(priv)) { ret = gve_alloc_stats_report(priv, @@ -576,7 +579,7 @@ gve_dev_start(struct rte_eth_dev *dev) if (ret != 0) { PMD_DRV_LOG(ERR, "Failed to allocate region for stats reporting."); - return ret; + goto unlock_and_return; } ret = process_priv->ctrl_ops->setup_stats_report(priv, priv->stats_report_len, @@ -584,13 +587,16 @@ gve_dev_start(struct rte_eth_dev *dev) GVE_STATS_REPORT_TIMER_PERIOD); if (ret != 0) { PMD_DRV_LOG(ERR, "setup_stats_report command failed."); - return ret; + goto unlock_and_return; } } gve_start_dev_status_polling(dev); + ret = 0; - return 0; +unlock_and_return: + pthread_mutex_unlock(&priv->reset_lock); + return ret; } static void @@ -700,10 +706,14 @@ gve_dev_stop(struct rte_eth_dev *dev) /* * Block until all polling callbacks have concluded before tearing down - * any device resources. + * any device resources. Do so before trying to acquire the reset lock + * because a polling callback could be invoking a reset which will + * itself try to acquire the lock. */ gve_stop_dev_status_polling(dev); + pthread_mutex_lock(&priv->reset_lock); + dev->data->dev_started = 0; dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN; @@ -719,6 +729,8 @@ gve_dev_stop(struct rte_eth_dev *dev) if (gve_is_gqi(dev->data->dev_private)) gve_free_stats_report(dev); + pthread_mutex_unlock(&priv->reset_lock); + return 0; } @@ -880,6 +892,7 @@ gve_dev_close(struct rte_eth_dev *dev) pthread_mutex_destroy(&priv->flow_rule_lock); pthread_mutex_destroy(&priv->nic_ts_lock); + pthread_mutex_destroy(&priv->reset_lock); rte_free(priv->rxq_configs); priv->rxq_configs = NULL; @@ -908,6 +921,8 @@ gve_dev_reset(struct rte_eth_dev *dev) return -EPERM; } + pthread_mutex_lock(&priv->reset_lock); + /* Tear down all device resources before re-initializing. */ if (gve_get_flow_subsystem_ok(priv)) gve_teardown_flow_subsystem(priv); @@ -927,9 +942,12 @@ gve_dev_reset(struct rte_eth_dev *dev) PMD_DRV_LOG(ERR, "Failed to re-init device on port %u after reset.", dev->data->port_id); + pthread_mutex_unlock(&priv->reset_lock); return err; } + pthread_mutex_unlock(&priv->reset_lock); + return 0; } @@ -1971,8 +1989,12 @@ gve_dev_init(struct rte_eth_dev *eth_dev) pthread_mutexattr_init(&mutexattr); pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&priv->flow_rule_lock, &mutexattr); pthread_mutex_init(&priv->nic_ts_lock, &mutexattr); + pthread_mutex_init(&priv->reset_lock, &mutexattr); + pthread_mutexattr_destroy(&mutexattr); priv->mbuf_timestamp_offset = -1; @@ -1980,6 +2002,7 @@ gve_dev_init(struct rte_eth_dev *eth_dev) if (err) { pthread_mutex_destroy(&priv->flow_rule_lock); pthread_mutex_destroy(&priv->nic_ts_lock); + pthread_mutex_destroy(&priv->reset_lock); goto free_process_priv; } diff --git a/drivers/net/gve/gve_ethdev.h b/drivers/net/gve/gve_ethdev.h index c56a8a693..d16db54a8 100644 --- a/drivers/net/gve/gve_ethdev.h +++ b/drivers/net/gve/gve_ethdev.h @@ -385,6 +385,8 @@ struct gve_priv { struct gve_tx_queue **zombie_tx_queues; rte_spinlock_t zombie_lock; + pthread_mutex_t reset_lock; + struct gve_registers __iomem *reg_bar0; /* see gve_register.h */ rte_be32_t __iomem *db_bar; /* "array" of doorbells */ struct rte_pci_device *pci_dev; -- 2.56.0.307.g5fe7bd680c-goog

