> -----Original Message-----
> From: Kitszel, Przemyslaw <[email protected]>
> Sent: Friday, September 25, 2026 3:16 PM
> To: [email protected]; Jakub Kicinski <[email protected]>
> Cc: Nguyen, Anthony L <[email protected]>; Loktionov,
> Aleksandr <[email protected]>; Schmidt, Michal
> <[email protected]>; [email protected];
> [email protected]; [email protected]; [email protected];
> [email protected]; Kitszel, Przemyslaw
> <[email protected]>
> Subject: [PATCH net v5 2/6] ice: extract __ice_vsi_free_stats()
>
> Record the length of each ring stats array in struct ice_vsi_stats, so
> that freeing the array entries no longer needs the owning VSI. Keep
> the new fields in sync in both places that size the arrays.
>
> With that, the body of ice_vsi_free_stats() becomes independent of the
> VSI and can be split out as __ice_vsi_free_stats(). The @free_entries
> parameter is always true here; a later commit adds a caller that frees
> only the array container, after its entries have been handed over to a
> freshly allocated stats structure.
>
> The free path now stops at the recorded length instead of the VSI
> queue count, so it follows the real allocation rather than a number
> that can disagree with it. Sizing still does not: "ice: rebuild ring
> stats arrays instead of reallocating them in place" starts using the
> lengths to carry entries over, and only "ice: size ring stats arrays
> from the final queue count" makes them authoritative for the
> allocation path.
>
> Signed-off-by: Przemek Kitszel <[email protected]>
> ---
> v5:
> - drop the "no functional change intended" claim, the bound of the
> free
> loop changes owner here (Clashiko)
> - state that the recorded lengths govern only the free path at this
> point in the series (Clashiko)
> ---
> drivers/net/ethernet/intel/ice/ice.h | 2 +
> drivers/net/ethernet/intel/ice/ice_lib.c | 52 ++++++++++++++---------
> -
> 2 files changed, 33 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice.h
> b/drivers/net/ethernet/intel/ice/ice.h
> index db3c7015c56c..fadfe94bf1c8 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -328,6 +328,8 @@ enum ice_vsi_state { struct ice_vsi_stats {
> struct ice_ring_stats **tx_ring_stats; /* Tx ring stats array
> */
> struct ice_ring_stats **rx_ring_stats; /* Rx ring stats array
> */
> + u16 tx_ring_stats_len; /* Length of the Tx ring stats array */
> + u16 rx_ring_stats_len; /* Length of the Rx ring stats array */
> };
>
> /* struct that defines a VSI, associated with a dev */ diff --git
> a/drivers/net/ethernet/intel/ice/ice_lib.c
> b/drivers/net/ethernet/intel/ice/ice_lib.c
> index 31af378aa0e7..1414127d32cd 100644
> --- a/drivers/net/ethernet/intel/ice/ice_lib.c
> +++ b/drivers/net/ethernet/intel/ice/ice_lib.c
> @@ -330,42 +330,48 @@ static void ice_vsi_free_arrays(struct ice_vsi
> *vsi)
> vsi->rxq_map = NULL;
> }
>
> +/* free single stats memory */
> +static void __ice_vsi_free_stats(struct ice_vsi_stats *vsi_stat, bool
> +free_entries) {
> + if (!vsi_stat)
> + return;
> +
> + if (free_entries) {
> + for (int i = 0; i < vsi_stat->tx_ring_stats_len; i++) {
> + if (vsi_stat->tx_ring_stats[i]) {
> + kfree_rcu(vsi_stat->tx_ring_stats[i], rcu);
> + WRITE_ONCE(vsi_stat->tx_ring_stats[i],
> NULL);
> + }
> + }
> + for (int i = 0; i < vsi_stat->rx_ring_stats_len; i++) {
> + if (vsi_stat->rx_ring_stats[i]) {
> + kfree_rcu(vsi_stat->rx_ring_stats[i], rcu);
> + WRITE_ONCE(vsi_stat->rx_ring_stats[i],
> NULL);
> + }
> + }
> + }
> +
> + kfree(vsi_stat->tx_ring_stats);
> + kfree(vsi_stat->rx_ring_stats);
> + kfree(vsi_stat);
> +}
> +
> /**
> * ice_vsi_free_stats - Free the ring statistics structures
> * @vsi: VSI pointer
> */
> static void ice_vsi_free_stats(struct ice_vsi *vsi) {
> struct ice_vsi_stats *vsi_stat;
> struct ice_pf *pf = vsi->back;
> - int i;
>
> if (vsi->type == ICE_VSI_CHNL)
> return;
> if (!pf->vsi_stats)
> return;
>
> vsi_stat = pf->vsi_stats[vsi->idx];
> - if (!vsi_stat)
> - return;
> -
> - ice_for_each_alloc_txq(vsi, i) {
> - if (vsi_stat->tx_ring_stats[i]) {
> - kfree_rcu(vsi_stat->tx_ring_stats[i], rcu);
> - WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL);
> - }
> - }
> -
> - ice_for_each_alloc_rxq(vsi, i) {
> - if (vsi_stat->rx_ring_stats[i]) {
> - kfree_rcu(vsi_stat->rx_ring_stats[i], rcu);
> - WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL);
> - }
> - }
> -
> - kfree(vsi_stat->tx_ring_stats);
> - kfree(vsi_stat->rx_ring_stats);
> - kfree(vsi_stat);
> + __ice_vsi_free_stats(vsi_stat, true);
> pf->vsi_stats[vsi->idx] = NULL;
> }
>
> @@ -539,11 +545,13 @@ static int ice_vsi_alloc_stat_arrays(struct
> ice_vsi *vsi)
> kzalloc_objs(*vsi_stat->tx_ring_stats, vsi->alloc_txq);
> if (!vsi_stat->tx_ring_stats)
> goto err_alloc_tx;
> + vsi_stat->tx_ring_stats_len = vsi->alloc_txq;
>
> vsi_stat->rx_ring_stats =
> kzalloc_objs(*vsi_stat->rx_ring_stats, vsi->alloc_rxq);
> if (!vsi_stat->rx_ring_stats)
> goto err_alloc_rx;
> + vsi_stat->rx_ring_stats_len = vsi->alloc_rxq;
>
> pf->vsi_stats[vsi->idx] = vsi_stat;
>
> @@ -3055,6 +3063,7 @@ ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
> vsi_stat->tx_ring_stats = tx_ring_stats;
> return -ENOMEM;
> }
> + vsi_stat->tx_ring_stats_len = req_txq;
>
> if (req_rxq < prev_rxq) {
> for (i = req_rxq; i < prev_rxq; i++) { @@ -3074,6
> +3083,7 @@ ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
> vsi_stat->rx_ring_stats = rx_ring_stats;
> return -ENOMEM;
> }
> + vsi_stat->rx_ring_stats_len = req_rxq;
>
> return 0;
> }
> --
> 2.51.1
Reviewed-by: Aleksandr Loktionov <[email protected]>