diff options
| author | Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com> | 2009-03-31 17:35:24 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-04-02 04:02:33 -0400 |
| commit | f9ed88549e2ec73922b788e3865282d221233662 (patch) | |
| tree | 1e7aa52d8022d8b328b5a9efde25a42a66431991 | |
| parent | 71fd570b23ee74bca052beb9e88f8f57fb668ac7 (diff) | |
ixgbe: Fix potential memory leak/driver panic issue while setting up Tx & Rx ring parameters
While setting up the ring parameters using ethtool the driver can
panic or leak memory as ixgbe_open tries to setup tx & rx resources.
The updated logic will use ixgbe_down/up after successful allocation of
tx & rx resources
Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
CC: stable@kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 101 |
1 files changed, 58 insertions, 43 deletions
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 55970ec72de3..aafc120f164e 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
| @@ -734,9 +734,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
| 734 | struct ethtool_ringparam *ring) | 734 | struct ethtool_ringparam *ring) |
| 735 | { | 735 | { |
| 736 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | 736 | struct ixgbe_adapter *adapter = netdev_priv(netdev); |
| 737 | struct ixgbe_ring *temp_ring; | 737 | struct ixgbe_ring *temp_tx_ring, *temp_rx_ring; |
| 738 | int i, err; | 738 | int i, err; |
| 739 | u32 new_rx_count, new_tx_count; | 739 | u32 new_rx_count, new_tx_count; |
| 740 | bool need_update = false; | ||
| 740 | 741 | ||
| 741 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 742 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) |
| 742 | return -EINVAL; | 743 | return -EINVAL; |
| @@ -755,80 +756,94 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
| 755 | return 0; | 756 | return 0; |
| 756 | } | 757 | } |
| 757 | 758 | ||
| 758 | temp_ring = kcalloc(adapter->num_tx_queues, | ||
| 759 | sizeof(struct ixgbe_ring), GFP_KERNEL); | ||
| 760 | if (!temp_ring) | ||
| 761 | return -ENOMEM; | ||
| 762 | |||
| 763 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) | 759 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) |
| 764 | msleep(1); | 760 | msleep(1); |
| 765 | 761 | ||
| 766 | if (new_tx_count != adapter->tx_ring->count) { | 762 | temp_tx_ring = kcalloc(adapter->num_tx_queues, |
| 763 | sizeof(struct ixgbe_ring), GFP_KERNEL); | ||
| 764 | if (!temp_tx_ring) { | ||
| 765 | err = -ENOMEM; | ||
| 766 | goto err_setup; | ||
| 767 | } | ||
| 768 | |||
| 769 | if (new_tx_count != adapter->tx_ring_count) { | ||
| 770 | memcpy(temp_tx_ring, adapter->tx_ring, | ||
| 771 | adapter->num_tx_queues * sizeof(struct ixgbe_ring)); | ||
| 767 | for (i = 0; i < adapter->num_tx_queues; i++) { | 772 | for (i = 0; i < adapter->num_tx_queues; i++) { |
| 768 | temp_ring[i].count = new_tx_count; | 773 | temp_tx_ring[i].count = new_tx_count; |
| 769 | err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); | 774 | err = ixgbe_setup_tx_resources(adapter, |
| 775 | &temp_tx_ring[i]); | ||
| 770 | if (err) { | 776 | if (err) { |
| 771 | while (i) { | 777 | while (i) { |
| 772 | i--; | 778 | i--; |
| 773 | ixgbe_free_tx_resources(adapter, | 779 | ixgbe_free_tx_resources(adapter, |
| 774 | &temp_ring[i]); | 780 | &temp_tx_ring[i]); |
| 775 | } | 781 | } |
| 776 | goto err_setup; | 782 | goto err_setup; |
| 777 | } | 783 | } |
| 778 | temp_ring[i].v_idx = adapter->tx_ring[i].v_idx; | 784 | temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; |
| 779 | } | 785 | } |
| 780 | if (netif_running(netdev)) | 786 | need_update = true; |
| 781 | netdev->netdev_ops->ndo_stop(netdev); | ||
| 782 | ixgbe_reset_interrupt_capability(adapter); | ||
| 783 | ixgbe_napi_del_all(adapter); | ||
| 784 | INIT_LIST_HEAD(&netdev->napi_list); | ||
| 785 | kfree(adapter->tx_ring); | ||
| 786 | adapter->tx_ring = temp_ring; | ||
| 787 | temp_ring = NULL; | ||
| 788 | adapter->tx_ring_count = new_tx_count; | ||
| 789 | } | 787 | } |
| 790 | 788 | ||
| 791 | temp_ring = kcalloc(adapter->num_rx_queues, | 789 | temp_rx_ring = kcalloc(adapter->num_rx_queues, |
| 792 | sizeof(struct ixgbe_ring), GFP_KERNEL); | 790 | sizeof(struct ixgbe_ring), GFP_KERNEL); |
| 793 | if (!temp_ring) { | 791 | if ((!temp_rx_ring) && (need_update)) { |
| 794 | if (netif_running(netdev)) | 792 | for (i = 0; i < adapter->num_tx_queues; i++) |
| 795 | netdev->netdev_ops->ndo_open(netdev); | 793 | ixgbe_free_tx_resources(adapter, &temp_tx_ring[i]); |
| 796 | return -ENOMEM; | 794 | kfree(temp_tx_ring); |
| 795 | err = -ENOMEM; | ||
| 796 | goto err_setup; | ||
| 797 | } | 797 | } |
| 798 | 798 | ||
| 799 | if (new_rx_count != adapter->rx_ring->count) { | 799 | if (new_rx_count != adapter->rx_ring_count) { |
| 800 | memcpy(temp_rx_ring, adapter->rx_ring, | ||
| 801 | adapter->num_rx_queues * sizeof(struct ixgbe_ring)); | ||
| 800 | for (i = 0; i < adapter->num_rx_queues; i++) { | 802 | for (i = 0; i < adapter->num_rx_queues; i++) { |
| 801 | temp_ring[i].count = new_rx_count; | 803 | temp_rx_ring[i].count = new_rx_count; |
| 802 | err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); | 804 | err = ixgbe_setup_rx_resources(adapter, |
| 805 | &temp_rx_ring[i]); | ||
| 803 | if (err) { | 806 | if (err) { |
| 804 | while (i) { | 807 | while (i) { |
| 805 | i--; | 808 | i--; |
| 806 | ixgbe_free_rx_resources(adapter, | 809 | ixgbe_free_rx_resources(adapter, |
| 807 | &temp_ring[i]); | 810 | &temp_rx_ring[i]); |
| 808 | } | 811 | } |
| 809 | goto err_setup; | 812 | goto err_setup; |
| 810 | } | 813 | } |
| 811 | temp_ring[i].v_idx = adapter->rx_ring[i].v_idx; | 814 | temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; |
| 812 | } | 815 | } |
| 816 | need_update = true; | ||
| 817 | } | ||
| 818 | |||
| 819 | /* if rings need to be updated, here's the place to do it in one shot */ | ||
| 820 | if (need_update) { | ||
| 813 | if (netif_running(netdev)) | 821 | if (netif_running(netdev)) |
| 814 | netdev->netdev_ops->ndo_stop(netdev); | 822 | ixgbe_down(adapter); |
| 815 | ixgbe_reset_interrupt_capability(adapter); | 823 | |
| 816 | ixgbe_napi_del_all(adapter); | 824 | /* tx */ |
| 817 | INIT_LIST_HEAD(&netdev->napi_list); | 825 | if (new_tx_count != adapter->tx_ring_count) { |
| 818 | kfree(adapter->rx_ring); | 826 | kfree(adapter->tx_ring); |
| 819 | adapter->rx_ring = temp_ring; | 827 | adapter->tx_ring = temp_tx_ring; |
| 820 | temp_ring = NULL; | 828 | temp_tx_ring = NULL; |
| 821 | 829 | adapter->tx_ring_count = new_tx_count; | |
| 822 | adapter->rx_ring_count = new_rx_count; | 830 | } |
| 831 | |||
| 832 | /* rx */ | ||
| 833 | if (new_rx_count != adapter->rx_ring_count) { | ||
| 834 | kfree(adapter->rx_ring); | ||
| 835 | adapter->rx_ring = temp_rx_ring; | ||
| 836 | temp_rx_ring = NULL; | ||
| 837 | adapter->rx_ring_count = new_rx_count; | ||
| 838 | } | ||
| 823 | } | 839 | } |
| 824 | 840 | ||
| 825 | /* success! */ | 841 | /* success! */ |
| 826 | err = 0; | 842 | err = 0; |
| 827 | err_setup: | ||
| 828 | ixgbe_init_interrupt_scheme(adapter); | ||
| 829 | if (netif_running(netdev)) | 843 | if (netif_running(netdev)) |
| 830 | netdev->netdev_ops->ndo_open(netdev); | 844 | ixgbe_up(adapter); |
| 831 | 845 | ||
| 846 | err_setup: | ||
| 832 | clear_bit(__IXGBE_RESETTING, &adapter->state); | 847 | clear_bit(__IXGBE_RESETTING, &adapter->state); |
| 833 | return err; | 848 | return err; |
| 834 | } | 849 | } |
