As noted in the subsequent review.
In hinic3_get_stats64() in hinic3_netdev_ops.c, the reader retry loops
accumulate txq_stats and rxq_stats using '+=':
do {
start = u64_stats_fetch_begin(&txq_stats->syncp);
bytes += txq_stats->bytes;
...
} while (u64_stats_fetch_retry(&txq_stats->syncp, start));
If the loop retries due to concurrent updates on 32-bit systems,
the counters are added multiple times. This was previously benign
since the fields weren't populated by the driver, but these new
updates will cause incorrect statistics on 32-bit platforms.
Co-developed-by: Wu Di <redacted>
Signed-off-by: Wu Di <redacted>
Co-developed-by: Teng Peisen <redacted>
Signed-off-by: Teng Peisen <redacted>
Signed-off-by: Fan Gong <gongfan1@huawei.com>
---
.../huawei/hinic3/hinic3_netdev_ops.c | 35 ++++++++-----------
1 file changed, 14 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
index da73811641a9..474ea81f1750 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
@@ -795,45 +795,38 @@ static void hinic3_get_stats64(struct net_device *netdev,
packets = 0;
dropped = 0;
for (i = 0; i < nic_dev->max_qps; i++) {
- if (!nic_dev->txqs)
- break;
-
txq = &nic_dev->txqs[i];
txq_stats = &txq->txq_stats;
do {
start = u64_stats_fetch_begin(&txq_stats->syncp);
- bytes += txq_stats->bytes;
- packets += txq_stats->packets;
- dropped += txq_stats->dropped;
+ bytes = txq_stats->bytes;
+ packets = txq_stats->packets;
+ dropped = txq_stats->dropped;
} while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+ stats->tx_packets += packets;
+ stats->tx_bytes += bytes;
+ stats->tx_dropped += dropped;
}
- stats->tx_packets = packets;
- stats->tx_bytes = bytes;
- stats->tx_dropped = dropped;
bytes = 0;
packets = 0;
errors = 0;
dropped = 0;
for (i = 0; i < nic_dev->max_qps; i++) {
- if (!nic_dev->rxqs)
- break;
-
rxq = &nic_dev->rxqs[i];
rxq_stats = &rxq->rxq_stats;
do {
start = u64_stats_fetch_begin(&rxq_stats->syncp);
- bytes += rxq_stats->bytes;
- packets += rxq_stats->packets;
- errors += rxq_stats->csum_errors +
- rxq_stats->other_errors;
- dropped += rxq_stats->dropped;
+ bytes = rxq_stats->bytes;
+ packets = rxq_stats->packets;
+ errors = rxq_stats->other_errors;
+ dropped = rxq_stats->dropped;
} while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+ stats->rx_packets += packets;
+ stats->rx_bytes += bytes;
+ stats->rx_errors += errors;
+ stats->rx_dropped += dropped;
}
- stats->rx_packets = packets;
- stats->rx_bytes = bytes;
- stats->rx_errors = errors;
- stats->rx_dropped = dropped;
}
static void hinic3_nic_set_rx_mode(struct net_device *netdev)--
2.43.0