i40e_vsi_reinit_setup() tears down the existing VSI queue/ring backing
state before allocating replacement arrays and queue tracking. If one of
these early allocations fails, the function jumps directly to err_vsi
and calls i40e_vsi_clear().

For a registered netdev, this frees the VSI while
netdev_priv(netdev)->vsi can still point at it, leaving the registered
netdev with dangling private driver state.

Split the error path so failures after destructive reinit teardown first
unregister and free the netdev before clearing the VSI.

Fixes: d2a69fefd756 ("i40e: Fix changing previously set num_queue_pairs for 
PFs")
Signed-off-by: Maciej Fijalkowski <[email protected]>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a04683004a56..471fa7f7b643 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -14274,7 +14274,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct 
i40e_vsi *vsi)
        i40e_set_num_rings_in_vsi(vsi);
        ret = i40e_vsi_alloc_arrays(vsi, false);
        if (ret)
-               goto err_vsi;
+               goto err_netdev;
 
        alloc_queue_pairs = vsi->alloc_queue_pairs *
                            (i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
@@ -14284,7 +14284,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct 
i40e_vsi *vsi)
                dev_info(&pf->pdev->dev,
                         "failed to get tracking for %d queues for VSI %d err 
%d\n",
                         alloc_queue_pairs, vsi->seid, ret);
-               goto err_vsi;
+               goto err_netdev;
        }
        vsi->base_queue = ret;
 
@@ -14309,6 +14309,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct 
i40e_vsi *vsi)
 
 err_rings:
        i40e_vsi_free_q_vectors(vsi);
+err_netdev:
        if (vsi->netdev_registered) {
                vsi->netdev_registered = false;
                unregister_netdev(vsi->netdev);
@@ -14318,7 +14319,6 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct 
i40e_vsi *vsi)
        if (vsi->type == I40E_VSI_MAIN)
                i40e_devlink_destroy_port(pf);
        i40e_aq_delete_element(&pf->hw, vsi->seid, NULL);
-err_vsi:
        i40e_vsi_clear(vsi);
        return NULL;
 }
-- 
2.43.0

Reply via email to