Skip to content

Commit b831236

Browse files
jacob-kellerJeff Kirsher
authored andcommitted
i40e: always return all queue stat strings
The ethtool API for obtaining device statistics is not intended to allow runtime changes in the number of statistics reported. It may *appear* this way, as there is an ability to request the number of stats using ethtool_get_set_count(). However, it is expected that this must always return the same value for invocations of the same device. If we don't satisfy this contract, and allow the number of stats to change during run time, we could cause invalid memory accesses or report the stat strings incorrectly. This is because the API for obtaining stats is to (1) get the size, (2) get the strings and finally (3) get the stats. Since these are each separate ethtool op commands, it is not possible to maintain consistency by holding the RTNL lock over the whole operation. This results in the potential for a race condition to occur where the size changed between any of the 3 calls. Avoid this issue by requiring that we always return the same value for a given device. We can check any values which remain constant for the life of the device, but must not report different sizes depending on runtime attributes. This patch specifically fixes the queue statistics to always return every queue even if it's not currently in use. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
1 parent 9955d49 commit b831236

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

drivers/net/ethernet/intel/i40e/i40e_ethtool.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ static const struct i40e_stats i40e_gstrings_stats[] = {
140140
I40E_PF_STAT("rx_lpi_count", stats.rx_lpi_count),
141141
};
142142

143-
#define I40E_QUEUE_STATS_LEN(n) \
144-
(((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs \
143+
/* We use num_tx_queues here as a proxy for the maximum number of queues
144+
* available because we always allocate queues symmetrically.
145+
*/
146+
#define I40E_MAX_NUM_QUEUES(n) ((n)->num_tx_queues)
147+
#define I40E_QUEUE_STATS_LEN(n) \
148+
(I40E_MAX_NUM_QUEUES(n) \
145149
* 2 /* Tx and Rx together */ \
146150
* (sizeof(struct i40e_queue_stats) / sizeof(u64)))
147151
#define I40E_GLOBAL_STATS_LEN ARRAY_SIZE(i40e_gstrings_stats)
@@ -1712,11 +1716,19 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
17121716
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
17131717
}
17141718
rcu_read_lock();
1715-
for (j = 0; j < vsi->num_queue_pairs; j++) {
1719+
for (j = 0; j < I40E_MAX_NUM_QUEUES(netdev) ; j++) {
17161720
tx_ring = READ_ONCE(vsi->tx_rings[j]);
17171721

1718-
if (!tx_ring)
1722+
if (!tx_ring) {
1723+
/* Bump the stat counter to skip these stats, and make
1724+
* sure the memory is zero'd
1725+
*/
1726+
data[i++] = 0;
1727+
data[i++] = 0;
1728+
data[i++] = 0;
1729+
data[i++] = 0;
17191730
continue;
1731+
}
17201732

17211733
/* process Tx ring statistics */
17221734
do {
@@ -1800,7 +1812,7 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
18001812
i40e_gstrings_misc_stats[i].stat_string);
18011813
p += ETH_GSTRING_LEN;
18021814
}
1803-
for (i = 0; i < vsi->num_queue_pairs; i++) {
1815+
for (i = 0; i < I40E_MAX_NUM_QUEUES(netdev); i++) {
18041816
snprintf(p, ETH_GSTRING_LEN, "tx-%d.tx_packets", i);
18051817
p += ETH_GSTRING_LEN;
18061818
snprintf(p, ETH_GSTRING_LEN, "tx-%d.tx_bytes", i);

0 commit comments

Comments
 (0)