Commit fa37feef authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Jialin Zhang
Browse files

net: Use u64_stats_fetch_begin_irq() for stats fetch.

stable inclusion
from stable-v5.10.142
commit d71a1c9fce184718d1b3a51a9e8a6e31cbbb45ce
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6D0ZE

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=d71a1c9fce184718d1b3a51a9e8a6e31cbbb45ce



-------------------------------------------------

commit 278d3ba6 upstream.

On 32bit-UP u64_stats_fetch_begin() disables only preemption. If the
reader is in preemptible context and the writer side
(u64_stats_update_begin*()) runs in an interrupt context (IRQ or
softirq) then the writer can update the stats during the read operation.
This update remains undetected.

Use u64_stats_fetch_begin_irq() to ensure the stats fetch on 32bit-UP
are not interrupted by a writer. 32bit-SMP remains unaffected by this
change.

Cc: "David S. Miller" <davem@davemloft.net>
Cc: Catherine Sullivan <csully@google.com>
Cc: David Awogbemila <awogbemila@google.com>
Cc: Dimitris Michailidis <dmichail@fungible.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Jeroen de Borst <jeroendb@google.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <simon.horman@corigine.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: oss-drivers@corigine.com
Cc: stable@vger.kernel.org
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit d71a1c9fce184718d1b3a51a9e8a6e31cbbb45ce)
Signed-off-by: default avatarWang Yufen <wangyufen@huawei.com>

Conflicts:
	drivers/net/ethernet/huawei/hinic/hinic_rx.c
	drivers/net/ethernet/huawei/hinic/hinic_tx.c

Signed-off-by: default avatarWang Yufen <wangyufen@huawei.com>
Reviewed-by: default avatarLiu Jian <liujian56@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parent 067d1b49
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -1920,7 +1920,7 @@ static void gmac_get_stats64(struct net_device *netdev,

	/* Racing with RX NAPI */
	do {
		start = u64_stats_fetch_begin(&port->rx_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp);

		stats->rx_packets = port->stats.rx_packets;
		stats->rx_bytes = port->stats.rx_bytes;
@@ -1932,11 +1932,11 @@ static void gmac_get_stats64(struct net_device *netdev,
		stats->rx_crc_errors = port->stats.rx_crc_errors;
		stats->rx_frame_errors = port->stats.rx_frame_errors;

	} while (u64_stats_fetch_retry(&port->rx_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start));

	/* Racing with MIB and TX completion interrupts */
	do {
		start = u64_stats_fetch_begin(&port->ir_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp);

		stats->tx_errors = port->stats.tx_errors;
		stats->tx_packets = port->stats.tx_packets;
@@ -1946,15 +1946,15 @@ static void gmac_get_stats64(struct net_device *netdev,
		stats->rx_missed_errors = port->stats.rx_missed_errors;
		stats->rx_fifo_errors = port->stats.rx_fifo_errors;

	} while (u64_stats_fetch_retry(&port->ir_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start));

	/* Racing with hard_start_xmit */
	do {
		start = u64_stats_fetch_begin(&port->tx_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp);

		stats->tx_dropped = port->stats.tx_dropped;

	} while (u64_stats_fetch_retry(&port->tx_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start));

	stats->rx_dropped += stats->rx_missed_errors;
}
@@ -2032,18 +2032,18 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
	/* Racing with MIB interrupt */
	do {
		p = values;
		start = u64_stats_fetch_begin(&port->ir_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->ir_stats_syncp);

		for (i = 0; i < RX_STATS_NUM; i++)
			*p++ = port->hw_stats[i];

	} while (u64_stats_fetch_retry(&port->ir_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->ir_stats_syncp, start));
	values = p;

	/* Racing with RX NAPI */
	do {
		p = values;
		start = u64_stats_fetch_begin(&port->rx_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->rx_stats_syncp);

		for (i = 0; i < RX_STATUS_NUM; i++)
			*p++ = port->rx_stats[i];
@@ -2051,13 +2051,13 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
			*p++ = port->rx_csum_stats[i];
		*p++ = port->rx_napi_exits;

	} while (u64_stats_fetch_retry(&port->rx_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->rx_stats_syncp, start));
	values = p;

	/* Racing with TX start_xmit */
	do {
		p = values;
		start = u64_stats_fetch_begin(&port->tx_stats_syncp);
		start = u64_stats_fetch_begin_irq(&port->tx_stats_syncp);

		for (i = 0; i < TX_MAX_FRAGS; i++) {
			*values++ = port->tx_frag_stats[i];
@@ -2066,7 +2066,7 @@ static void gmac_get_ethtool_stats(struct net_device *netdev,
		*values++ = port->tx_frags_linearized;
		*values++ = port->tx_hw_csummed;

	} while (u64_stats_fetch_retry(&port->tx_stats_syncp, start));
	} while (u64_stats_fetch_retry_irq(&port->tx_stats_syncp, start));
}

static int gmac_get_ksettings(struct net_device *netdev,
+8 −8
Original line number Diff line number Diff line
@@ -172,14 +172,14 @@ gve_get_ethtool_stats(struct net_device *netdev,
				struct gve_rx_ring *rx = &priv->rx[ring];

				start =
				  u64_stats_fetch_begin(&priv->rx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
				tmp_rx_pkts = rx->rpackets;
				tmp_rx_bytes = rx->rbytes;
				tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail;
				tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail;
				tmp_rx_desc_err_dropped_pkt =
					rx->rx_desc_err_dropped_pkt;
			} while (u64_stats_fetch_retry(&priv->rx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
						       start));
			rx_pkts += tmp_rx_pkts;
			rx_bytes += tmp_rx_bytes;
@@ -193,10 +193,10 @@ gve_get_ethtool_stats(struct net_device *netdev,
		if (priv->tx) {
			do {
				start =
				  u64_stats_fetch_begin(&priv->tx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
				tmp_tx_pkts = priv->tx[ring].pkt_done;
				tmp_tx_bytes = priv->tx[ring].bytes_done;
			} while (u64_stats_fetch_retry(&priv->tx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
						       start));
			tx_pkts += tmp_tx_pkts;
			tx_bytes += tmp_tx_bytes;
@@ -254,13 +254,13 @@ gve_get_ethtool_stats(struct net_device *netdev,
			data[i++] = rx->cnt;
			do {
				start =
				  u64_stats_fetch_begin(&priv->rx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
				tmp_rx_bytes = rx->rbytes;
				tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail;
				tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail;
				tmp_rx_desc_err_dropped_pkt =
					rx->rx_desc_err_dropped_pkt;
			} while (u64_stats_fetch_retry(&priv->rx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
						       start));
			data[i++] = tmp_rx_bytes;
			/* rx dropped packets */
@@ -313,9 +313,9 @@ gve_get_ethtool_stats(struct net_device *netdev,
			data[i++] = tx->done;
			do {
				start =
				  u64_stats_fetch_begin(&priv->tx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
				tmp_tx_bytes = tx->bytes_done;
			} while (u64_stats_fetch_retry(&priv->tx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
						       start));
			data[i++] = tmp_tx_bytes;
			data[i++] = tx->wake_queue;
+6 −6
Original line number Diff line number Diff line
@@ -40,10 +40,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
		for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
			do {
				start =
				  u64_stats_fetch_begin(&priv->rx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->rx[ring].statss);
				packets = priv->rx[ring].rpackets;
				bytes = priv->rx[ring].rbytes;
			} while (u64_stats_fetch_retry(&priv->rx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->rx[ring].statss,
						       start));
			s->rx_packets += packets;
			s->rx_bytes += bytes;
@@ -53,10 +53,10 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
		for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) {
			do {
				start =
				  u64_stats_fetch_begin(&priv->tx[ring].statss);
				  u64_stats_fetch_begin_irq(&priv->tx[ring].statss);
				packets = priv->tx[ring].pkt_done;
				bytes = priv->tx[ring].bytes_done;
			} while (u64_stats_fetch_retry(&priv->tx[ring].statss,
			} while (u64_stats_fetch_retry_irq(&priv->tx[ring].statss,
						       start));
			s->tx_packets += packets;
			s->tx_bytes += bytes;
@@ -1041,9 +1041,9 @@ void gve_handle_report_stats(struct gve_priv *priv)
	if (priv->tx) {
		for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
			do {
				start = u64_stats_fetch_begin(&priv->tx[idx].statss);
				start = u64_stats_fetch_begin_irq(&priv->tx[idx].statss);
				tx_bytes = priv->tx[idx].bytes_done;
			} while (u64_stats_fetch_retry(&priv->tx[idx].statss, start));
			} while (u64_stats_fetch_retry_irq(&priv->tx[idx].statss, start));
			stats[stats_idx++] = (struct stats) {
				.stat_name = cpu_to_be32(TX_WAKE_CNT),
				.value = cpu_to_be64(priv->tx[idx].wake_queue),
+2 −2
Original line number Diff line number Diff line
@@ -375,7 +375,7 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq,

	u64_stats_update_begin(&stats->syncp);
	do {
		start = u64_stats_fetch_begin(&rxq_stats->syncp);
		start = u64_stats_fetch_begin_irq(&rxq_stats->syncp);
		stats->bytes = rxq_stats->bytes;
		stats->packets = rxq_stats->packets;
		stats->errors = rxq_stats->csum_errors +
@@ -384,7 +384,7 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq,
		stats->other_errors = rxq_stats->other_errors;
		stats->dropped = rxq_stats->dropped;
		stats->rx_buf_empty = rxq_stats->rx_buf_empty;
	} while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
	} while (u64_stats_fetch_retry_irq(&rxq_stats->syncp, start));
	u64_stats_update_end(&stats->syncp);
}

+2 −2
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ void hinic_txq_get_stats(struct hinic_txq *txq,

	u64_stats_update_begin(&stats->syncp);
	do {
		start = u64_stats_fetch_begin(&txq_stats->syncp);
		start = u64_stats_fetch_begin_irq(&txq_stats->syncp);
		stats->bytes = txq_stats->bytes;
		stats->packets = txq_stats->packets;
		stats->busy = txq_stats->busy;
@@ -69,7 +69,7 @@ void hinic_txq_get_stats(struct hinic_txq *txq,
		stats->dropped = txq_stats->dropped;
		stats->big_frags_pkts = txq_stats->big_frags_pkts;
		stats->big_udp_pkts = txq_stats->big_udp_pkts;
	} while (u64_stats_fetch_retry(&txq_stats->syncp, start));
	} while (u64_stats_fetch_retry_irq(&txq_stats->syncp, start));
	u64_stats_update_end(&stats->syncp);
}

Loading