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 /drivers/net/ixgbe | |
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>
Diffstat (limited to 'drivers/net/ixgbe')
-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 | } |