]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: hns3: fix data race in hns3_fetch_stats
authorDavid Yang <mmyangfl@gmail.com>
Mon, 19 Jan 2026 16:07:37 +0000 (00:07 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 21 Jan 2026 02:29:09 +0000 (18:29 -0800)
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: b20d7fe51e0d ("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>
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c

index 7a0654e2d3dd96d28b675e6219a76b4aad3ff0ba..7a9573dcab741bb2d015ce5c86f32c06d49ce2a9 100644 (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,