Sashiko reports:
***
> +err_netdev:
>       if (vsi->netdev_registered) {
>               vsi->netdev_registered = false;
>               unregister_netdev(vsi->netdev);
Could this result in a deadlock when called during a device rebuild?
Looking at i40e_rebuild(), it explicitly acquires the RTNL lock before
proceeding:
drivers/net/ethernet/intel/i40e/i40e_main.c:i40e_rebuild() {
    ...
        if (!lock_acquired)
                rtnl_lock();
        ret = i40e_setup_pf_switch(pf, reinit, true);
    ...
}
If i40e_setup_pf_switch() calls i40e_vsi_reinit_setup() and takes this new
err_netdev path, unregister_netdev() will unconditionally attempt to acquire
rtnl_lock(), leading to a deadlock on the non-recursive mutex.
***

Use unregister_netdevice() when the rebuild path already holds RTNL, and
keep unregister_netdev() for callers that do not. This avoids both
recursive RTNL locking and dropping RTNL in the middle of the VSI unwind
path.

Fixes: bc7d338fbb3f ("i40e: reinit flow for the main VSI")
Reported-by: Sashiko AI Review <[email protected]>
Signed-off-by: Maciej Fijalkowski <[email protected]>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a29a89192a7a..e88cf7cfbd84 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -14257,7 +14257,8 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
  * Returns pointer to the successfully allocated and configured VSI sw struct
  * on success, otherwise returns NULL on failure.
  **/
-static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
+static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi,
+                                             bool lock_acquired)
 {
        struct i40e_vsi *main_vsi;
        u16 alloc_queue_pairs;
@@ -14314,7 +14315,10 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct 
i40e_vsi *vsi)
 err_netdev:
        if (vsi->netdev_registered) {
                vsi->netdev_registered = false;
-               unregister_netdev(vsi->netdev);
+               if (lock_acquired)
+                       unregister_netdevice(vsi->netdev);
+               else
+                       unregister_netdev(vsi->netdev);
                free_netdev(vsi->netdev);
                vsi->netdev = NULL;
        }
@@ -15036,7 +15040,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, 
bool reinit, bool lock_acqui
                        main_vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN,
                                                  uplink_seid, 0);
                else if (reinit)
-                       main_vsi = i40e_vsi_reinit_setup(main_vsi);
+                       main_vsi = i40e_vsi_reinit_setup(main_vsi, 
lock_acquired);
                if (!main_vsi) {
                        dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n");
                        i40e_cloud_filter_exit(pf);
-- 
2.43.0

Reply via email to