Skip to content

Commit 1f4702a

Browse files
Alexander DuyckJeff Kirsher
authored andcommitted
ixgbe: Fix possible memory leak in ixgbe_set_ringparam
We were not correctly freeing the temporary rings on error in ixgbe_set_ring_param. In order to correct this I am unwinding a number of changes that were made in order to get things back to the original working form with modification for the current ring layouts. This approach has multiple advantages including a smaller memory footprint, and the fact that the interface is stopped while we are allocating the rings meaning that there is less potential for some sort of memory corruption on the ring. The only disadvantage I see with this approach is that on a Rx allocation failure we will report an error and only update the Tx rings. However the adapter should be fully functional in this state and the likelihood of such an error is very low. In addition it is not unreasonable to expect the user to need to recheck the ring configuration should they experience an error setting the ring sizes. Signed-off-by: Alexander Duyck <[email protected]> Tested-by: Phil Schmitt <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent de52a12 commit 1f4702a

File tree

1 file changed

+50
-52
lines changed

1 file changed

+50
-52
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -887,24 +887,23 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
887887
struct ethtool_ringparam *ring)
888888
{
889889
struct ixgbe_adapter *adapter = netdev_priv(netdev);
890-
struct ixgbe_ring *temp_tx_ring, *temp_rx_ring;
890+
struct ixgbe_ring *temp_ring;
891891
int i, err = 0;
892892
u32 new_rx_count, new_tx_count;
893-
bool need_update = false;
894893

895894
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
896895
return -EINVAL;
897896

898-
new_rx_count = max_t(u32, ring->rx_pending, IXGBE_MIN_RXD);
899-
new_rx_count = min_t(u32, new_rx_count, IXGBE_MAX_RXD);
900-
new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
901-
902-
new_tx_count = max_t(u32, ring->tx_pending, IXGBE_MIN_TXD);
903-
new_tx_count = min_t(u32, new_tx_count, IXGBE_MAX_TXD);
897+
new_tx_count = clamp_t(u32, ring->tx_pending,
898+
IXGBE_MIN_TXD, IXGBE_MAX_TXD);
904899
new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
905900

906-
if ((new_tx_count == adapter->tx_ring[0]->count) &&
907-
(new_rx_count == adapter->rx_ring[0]->count)) {
901+
new_rx_count = clamp_t(u32, ring->rx_pending,
902+
IXGBE_MIN_RXD, IXGBE_MAX_RXD);
903+
new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
904+
905+
if ((new_tx_count == adapter->tx_ring_count) &&
906+
(new_rx_count == adapter->rx_ring_count)) {
908907
/* nothing to do */
909908
return 0;
910909
}
@@ -922,81 +921,80 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
922921
goto clear_reset;
923922
}
924923

925-
temp_tx_ring = vmalloc(adapter->num_tx_queues * sizeof(struct ixgbe_ring));
926-
if (!temp_tx_ring) {
924+
/* allocate temporary buffer to store rings in */
925+
i = max_t(int, adapter->num_tx_queues, adapter->num_rx_queues);
926+
temp_ring = vmalloc(i * sizeof(struct ixgbe_ring));
927+
928+
if (!temp_ring) {
927929
err = -ENOMEM;
928930
goto clear_reset;
929931
}
930932

933+
ixgbe_down(adapter);
934+
935+
/*
936+
* Setup new Tx resources and free the old Tx resources in that order.
937+
* We can then assign the new resources to the rings via a memcpy.
938+
* The advantage to this approach is that we are guaranteed to still
939+
* have resources even in the case of an allocation failure.
940+
*/
931941
if (new_tx_count != adapter->tx_ring_count) {
932942
for (i = 0; i < adapter->num_tx_queues; i++) {
933-
memcpy(&temp_tx_ring[i], adapter->tx_ring[i],
943+
memcpy(&temp_ring[i], adapter->tx_ring[i],
934944
sizeof(struct ixgbe_ring));
935-
temp_tx_ring[i].count = new_tx_count;
936-
err = ixgbe_setup_tx_resources(&temp_tx_ring[i]);
945+
946+
temp_ring[i].count = new_tx_count;
947+
err = ixgbe_setup_tx_resources(&temp_ring[i]);
937948
if (err) {
938949
while (i) {
939950
i--;
940-
ixgbe_free_tx_resources(&temp_tx_ring[i]);
951+
ixgbe_free_tx_resources(&temp_ring[i]);
941952
}
942-
goto clear_reset;
953+
goto err_setup;
943954
}
944955
}
945-
need_update = true;
946-
}
947956

948-
temp_rx_ring = vmalloc(adapter->num_rx_queues * sizeof(struct ixgbe_ring));
949-
if (!temp_rx_ring) {
950-
err = -ENOMEM;
951-
goto err_setup;
957+
for (i = 0; i < adapter->num_tx_queues; i++) {
958+
ixgbe_free_tx_resources(adapter->tx_ring[i]);
959+
960+
memcpy(adapter->tx_ring[i], &temp_ring[i],
961+
sizeof(struct ixgbe_ring));
962+
}
963+
964+
adapter->tx_ring_count = new_tx_count;
952965
}
953966

967+
/* Repeat the process for the Rx rings if needed */
954968
if (new_rx_count != adapter->rx_ring_count) {
955969
for (i = 0; i < adapter->num_rx_queues; i++) {
956-
memcpy(&temp_rx_ring[i], adapter->rx_ring[i],
970+
memcpy(&temp_ring[i], adapter->rx_ring[i],
957971
sizeof(struct ixgbe_ring));
958-
temp_rx_ring[i].count = new_rx_count;
959-
err = ixgbe_setup_rx_resources(&temp_rx_ring[i]);
972+
973+
temp_ring[i].count = new_rx_count;
974+
err = ixgbe_setup_rx_resources(&temp_ring[i]);
960975
if (err) {
961976
while (i) {
962977
i--;
963-
ixgbe_free_rx_resources(&temp_rx_ring[i]);
978+
ixgbe_free_rx_resources(&temp_ring[i]);
964979
}
965980
goto err_setup;
966981
}
982+
967983
}
968-
need_update = true;
969-
}
970984

971-
/* if rings need to be updated, here's the place to do it in one shot */
972-
if (need_update) {
973-
ixgbe_down(adapter);
985+
for (i = 0; i < adapter->num_rx_queues; i++) {
986+
ixgbe_free_rx_resources(adapter->rx_ring[i]);
974987

975-
/* tx */
976-
if (new_tx_count != adapter->tx_ring_count) {
977-
for (i = 0; i < adapter->num_tx_queues; i++) {
978-
ixgbe_free_tx_resources(adapter->tx_ring[i]);
979-
memcpy(adapter->tx_ring[i], &temp_tx_ring[i],
980-
sizeof(struct ixgbe_ring));
981-
}
982-
adapter->tx_ring_count = new_tx_count;
988+
memcpy(adapter->rx_ring[i], &temp_ring[i],
989+
sizeof(struct ixgbe_ring));
983990
}
984991

985-
/* rx */
986-
if (new_rx_count != adapter->rx_ring_count) {
987-
for (i = 0; i < adapter->num_rx_queues; i++) {
988-
ixgbe_free_rx_resources(adapter->rx_ring[i]);
989-
memcpy(adapter->rx_ring[i], &temp_rx_ring[i],
990-
sizeof(struct ixgbe_ring));
991-
}
992-
adapter->rx_ring_count = new_rx_count;
993-
}
994-
ixgbe_up(adapter);
992+
adapter->rx_ring_count = new_rx_count;
995993
}
996994

997-
vfree(temp_rx_ring);
998995
err_setup:
999-
vfree(temp_tx_ring);
996+
ixgbe_up(adapter);
997+
vfree(temp_ring);
1000998
clear_reset:
1001999
clear_bit(__IXGBE_RESETTING, &adapter->state);
10021000
return err;

0 commit comments

Comments
 (0)