lkml.org 
[lkml]   [2022]   [Mar]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 230/262] iavf: Add waiting so the port is initialized in remove
    Date
    From: Slawomir Laba <slawomirx.laba@intel.com>

    [ Upstream commit 974578017fc1fdd06cea8afb9dfa32602e8529ed ]

    There exist races when port is being configured and remove is
    triggered.

    unregister_netdev is not and can't be called under crit_lock
    mutex since it is calling ndo_stop -> iavf_close which requires
    this lock. Depending on init state the netdev could be still
    unregistered so unregister_netdev never cleans up, when shortly
    after that the device could become registered.

    Make iavf_remove wait until port finishes initialization.
    All critical state changes are atomic (under crit_lock).
    Crashes that come from iavf_reset_interrupt_capability and
    iavf_free_traffic_irqs should now be solved in a graceful
    manner.

    Fixes: 605ca7c5c6707 ("iavf: Fix kernel BUG in free_msi_irqs")
    Signed-off-by: Slawomir Laba <slawomirx.laba@intel.com>
    Signed-off-by: Phani Burra <phani.r.burra@intel.com>
    Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
    Signed-off-by: Mateusz Palczewski <mateusz.palczewski@intel.com>
    Tested-by: Konrad Jankowski <konrad0.jankowski@intel.com>
    Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/net/ethernet/intel/iavf/iavf_main.c | 27 ++++++++++++---------
    1 file changed, 16 insertions(+), 11 deletions(-)

    diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
    index e97a8dbbbc89..60e6f55c6dc5 100644
    --- a/drivers/net/ethernet/intel/iavf/iavf_main.c
    +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
    @@ -3979,7 +3979,6 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
    static void iavf_remove(struct pci_dev *pdev)
    {
    struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
    - enum iavf_state_t prev_state = adapter->last_state;
    struct net_device *netdev = adapter->netdev;
    struct iavf_fdir_fltr *fdir, *fdirtmp;
    struct iavf_vlan_filter *vlf, *vlftmp;
    @@ -3989,6 +3988,22 @@ static void iavf_remove(struct pci_dev *pdev)
    struct iavf_hw *hw = &adapter->hw;
    int err;

    + /* Wait until port initialization is complete.
    + * There are flows where register/unregister netdev may race.
    + */
    + while (1) {
    + mutex_lock(&adapter->crit_lock);
    + if (adapter->state == __IAVF_RUNNING ||
    + adapter->state == __IAVF_DOWN) {
    + mutex_unlock(&adapter->crit_lock);
    + break;
    + }
    +
    + mutex_unlock(&adapter->crit_lock);
    + usleep_range(500, 1000);
    + }
    + cancel_delayed_work_sync(&adapter->watchdog_task);
    +
    if (adapter->netdev_registered) {
    unregister_netdev(netdev);
    adapter->netdev_registered = false;
    @@ -4026,16 +4041,6 @@ static void iavf_remove(struct pci_dev *pdev)
    iavf_free_all_rx_resources(adapter);
    iavf_free_misc_irq(adapter);

    - /* In case we enter iavf_remove from erroneous state, free traffic irqs
    - * here, so as to not cause a kernel crash, when calling
    - * iavf_reset_interrupt_capability.
    - */
    - if ((adapter->last_state == __IAVF_RESETTING &&
    - prev_state != __IAVF_DOWN) ||
    - (adapter->last_state == __IAVF_RUNNING &&
    - !(netdev->flags & IFF_UP)))
    - iavf_free_traffic_irqs(adapter);
    -
    iavf_reset_interrupt_capability(adapter);
    iavf_free_q_vectors(adapter);

    --
    2.34.1


    \
     
     \ /
      Last update: 2022-03-07 11:17    [W:4.088 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site