Skip to content

Commit 6faee3d

Browse files
f0rm2l1nkuba-moo
authored andcommitted
igb: Add lock to avoid data race
The commit c23d92b ("igb: Teardown SR-IOV before unregister_netdev()") places the unregister_netdev() call after the igb_disable_sriov() call to avoid functionality issue. However, it introduces several race conditions when detaching a device. For example, when .remove() is called, the below interleaving leads to use-after-free. (FREE from device detaching) | (USE from netdev core) igb_remove | igb_ndo_get_vf_config igb_disable_sriov | vf >= adapter->vfs_allocated_count? kfree(adapter->vf_data) | adapter->vfs_allocated_count = 0 | | memcpy(... adapter->vf_data[vf] Moreover, the igb_disable_sriov() also suffers from data race with the requests from VF driver. (FREE from device detaching) | (USE from requests) igb_remove | igb_msix_other igb_disable_sriov | igb_msg_task kfree(adapter->vf_data) | vf < adapter->vfs_allocated_count adapter->vfs_allocated_count = 0 | To this end, this commit first eliminates the data races from netdev core by using rtnl_lock (similar to commit 7194792 ("dpaa2-eth: add MAC/PHY support through phylink")). And then adds a spinlock to eliminate races from driver requests. (similar to commit 1e53834 ("ixgbe: Add locking to prevent panic when setting sriov_numvfs to zero") Fixes: c23d92b ("igb: Teardown SR-IOV before unregister_netdev()") Signed-off-by: Lin Ma <[email protected]> Tested-by: Konrad Jankowski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 138d186 commit 6faee3d

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

drivers/net/ethernet/intel/igb/igb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,8 @@ struct igb_adapter {
664664
struct igb_mac_addr *mac_table;
665665
struct vf_mac_filter vf_macs;
666666
struct vf_mac_filter *vf_mac_list;
667+
/* lock for VF resources */
668+
spinlock_t vfs_lock;
667669
};
668670

669671
/* flags controlling PTP/1588 function */

drivers/net/ethernet/intel/igb/igb_main.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,7 @@ static int igb_disable_sriov(struct pci_dev *pdev)
36373637
struct net_device *netdev = pci_get_drvdata(pdev);
36383638
struct igb_adapter *adapter = netdev_priv(netdev);
36393639
struct e1000_hw *hw = &adapter->hw;
3640+
unsigned long flags;
36403641

36413642
/* reclaim resources allocated to VFs */
36423643
if (adapter->vf_data) {
@@ -3649,12 +3650,13 @@ static int igb_disable_sriov(struct pci_dev *pdev)
36493650
pci_disable_sriov(pdev);
36503651
msleep(500);
36513652
}
3652-
3653+
spin_lock_irqsave(&adapter->vfs_lock, flags);
36533654
kfree(adapter->vf_mac_list);
36543655
adapter->vf_mac_list = NULL;
36553656
kfree(adapter->vf_data);
36563657
adapter->vf_data = NULL;
36573658
adapter->vfs_allocated_count = 0;
3659+
spin_unlock_irqrestore(&adapter->vfs_lock, flags);
36583660
wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
36593661
wrfl();
36603662
msleep(100);
@@ -3814,7 +3816,9 @@ static void igb_remove(struct pci_dev *pdev)
38143816
igb_release_hw_control(adapter);
38153817

38163818
#ifdef CONFIG_PCI_IOV
3819+
rtnl_lock();
38173820
igb_disable_sriov(pdev);
3821+
rtnl_unlock();
38183822
#endif
38193823

38203824
unregister_netdev(netdev);
@@ -3974,6 +3978,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
39743978

39753979
spin_lock_init(&adapter->nfc_lock);
39763980
spin_lock_init(&adapter->stats64_lock);
3981+
3982+
/* init spinlock to avoid concurrency of VF resources */
3983+
spin_lock_init(&adapter->vfs_lock);
39773984
#ifdef CONFIG_PCI_IOV
39783985
switch (hw->mac.type) {
39793986
case e1000_82576:
@@ -7958,8 +7965,10 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
79587965
static void igb_msg_task(struct igb_adapter *adapter)
79597966
{
79607967
struct e1000_hw *hw = &adapter->hw;
7968+
unsigned long flags;
79617969
u32 vf;
79627970

7971+
spin_lock_irqsave(&adapter->vfs_lock, flags);
79637972
for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
79647973
/* process any reset requests */
79657974
if (!igb_check_for_rst(hw, vf))
@@ -7973,6 +7982,7 @@ static void igb_msg_task(struct igb_adapter *adapter)
79737982
if (!igb_check_for_ack(hw, vf))
79747983
igb_rcv_ack_from_vf(adapter, vf);
79757984
}
7985+
spin_unlock_irqrestore(&adapter->vfs_lock, flags);
79767986
}
79777987

79787988
/**

0 commit comments

Comments
 (0)