All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Eric Dumazet <edumazet@google.com>,
	"David S . Miller" <davem@davemloft.net>,
	Sasha Levin <sashal@kernel.org>,
	kuba@kernel.org, pabeni@redhat.com, imagedong@tencent.com,
	bigeasy@linutronix.de, kuniyu@amazon.com, petrm@nvidia.com,
	netdev@vger.kernel.org
Subject: [PATCH AUTOSEL 5.10 25/39] net: add atomic_long_t to net_device_stats fields
Date: Sun, 18 Dec 2022 11:15:45 -0500	[thread overview]
Message-ID: <20221218161559.932604-25-sashal@kernel.org> (raw)
In-Reply-To: <20221218161559.932604-1-sashal@kernel.org>

From: Eric Dumazet <edumazet@google.com>

[ Upstream commit 6c1c5097781f563b70a81683ea6fdac21637573b ]

Long standing KCSAN issues are caused by data-race around
some dev->stats changes.

Most performance critical paths already use per-cpu
variables, or per-queue ones.

It is reasonable (and more correct) to use atomic operations
for the slow paths.

This patch adds an union for each field of net_device_stats,
so that we can convert paths that are not yet protected
by a spinlock or a mutex.

netdev_stats_to_stats64() no longer has an #if BITS_PER_LONG==64

Note that the memcpy() we were using on 64bit arches
had no provision to avoid load-tearing,
while atomic_long_read() is providing the needed protection
at no cost.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/netdevice.h | 58 +++++++++++++++++++++++----------------
 include/net/dst.h         |  5 ++--
 net/core/dev.c            | 14 ++--------
 3 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ef75567efd27..b478a16ef284 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -166,31 +166,38 @@ static inline bool dev_xmit_complete(int rc)
  *	(unsigned long) so they can be read and written atomically.
  */
 
+#define NET_DEV_STAT(FIELD)			\
+	union {					\
+		unsigned long FIELD;		\
+		atomic_long_t __##FIELD;	\
+	}
+
 struct net_device_stats {
-	unsigned long	rx_packets;
-	unsigned long	tx_packets;
-	unsigned long	rx_bytes;
-	unsigned long	tx_bytes;
-	unsigned long	rx_errors;
-	unsigned long	tx_errors;
-	unsigned long	rx_dropped;
-	unsigned long	tx_dropped;
-	unsigned long	multicast;
-	unsigned long	collisions;
-	unsigned long	rx_length_errors;
-	unsigned long	rx_over_errors;
-	unsigned long	rx_crc_errors;
-	unsigned long	rx_frame_errors;
-	unsigned long	rx_fifo_errors;
-	unsigned long	rx_missed_errors;
-	unsigned long	tx_aborted_errors;
-	unsigned long	tx_carrier_errors;
-	unsigned long	tx_fifo_errors;
-	unsigned long	tx_heartbeat_errors;
-	unsigned long	tx_window_errors;
-	unsigned long	rx_compressed;
-	unsigned long	tx_compressed;
+	NET_DEV_STAT(rx_packets);
+	NET_DEV_STAT(tx_packets);
+	NET_DEV_STAT(rx_bytes);
+	NET_DEV_STAT(tx_bytes);
+	NET_DEV_STAT(rx_errors);
+	NET_DEV_STAT(tx_errors);
+	NET_DEV_STAT(rx_dropped);
+	NET_DEV_STAT(tx_dropped);
+	NET_DEV_STAT(multicast);
+	NET_DEV_STAT(collisions);
+	NET_DEV_STAT(rx_length_errors);
+	NET_DEV_STAT(rx_over_errors);
+	NET_DEV_STAT(rx_crc_errors);
+	NET_DEV_STAT(rx_frame_errors);
+	NET_DEV_STAT(rx_fifo_errors);
+	NET_DEV_STAT(rx_missed_errors);
+	NET_DEV_STAT(tx_aborted_errors);
+	NET_DEV_STAT(tx_carrier_errors);
+	NET_DEV_STAT(tx_fifo_errors);
+	NET_DEV_STAT(tx_heartbeat_errors);
+	NET_DEV_STAT(tx_window_errors);
+	NET_DEV_STAT(rx_compressed);
+	NET_DEV_STAT(tx_compressed);
 };
+#undef NET_DEV_STAT
 
 
 #include <linux/cache.h>
@@ -5256,4 +5263,9 @@ do {								\
 
 extern struct net_device *blackhole_netdev;
 
+/* Note: Avoid these macros in fast path, prefer per-cpu or per-queue counters. */
+#define DEV_STATS_INC(DEV, FIELD) atomic_long_inc(&(DEV)->stats.__##FIELD)
+#define DEV_STATS_ADD(DEV, FIELD, VAL) 	\
+		atomic_long_add((VAL), &(DEV)->stats.__##FIELD)
+
 #endif	/* _LINUX_NETDEVICE_H */
diff --git a/include/net/dst.h b/include/net/dst.h
index acd15c544cf3..ae2cf57d796b 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -356,9 +356,8 @@ static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev,
 static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev,
 				 struct net *net)
 {
-	/* TODO : stats should be SMP safe */
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += skb->len;
+	DEV_STATS_INC(dev, rx_packets);
+	DEV_STATS_ADD(dev, rx_bytes, skb->len);
 	__skb_tunnel_rx(skb, dev, net);
 }
 
diff --git a/net/core/dev.c b/net/core/dev.c
index 34b5aab42b91..5afe56e8e763 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10320,24 +10320,16 @@ void netdev_run_todo(void)
 void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
 			     const struct net_device_stats *netdev_stats)
 {
-#if BITS_PER_LONG == 64
-	BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats));
-	memcpy(stats64, netdev_stats, sizeof(*netdev_stats));
-	/* zero out counters that only exist in rtnl_link_stats64 */
-	memset((char *)stats64 + sizeof(*netdev_stats), 0,
-	       sizeof(*stats64) - sizeof(*netdev_stats));
-#else
-	size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long);
-	const unsigned long *src = (const unsigned long *)netdev_stats;
+	size_t i, n = sizeof(*netdev_stats) / sizeof(atomic_long_t);
+	const atomic_long_t *src = (atomic_long_t *)netdev_stats;
 	u64 *dst = (u64 *)stats64;
 
 	BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64));
 	for (i = 0; i < n; i++)
-		dst[i] = src[i];
+		dst[i] = atomic_long_read(&src[i]);
 	/* zero out counters that only exist in rtnl_link_stats64 */
 	memset((char *)stats64 + n * sizeof(u64), 0,
 	       sizeof(*stats64) - n * sizeof(u64));
-#endif
 }
 EXPORT_SYMBOL(netdev_stats_to_stats64);
 
-- 
2.35.1


  parent reply	other threads:[~2022-12-18 16:49 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-18 16:15 [PATCH AUTOSEL 5.10 01/39] drm/etnaviv: add missing quirks for GC300 Sasha Levin
2022-12-18 16:15 ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 02/39] brcmfmac: return error when getting invalid max_flowrings from dongle Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 03/39] wifi: ath9k: verify the expected usb_endpoints are present Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 04/39] wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 05/39] ASoC: codecs: rt298: Add quirk for KBL-R RVP platform Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 06/39] ipmi: fix memleak when unload ipmi driver Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 07/39] drm/amd/display: prevent memory leak Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 08/39] qed (gcc13): use u16 for fid to be big enough Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 09/39] bpf: make sure skb->len != 0 when redirecting to a tunneling device Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 10/39] net: ethernet: ti: Fix return type of netcp_ndo_start_xmit() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 11/39] hamradio: baycom_epp: Fix return type of baycom_send_packet() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 12/39] wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request() Sasha Levin
2022-12-18 16:15 ` [Intel-wired-lan] [PATCH AUTOSEL 5.10 13/39] igb: Do not free q_vector unless new one was allocated Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 14/39] drm/amdgpu: Fix type of second parameter in trans_msg() callback Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 15/39] drm/amdgpu: Fix type of second parameter in odn_edit_dpm_table() callback Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 16/39] s390/ctcm: Fix return type of ctc{mp,}m_tx() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 17/39] s390/netiucv: Fix return type of netiucv_tx() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 18/39] s390/lcs: Fix return type of lcs_start_xmit() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 19/39] drm/msm: Use drm_mode_copy() Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 20/39] drm/rockchip: " Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 21/39] drm/sti: " Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 22/39] drivers/md/md-bitmap: check the return value of md_bitmap_get_counter() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 23/39] md/raid1: stop mdx_raid1 thread when raid1 array run failed Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 24/39] drm/amd/display: fix array index out of bound error in bios parser Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15   ` Sasha Levin
2022-12-18 16:15 ` Sasha Levin [this message]
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 26/39] mrp: introduce active flags to prevent UAF when applicant uninit Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 27/39] ppp: associate skb with a device at tx Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 28/39] bpf: Prevent decl_tag from being referenced in func_proto arg Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 29/39] ethtool: avoiding integer overflow in ethtool_phys_id() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 30/39] media: dvb-frontends: fix leak of memory fw Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 31/39] media: dvbdev: adopts refcnt to avoid UAF Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 32/39] media: dvb-usb: fix memory leak in dvb_usb_adapter_init() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 33/39] blk-mq: fix possible memleak when register 'hctx' failed Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 34/39] libbpf: Avoid enum forward-declarations in public API in C++ mode Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 35/39] regulator: core: fix use_count leakage when handling boot-on Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 36/39] mmc: f-sdh30: Add quirks for broken timeout clock capability Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 37/39] mmc: renesas_sdhi: better reset from HS400 mode Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 38/39] media: si470x: Fix use-after-free in si470x_int_in_callback() Sasha Levin
2022-12-18 16:15 ` [PATCH AUTOSEL 5.10 39/39] clk: st: Fix memory leak in st_of_quadfs_setup() Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221218161559.932604-25-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=bigeasy@linutronix.de \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=imagedong@tencent.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@amazon.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=petrm@nvidia.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.