diff options
author | Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> | 2008-12-26 04:36:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-26 04:36:33 -0500 |
commit | d3fa4721456226d77475181a4bfbe5b3d899d65c (patch) | |
tree | a602610942cadbe5e44aa7549d0622bdb47730bf /drivers/net/ixgbe | |
parent | 7adf1525befb5606462431eb1a4ea40ded5baef4 (diff) |
ixgbe: Fix set_ringparam in ixgbe to use the same memory pools.
The adapter rings are kcalloc()'d, but in set_ringparam() in ixgbe_ethtool,
we replace that memory from the vmalloc() pool. This can result in a NULL
pointer reference when trying to modify the rings at a later time, or on
device removal.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ixgbe')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 64 |
1 files changed, 30 insertions, 34 deletions
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 849c1fe28207..67f87a79154d 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
@@ -712,30 +712,15 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
712 | return 0; | 712 | return 0; |
713 | } | 713 | } |
714 | 714 | ||
715 | if (adapter->num_tx_queues > adapter->num_rx_queues) | 715 | temp_ring = kcalloc(adapter->num_tx_queues, |
716 | temp_ring = vmalloc(adapter->num_tx_queues * | 716 | sizeof(struct ixgbe_ring), GFP_KERNEL); |
717 | sizeof(struct ixgbe_ring)); | ||
718 | else | ||
719 | temp_ring = vmalloc(adapter->num_rx_queues * | ||
720 | sizeof(struct ixgbe_ring)); | ||
721 | if (!temp_ring) | 717 | if (!temp_ring) |
722 | return -ENOMEM; | 718 | return -ENOMEM; |
723 | 719 | ||
724 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) | 720 | while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) |
725 | msleep(1); | 721 | msleep(1); |
726 | 722 | ||
727 | if (netif_running(netdev)) | ||
728 | ixgbe_down(adapter); | ||
729 | |||
730 | /* | ||
731 | * We can't just free everything and then setup again, | ||
732 | * because the ISRs in MSI-X mode get passed pointers | ||
733 | * to the tx and rx ring structs. | ||
734 | */ | ||
735 | if (new_tx_count != adapter->tx_ring->count) { | 723 | if (new_tx_count != adapter->tx_ring->count) { |
736 | memcpy(temp_ring, adapter->tx_ring, | ||
737 | adapter->num_tx_queues * sizeof(struct ixgbe_ring)); | ||
738 | |||
739 | for (i = 0; i < adapter->num_tx_queues; i++) { | 724 | for (i = 0; i < adapter->num_tx_queues; i++) { |
740 | temp_ring[i].count = new_tx_count; | 725 | temp_ring[i].count = new_tx_count; |
741 | err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); | 726 | err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); |
@@ -747,21 +732,28 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
747 | } | 732 | } |
748 | goto err_setup; | 733 | goto err_setup; |
749 | } | 734 | } |
735 | temp_ring[i].v_idx = adapter->tx_ring[i].v_idx; | ||
750 | } | 736 | } |
751 | 737 | if (netif_running(netdev)) | |
752 | for (i = 0; i < adapter->num_tx_queues; i++) | 738 | netdev->netdev_ops->ndo_stop(netdev); |
753 | ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); | 739 | ixgbe_reset_interrupt_capability(adapter); |
754 | 740 | ixgbe_napi_del_all(adapter); | |
755 | memcpy(adapter->tx_ring, temp_ring, | 741 | INIT_LIST_HEAD(&netdev->napi_list); |
756 | adapter->num_tx_queues * sizeof(struct ixgbe_ring)); | 742 | kfree(adapter->tx_ring); |
757 | 743 | adapter->tx_ring = temp_ring; | |
744 | temp_ring = NULL; | ||
758 | adapter->tx_ring_count = new_tx_count; | 745 | adapter->tx_ring_count = new_tx_count; |
759 | } | 746 | } |
760 | 747 | ||
761 | if (new_rx_count != adapter->rx_ring->count) { | 748 | temp_ring = kcalloc(adapter->num_rx_queues, |
762 | memcpy(temp_ring, adapter->rx_ring, | 749 | sizeof(struct ixgbe_ring), GFP_KERNEL); |
763 | adapter->num_rx_queues * sizeof(struct ixgbe_ring)); | 750 | if (!temp_ring) { |
751 | if (netif_running(netdev)) | ||
752 | netdev->netdev_ops->ndo_open(netdev); | ||
753 | return -ENOMEM; | ||
754 | } | ||
764 | 755 | ||
756 | if (new_rx_count != adapter->rx_ring->count) { | ||
765 | for (i = 0; i < adapter->num_rx_queues; i++) { | 757 | for (i = 0; i < adapter->num_rx_queues; i++) { |
766 | temp_ring[i].count = new_rx_count; | 758 | temp_ring[i].count = new_rx_count; |
767 | err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); | 759 | err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); |
@@ -773,13 +765,16 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
773 | } | 765 | } |
774 | goto err_setup; | 766 | goto err_setup; |
775 | } | 767 | } |
768 | temp_ring[i].v_idx = adapter->rx_ring[i].v_idx; | ||
776 | } | 769 | } |
777 | 770 | if (netif_running(netdev)) | |
778 | for (i = 0; i < adapter->num_rx_queues; i++) | 771 | netdev->netdev_ops->ndo_stop(netdev); |
779 | ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); | 772 | ixgbe_reset_interrupt_capability(adapter); |
780 | 773 | ixgbe_napi_del_all(adapter); | |
781 | memcpy(adapter->rx_ring, temp_ring, | 774 | INIT_LIST_HEAD(&netdev->napi_list); |
782 | adapter->num_rx_queues * sizeof(struct ixgbe_ring)); | 775 | kfree(adapter->rx_ring); |
776 | adapter->rx_ring = temp_ring; | ||
777 | temp_ring = NULL; | ||
783 | 778 | ||
784 | adapter->rx_ring_count = new_rx_count; | 779 | adapter->rx_ring_count = new_rx_count; |
785 | } | 780 | } |
@@ -787,8 +782,9 @@ static int ixgbe_set_ringparam(struct net_device *netdev, | |||
787 | /* success! */ | 782 | /* success! */ |
788 | err = 0; | 783 | err = 0; |
789 | err_setup: | 784 | err_setup: |
785 | ixgbe_init_interrupt_scheme(adapter); | ||
790 | if (netif_running(netdev)) | 786 | if (netif_running(netdev)) |
791 | ixgbe_up(adapter); | 787 | netdev->netdev_ops->ndo_open(netdev); |
792 | 788 | ||
793 | clear_bit(__IXGBE_RESETTING, &adapter->state); | 789 | clear_bit(__IXGBE_RESETTING, &adapter->state); |
794 | return err; | 790 | return err; |