igbvf: fix memory leak when ring size changed while interface down
Alexander Duyck [Mon, 26 Oct 2009 11:32:25 +0000 (11:32 +0000)]
This patch resolves a memory leak which occurs while changing the ring size
while the interface is down.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/igbvf/ethtool.c

index ee17a09..c68265b 100644 (file)
@@ -279,7 +279,7 @@ static int igbvf_set_ringparam(struct net_device *netdev,
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
        struct igbvf_ring *temp_ring;
-       int err;
+       int err = 0;
        u32 new_rx_count, new_tx_count;
 
        if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
@@ -299,15 +299,22 @@ static int igbvf_set_ringparam(struct net_device *netdev,
                return 0;
        }
 
-       temp_ring = vmalloc(sizeof(struct igbvf_ring));
-       if (!temp_ring)
-               return -ENOMEM;
-
        while (test_and_set_bit(__IGBVF_RESETTING, &adapter->state))
                msleep(1);
 
-       if (netif_running(adapter->netdev))
-               igbvf_down(adapter);
+       if (!netif_running(adapter->netdev)) {
+               adapter->tx_ring->count = new_tx_count;
+               adapter->rx_ring->count = new_rx_count;
+               goto clear_reset;
+       }
+
+       temp_ring = vmalloc(sizeof(struct igbvf_ring));
+       if (!temp_ring) {
+               err = -ENOMEM;
+               goto clear_reset;
+       }
+
+       igbvf_down(adapter);
 
        /*
         * We can't just free everything and then setup again,
@@ -339,14 +346,11 @@ static int igbvf_set_ringparam(struct net_device *netdev,
 
                memcpy(adapter->rx_ring, temp_ring,sizeof(struct igbvf_ring));
        }
-
-       err = 0;
 err_setup:
-       if (netif_running(adapter->netdev))
-               igbvf_up(adapter);
-
-       clear_bit(__IGBVF_RESETTING, &adapter->state);
+       igbvf_up(adapter);
        vfree(temp_ring);
+clear_reset:
+       clear_bit(__IGBVF_RESETTING, &adapter->state);
        return err;
 }