> -----Original Message-----
> From: Intel-wired-lan <[email protected]> On Behalf
> Of Maciej Fijalkowski
> Sent: Wednesday, July 1, 2026 2:45 PM
> To: [email protected]
> Cc: [email protected]; Karlsson, Magnus
> <[email protected]>; [email protected]; [email protected];
> [email protected]; Kitszel, Przemyslaw <[email protected]>;
> Keller, Jacob E <[email protected]>; Fijalkowski, Maciej
> <[email protected]>; Sashiko AI Review <sashiko-
> [email protected]>
> Subject: [Intel-wired-lan] [PATCH v5 net 4/7] i40e: avoid deadlock
> when calling unregister_netdev()
> 
> 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


Reviewed-by: Aleksandr Loktionov <[email protected]>

Reply via email to