diff options
author | Mitch Williams <mitch.a.williams@intel.com> | 2014-08-01 16:27:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-02 22:41:15 -0400 |
commit | 6ba36a246ef58100ff3f31b0738e317cfab1f240 (patch) | |
tree | 4562184f83685780216c78940ec372ff53fd1520 /drivers/net/ethernet/intel | |
parent | d31944d6f0872ba9536501c4850dfb20dea5bf64 (diff) |
i40evf: fix memory leak on unused interfaces
If the driver is loaded and then unloaded before the interface is
brought up, then it will allocate a MAC filter entry and never free it.
To fix this, on unload, run through the mac filter list and free all the
entries. We also do this during reset recovery when the driver cannot
contact the PF and needs to shut down completely.
Change-ID: I15fabd67eb4a1bfc57605a7db60d0b5d819839db
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Sibai Li <sibai.li@intel.com>
Signed-off-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/intel')
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40evf_main.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 0c4f7baffad6..e5679d82e0c0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c | |||
@@ -1527,6 +1527,9 @@ static void i40evf_reset_task(struct work_struct *work) | |||
1527 | msleep(I40EVF_RESET_WAIT_MS); | 1527 | msleep(I40EVF_RESET_WAIT_MS); |
1528 | } | 1528 | } |
1529 | if (i == I40EVF_RESET_WAIT_COUNT) { | 1529 | if (i == I40EVF_RESET_WAIT_COUNT) { |
1530 | struct i40evf_mac_filter *f, *ftmp; | ||
1531 | struct i40evf_vlan_filter *fv, *fvtmp; | ||
1532 | |||
1530 | /* reset never finished */ | 1533 | /* reset never finished */ |
1531 | dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", | 1534 | dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", |
1532 | rstat_val); | 1535 | rstat_val); |
@@ -1539,6 +1542,19 @@ static void i40evf_reset_task(struct work_struct *work) | |||
1539 | i40evf_free_all_tx_resources(adapter); | 1542 | i40evf_free_all_tx_resources(adapter); |
1540 | i40evf_free_all_rx_resources(adapter); | 1543 | i40evf_free_all_rx_resources(adapter); |
1541 | } | 1544 | } |
1545 | |||
1546 | /* Delete all of the filters, both MAC and VLAN. */ | ||
1547 | list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, | ||
1548 | list) { | ||
1549 | list_del(&f->list); | ||
1550 | kfree(f); | ||
1551 | } | ||
1552 | list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, | ||
1553 | list) { | ||
1554 | list_del(&fv->list); | ||
1555 | kfree(fv); | ||
1556 | } | ||
1557 | |||
1542 | i40evf_free_misc_irq(adapter); | 1558 | i40evf_free_misc_irq(adapter); |
1543 | i40evf_reset_interrupt_capability(adapter); | 1559 | i40evf_reset_interrupt_capability(adapter); |
1544 | i40evf_free_queues(adapter); | 1560 | i40evf_free_queues(adapter); |
@@ -2415,6 +2431,7 @@ static void i40evf_remove(struct pci_dev *pdev) | |||
2415 | { | 2431 | { |
2416 | struct net_device *netdev = pci_get_drvdata(pdev); | 2432 | struct net_device *netdev = pci_get_drvdata(pdev); |
2417 | struct i40evf_adapter *adapter = netdev_priv(netdev); | 2433 | struct i40evf_adapter *adapter = netdev_priv(netdev); |
2434 | struct i40evf_mac_filter *f, *ftmp; | ||
2418 | struct i40e_hw *hw = &adapter->hw; | 2435 | struct i40e_hw *hw = &adapter->hw; |
2419 | 2436 | ||
2420 | cancel_delayed_work_sync(&adapter->init_task); | 2437 | cancel_delayed_work_sync(&adapter->init_task); |
@@ -2446,6 +2463,13 @@ static void i40evf_remove(struct pci_dev *pdev) | |||
2446 | 2463 | ||
2447 | i40evf_free_queues(adapter); | 2464 | i40evf_free_queues(adapter); |
2448 | kfree(adapter->vf_res); | 2465 | kfree(adapter->vf_res); |
2466 | /* If we got removed before an up/down sequence, we've got a filter | ||
2467 | * hanging out there that we need to get rid of. | ||
2468 | */ | ||
2469 | list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { | ||
2470 | list_del(&f->list); | ||
2471 | kfree(f); | ||
2472 | } | ||
2449 | 2473 | ||
2450 | free_netdev(netdev); | 2474 | free_netdev(netdev); |
2451 | 2475 | ||