Commit bba50b99 authored by Greg Rose's avatar Greg Rose Committed by David S. Miller

ixgbevf: Refactor ring parameter re-size

The function to resize the Tx/Rx rings had the potential to
dereference a NULL pointer and the code would attempt to resize
the Tx ring even if the Rx ring allocation had failed.  This
would cause some confusion in the return code semantics.  Fixed
up to just unwind the allocations if any of them fail and return
an error.
Signed-off-by: default avatarGreg Rose <gregory.v.rose@intel.com>
Tested-by: default avatarEmil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 543876c9
...@@ -330,10 +330,8 @@ static int ixgbevf_set_ringparam(struct net_device *netdev, ...@@ -330,10 +330,8 @@ static int ixgbevf_set_ringparam(struct net_device *netdev,
{ {
struct ixgbevf_adapter *adapter = netdev_priv(netdev); struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL; struct ixgbevf_ring *tx_ring = NULL, *rx_ring = NULL;
int i, err; int i, err = 0;
u32 new_rx_count, new_tx_count; u32 new_rx_count, new_tx_count;
bool need_tx_update = false;
bool need_rx_update = false;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL; return -EINVAL;
...@@ -355,89 +353,96 @@ static int ixgbevf_set_ringparam(struct net_device *netdev, ...@@ -355,89 +353,96 @@ static int ixgbevf_set_ringparam(struct net_device *netdev,
while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state)) while (test_and_set_bit(__IXGBEVF_RESETTING, &adapter->state))
msleep(1); msleep(1);
if (new_tx_count != adapter->tx_ring_count) { /*
* If the adapter isn't up and running then just set the
* new parameters and scurry for the exits.
*/
if (!netif_running(adapter->netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++)
adapter->tx_ring[i].count = new_tx_count;
for (i = 0; i < adapter->num_rx_queues; i++)
adapter->rx_ring[i].count = new_rx_count;
adapter->tx_ring_count = new_tx_count;
adapter->rx_ring_count = new_rx_count;
goto clear_reset;
}
tx_ring = kcalloc(adapter->num_tx_queues, tx_ring = kcalloc(adapter->num_tx_queues,
sizeof(struct ixgbevf_ring), GFP_KERNEL); sizeof(struct ixgbevf_ring), GFP_KERNEL);
if (!tx_ring) { if (!tx_ring) {
err = -ENOMEM; err = -ENOMEM;
goto err_setup; goto clear_reset;
} }
rx_ring = kcalloc(adapter->num_rx_queues,
sizeof(struct ixgbevf_ring), GFP_KERNEL);
if (!rx_ring) {
err = -ENOMEM;
goto err_rx_setup;
}
ixgbevf_down(adapter);
memcpy(tx_ring, adapter->tx_ring, memcpy(tx_ring, adapter->tx_ring,
adapter->num_tx_queues * sizeof(struct ixgbevf_ring)); adapter->num_tx_queues * sizeof(struct ixgbevf_ring));
for (i = 0; i < adapter->num_tx_queues; i++) { for (i = 0; i < adapter->num_tx_queues; i++) {
tx_ring[i].count = new_tx_count; tx_ring[i].count = new_tx_count;
err = ixgbevf_setup_tx_resources(adapter, err = ixgbevf_setup_tx_resources(adapter, &tx_ring[i]);
&tx_ring[i]);
if (err) { if (err) {
while (i) { while (i) {
i--; i--;
ixgbevf_free_tx_resources(adapter, ixgbevf_free_tx_resources(adapter,
&tx_ring[i]); &tx_ring[i]);
} }
kfree(tx_ring); goto err_tx_ring_setup;
goto err_setup;
} }
tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
} }
need_tx_update = true;
}
if (new_rx_count != adapter->rx_ring_count) {
rx_ring = kcalloc(adapter->num_rx_queues,
sizeof(struct ixgbevf_ring), GFP_KERNEL);
if ((!rx_ring) && (need_tx_update)) {
err = -ENOMEM;
goto err_rx_setup;
}
memcpy(rx_ring, adapter->rx_ring, memcpy(rx_ring, adapter->rx_ring,
adapter->num_rx_queues * sizeof(struct ixgbevf_ring)); adapter->num_rx_queues * sizeof(struct ixgbevf_ring));
for (i = 0; i < adapter->num_rx_queues; i++) { for (i = 0; i < adapter->num_rx_queues; i++) {
rx_ring[i].count = new_rx_count; rx_ring[i].count = new_rx_count;
err = ixgbevf_setup_rx_resources(adapter, err = ixgbevf_setup_rx_resources(adapter, &rx_ring[i]);
&rx_ring[i]);
if (err) { if (err) {
while (i) { while (i) {
i--; i--;
ixgbevf_free_rx_resources(adapter, ixgbevf_free_rx_resources(adapter,
&rx_ring[i]); &rx_ring[i]);
} }
kfree(rx_ring); goto err_rx_ring_setup;
goto err_rx_setup;
} }
rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
} }
need_rx_update = true;
}
err_rx_setup: /*
/* if rings need to be updated, here's the place to do it in one shot */ * Only switch to new rings if all the prior allocations
if (need_tx_update || need_rx_update) { * and ring setups have succeeded.
if (netif_running(netdev)) */
ixgbevf_down(adapter);
}
/* tx */
if (need_tx_update) {
kfree(adapter->tx_ring); kfree(adapter->tx_ring);
adapter->tx_ring = tx_ring; adapter->tx_ring = tx_ring;
tx_ring = NULL;
adapter->tx_ring_count = new_tx_count; adapter->tx_ring_count = new_tx_count;
}
/* rx */
if (need_rx_update) {
kfree(adapter->rx_ring); kfree(adapter->rx_ring);
adapter->rx_ring = rx_ring; adapter->rx_ring = rx_ring;
rx_ring = NULL;
adapter->rx_ring_count = new_rx_count; adapter->rx_ring_count = new_rx_count;
}
/* success! */ /* success! */
err = 0;
if (netif_running(netdev))
ixgbevf_up(adapter); ixgbevf_up(adapter);
err_setup: goto clear_reset;
err_rx_ring_setup:
for(i = 0; i < adapter->num_tx_queues; i++)
ixgbevf_free_tx_resources(adapter, &tx_ring[i]);
err_tx_ring_setup:
kfree(rx_ring);
err_rx_setup:
kfree(tx_ring);
clear_reset:
clear_bit(__IXGBEVF_RESETTING, &adapter->state); clear_bit(__IXGBEVF_RESETTING, &adapter->state);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment