From: Emil Tantilov Date: Fri, 11 Nov 2016 18:12:51 +0000 (-0800) Subject: ixgbevf: handle race between close and suspend on shutdown X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=2dad7b2775ea030c898fe4946971edd25af237d1;p=openwrt%2Fstaging%2Fblogic.git ixgbevf: handle race between close and suspend on shutdown When an interface is part of a namespace it is possible that ixgbevf_close() may be called while ixgbevf_suspend() is running which ends up in a double free WARN and/or a BUG in free_msi_irqs() To handle this situation we extend the rtnl_lock() to protect the call to netif_device_detach() and check for !netif_device_present() to avoid entering close while in suspend. Also added rtnl locks to ixgbevf_queue_reset_subtask(). CC: Alexander Duyck Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 6d4bef5803f2..8574f212a67e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3242,6 +3242,9 @@ int ixgbevf_close(struct net_device *netdev) { struct ixgbevf_adapter *adapter = netdev_priv(netdev); + if (!netif_device_present(netdev)) + return 0; + ixgbevf_down(adapter); ixgbevf_free_irq(adapter); @@ -3268,6 +3271,8 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter) * match packet buffer alignment. Unfortunately, the * hardware is not flexible enough to do this dynamically. */ + rtnl_lock(); + if (netif_running(dev)) ixgbevf_close(dev); @@ -3276,6 +3281,8 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter) if (netif_running(dev)) ixgbevf_open(dev); + + rtnl_unlock(); } static void ixgbevf_tx_ctxtdesc(struct ixgbevf_ring *tx_ring, @@ -3796,17 +3803,17 @@ static int ixgbevf_suspend(struct pci_dev *pdev, pm_message_t state) int retval = 0; #endif + rtnl_lock(); netif_device_detach(netdev); if (netif_running(netdev)) { - rtnl_lock(); ixgbevf_down(adapter); ixgbevf_free_irq(adapter); ixgbevf_free_all_tx_resources(adapter); ixgbevf_free_all_rx_resources(adapter); ixgbevf_clear_interrupt_scheme(adapter); - rtnl_unlock(); } + rtnl_unlock(); #ifdef CONFIG_PM retval = pci_save_state(pdev);