net: hns3: fix data race in hns3_fetch_stats

In hns3_fetch_stats(), ring statistics, protected by u64_stats_sync, are
read and accumulated in ignorance of possible u64_stats_fetch_retry()
events. These statistics are already accumulated by
hns3_ring_stats_update(). Fix this by reading them into a temporary
buffer first.

Fixes: b20d7fe51e ("net: hns3: add some statitics info to tx process")
Signed-off-by: David Yang <mmyangfl@gmail.com>
Link: https://patch.msgid.link/20260119160759.1455950-1-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
David Yang
2026-01-20 00:07:37 +08:00
committed by Jakub Kicinski
parent a917cd0a23
commit 748a81c8ce

View File

@@ -2529,44 +2529,47 @@ static netdev_features_t hns3_features_check(struct sk_buff *skb,
static void hns3_fetch_stats(struct rtnl_link_stats64 *stats,
struct hns3_enet_ring *ring, bool is_tx)
{
struct ring_stats ring_stats;
unsigned int start;
do {
start = u64_stats_fetch_begin(&ring->syncp);
if (is_tx) {
stats->tx_bytes += ring->stats.tx_bytes;
stats->tx_packets += ring->stats.tx_pkts;
stats->tx_dropped += ring->stats.sw_err_cnt;
stats->tx_dropped += ring->stats.tx_vlan_err;
stats->tx_dropped += ring->stats.tx_l4_proto_err;
stats->tx_dropped += ring->stats.tx_l2l3l4_err;
stats->tx_dropped += ring->stats.tx_tso_err;
stats->tx_dropped += ring->stats.over_max_recursion;
stats->tx_dropped += ring->stats.hw_limitation;
stats->tx_dropped += ring->stats.copy_bits_err;
stats->tx_dropped += ring->stats.skb2sgl_err;
stats->tx_dropped += ring->stats.map_sg_err;
stats->tx_errors += ring->stats.sw_err_cnt;
stats->tx_errors += ring->stats.tx_vlan_err;
stats->tx_errors += ring->stats.tx_l4_proto_err;
stats->tx_errors += ring->stats.tx_l2l3l4_err;
stats->tx_errors += ring->stats.tx_tso_err;
stats->tx_errors += ring->stats.over_max_recursion;
stats->tx_errors += ring->stats.hw_limitation;
stats->tx_errors += ring->stats.copy_bits_err;
stats->tx_errors += ring->stats.skb2sgl_err;
stats->tx_errors += ring->stats.map_sg_err;
} else {
stats->rx_bytes += ring->stats.rx_bytes;
stats->rx_packets += ring->stats.rx_pkts;
stats->rx_dropped += ring->stats.l2_err;
stats->rx_errors += ring->stats.l2_err;
stats->rx_errors += ring->stats.l3l4_csum_err;
stats->rx_crc_errors += ring->stats.l2_err;
stats->multicast += ring->stats.rx_multicast;
stats->rx_length_errors += ring->stats.err_pkt_len;
}
ring_stats = ring->stats;
} while (u64_stats_fetch_retry(&ring->syncp, start));
if (is_tx) {
stats->tx_bytes += ring_stats.tx_bytes;
stats->tx_packets += ring_stats.tx_pkts;
stats->tx_dropped += ring_stats.sw_err_cnt;
stats->tx_dropped += ring_stats.tx_vlan_err;
stats->tx_dropped += ring_stats.tx_l4_proto_err;
stats->tx_dropped += ring_stats.tx_l2l3l4_err;
stats->tx_dropped += ring_stats.tx_tso_err;
stats->tx_dropped += ring_stats.over_max_recursion;
stats->tx_dropped += ring_stats.hw_limitation;
stats->tx_dropped += ring_stats.copy_bits_err;
stats->tx_dropped += ring_stats.skb2sgl_err;
stats->tx_dropped += ring_stats.map_sg_err;
stats->tx_errors += ring_stats.sw_err_cnt;
stats->tx_errors += ring_stats.tx_vlan_err;
stats->tx_errors += ring_stats.tx_l4_proto_err;
stats->tx_errors += ring_stats.tx_l2l3l4_err;
stats->tx_errors += ring_stats.tx_tso_err;
stats->tx_errors += ring_stats.over_max_recursion;
stats->tx_errors += ring_stats.hw_limitation;
stats->tx_errors += ring_stats.copy_bits_err;
stats->tx_errors += ring_stats.skb2sgl_err;
stats->tx_errors += ring_stats.map_sg_err;
} else {
stats->rx_bytes += ring_stats.rx_bytes;
stats->rx_packets += ring_stats.rx_pkts;
stats->rx_dropped += ring_stats.l2_err;
stats->rx_errors += ring_stats.l2_err;
stats->rx_errors += ring_stats.l3l4_csum_err;
stats->rx_crc_errors += ring_stats.l2_err;
stats->multicast += ring_stats.rx_multicast;
stats->rx_length_errors += ring_stats.err_pkt_len;
}
}
static void hns3_nic_get_stats64(struct net_device *netdev,