This structure will hold networking data that must consume a full cache line to avoid accidental false sharing. Signed-off-by: Eric Dumazet --- include/net/aligned_data.h | 16 ++++++++++++++++ net/core/hotdata.c | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 include/net/aligned_data.h diff --git a/include/net/aligned_data.h b/include/net/aligned_data.h new file mode 100644 index 0000000000000000000000000000000000000000..cf3329d7c2272ec4424e89352626800cbc282663 --- /dev/null +++ b/include/net/aligned_data.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _NET_ALIGNED_DATA_H +#define _NET_ALIGNED_DATA_H + +#include + +/* Structure holding cacheline aligned fields on SMP builds. + * Each field or group should have an ____cacheline_aligned_in_smp + * attribute to ensure no accidental false sharing can happen. + */ +struct net_aligned_data { +}; + +extern struct net_aligned_data net_aligned_data; + +#endif /* _NET_ALIGNED_DATA_H */ diff --git a/net/core/hotdata.c b/net/core/hotdata.c index 0bc893d5f07b03b31e08967a2238f63d218020d7..e9c03491ab001cc85fd60ad28533649b32d8a003 100644 --- a/net/core/hotdata.c +++ b/net/core/hotdata.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -22,3 +23,5 @@ struct net_hotdata net_hotdata __cacheline_aligned = { .sysctl_mem_pcpu_rsv = SK_MEMORY_PCPU_RESERVE }; EXPORT_SYMBOL(net_hotdata); + +struct net_aligned_data net_aligned_data; -- 2.50.0.727.gbf7dc18ff4-goog Using per-cpu data for net->net_cookie generation is overkill, because even busy hosts do not create hundreds of netns per second. Make sure to put net_cookie in a private cache line to avoid potential false sharing. Signed-off-by: Eric Dumazet --- include/net/aligned_data.h | 1 + net/core/net_namespace.c | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/net/aligned_data.h b/include/net/aligned_data.h index cf3329d7c2272ec4424e89352626800cbc282663..6538c66efdf90ed51836cf244237ee17019a325d 100644 --- a/include/net/aligned_data.h +++ b/include/net/aligned_data.h @@ -9,6 +9,7 @@ * attribute to ensure no accidental false sharing can happen. */ struct net_aligned_data { + atomic64_t net_cookie ____cacheline_aligned_in_smp; }; extern struct net_aligned_data net_aligned_data; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index d0f607507ee8d0b6d31f11a49421b5f0a985bd3b..e68d208b200dd4be76fc08af73054b3d1dea834c 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -19,9 +19,9 @@ #include #include #include -#include #include +#include #include #include #include @@ -64,8 +64,6 @@ DECLARE_RWSEM(pernet_ops_rwsem); static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; -DEFINE_COOKIE(net_cookie); - static struct net_generic *net_alloc_generic(void) { unsigned int gen_ptrs = READ_ONCE(max_gen_ptrs); @@ -434,9 +432,7 @@ static __net_init int setup_net(struct net *net) LIST_HEAD(net_exit_list); int error = 0; - preempt_disable(); - net->net_cookie = gen_cookie_next(&net_cookie); - preempt_enable(); + net->net_cookie = atomic64_inc_return(&net_aligned_data.net_cookie); list_for_each_entry(ops, &pernet_list, list) { error = ops_init(ops, net); -- 2.50.0.727.gbf7dc18ff4-goog ____cacheline_aligned_in_smp attribute only makes sure to align a field to a cache line. It does not prevent the linker to use the remaining of the cache line for other variables, causing potential false sharing. Move tcp_memory_allocated into a dedicated cache line. Signed-off-by: Eric Dumazet --- include/net/aligned_data.h | 3 +++ include/net/tcp.h | 1 - net/core/hotdata.c | 2 ++ net/ipv4/tcp.c | 2 -- net/ipv4/tcp_ipv4.c | 3 ++- net/ipv6/tcp_ipv6.c | 3 ++- net/mptcp/protocol.c | 3 ++- 7 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/net/aligned_data.h b/include/net/aligned_data.h index 6538c66efdf90ed51836cf244237ee17019a325d..a60c65a3b370a406b2078f23c3e332f58c84df58 100644 --- a/include/net/aligned_data.h +++ b/include/net/aligned_data.h @@ -10,6 +10,9 @@ */ struct net_aligned_data { atomic64_t net_cookie ____cacheline_aligned_in_smp; +#if defined(CONFIG_INET) + atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; +#endif }; extern struct net_aligned_data net_aligned_data; diff --git a/include/net/tcp.h b/include/net/tcp.h index 761c4a0ad386f95f73d72dc013a0952187342b51..bc08de49805cf6fc2ffbec96e42bf12378fd10cf 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -267,7 +267,6 @@ extern long sysctl_tcp_mem[3]; #define TCP_RACK_STATIC_REO_WND 0x2 /* Use static RACK reo wnd */ #define TCP_RACK_NO_DUPTHRESH 0x4 /* Do not use DUPACK threshold in RACK */ -extern atomic_long_t tcp_memory_allocated; DECLARE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); extern struct percpu_counter tcp_sockets_allocated; diff --git a/net/core/hotdata.c b/net/core/hotdata.c index e9c03491ab001cc85fd60ad28533649b32d8a003..95d0a4df10069e4529fb9e5b58e8391574085cf1 100644 --- a/net/core/hotdata.c +++ b/net/core/hotdata.c @@ -4,6 +4,7 @@ #include #include #include +#include #include struct net_hotdata net_hotdata __cacheline_aligned = { @@ -25,3 +26,4 @@ struct net_hotdata net_hotdata __cacheline_aligned = { EXPORT_SYMBOL(net_hotdata); struct net_aligned_data net_aligned_data; +EXPORT_IPV6_MOD(net_aligned_data); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8a3c99246d2ed32ba45849b56830bf128e265763..925b2c572ca23b3f2eba48a38820f6553a2724f4 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -302,8 +302,6 @@ EXPORT_PER_CPU_SYMBOL_GPL(tcp_tw_isn); long sysctl_tcp_mem[3] __read_mostly; EXPORT_IPV6_MOD(sysctl_tcp_mem); -atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; /* Current allocated memory. */ -EXPORT_IPV6_MOD(tcp_memory_allocated); DEFINE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc); EXPORT_PER_CPU_SYMBOL_GPL(tcp_memory_per_cpu_fw_alloc); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 429fb34b075e0bdad0e1c55dd6b1101b3dfe78dd..a9e1d19ffae4159fe1d6da4d2e8ee69e64f8dd55 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -59,6 +59,7 @@ #include #include +#include #include #include #include @@ -3391,7 +3392,7 @@ struct proto tcp_prot = { .sockets_allocated = &tcp_sockets_allocated, .orphan_count = &tcp_orphan_count, - .memory_allocated = &tcp_memory_allocated, + .memory_allocated = &net_aligned_data.tcp_memory_allocated, .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, .memory_pressure = &tcp_memory_pressure, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f0ce62549d90d6492b8ab139640cca91e4a9c2c7..20d51941e58ae830ab254c4681cc95fd740b88df 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -2357,7 +2358,7 @@ struct proto tcpv6_prot = { .stream_memory_free = tcp_stream_memory_free, .sockets_allocated = &tcp_sockets_allocated, - .memory_allocated = &tcp_memory_allocated, + .memory_allocated = &net_aligned_data.tcp_memory_allocated, .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, .memory_pressure = &tcp_memory_pressure, diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index e7972e633236e0451f0321ff4b0a8d1b37282d5f..5f904fc5ac4c63e8b6c7c9aa79f17e8dcdf1a007 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -3729,7 +3730,7 @@ static struct proto mptcp_prot = { .stream_memory_free = mptcp_stream_memory_free, .sockets_allocated = &mptcp_sockets_allocated, - .memory_allocated = &tcp_memory_allocated, + .memory_allocated = &net_aligned_data.tcp_memory_allocated, .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, .memory_pressure = &tcp_memory_pressure, -- 2.50.0.727.gbf7dc18ff4-goog ____cacheline_aligned_in_smp attribute only makes sure to align a field to a cache line. It does not prevent the linker to use the remaining of the cache line for other variables, causing potential false sharing. Signed-off-by: Eric Dumazet --- include/net/aligned_data.h | 1 + include/net/udp.h | 1 - net/ipv4/udp.c | 4 +--- net/ipv4/udp_impl.h | 1 + net/ipv4/udplite.c | 2 +- net/ipv6/udp.c | 2 +- net/ipv6/udp_impl.h | 1 + net/ipv6/udplite.c | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/net/aligned_data.h b/include/net/aligned_data.h index a60c65a3b370a406b2078f23c3e332f58c84df58..fc07461e31352eb757c34867ea9b458fb9e539f4 100644 --- a/include/net/aligned_data.h +++ b/include/net/aligned_data.h @@ -12,6 +12,7 @@ struct net_aligned_data { atomic64_t net_cookie ____cacheline_aligned_in_smp; #if defined(CONFIG_INET) atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp; + atomic_long_t udp_memory_allocated ____cacheline_aligned_in_smp; #endif }; diff --git a/include/net/udp.h b/include/net/udp.h index a772510b2aa58a922dc4dd5bd7cb7f7f0c1ce0e3..f8ae2c4ade141d27e4af3376f5a177e46d5b39ea 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -205,7 +205,6 @@ static inline void udp_hash4_dec(struct udp_hslot *hslot2) extern struct proto udp_prot; -extern atomic_long_t udp_memory_allocated; DECLARE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); /* sysctl variables for udp */ diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 19573ee64a0f18cf55df34ace1956e9c3e20172c..49f43c54cfb0e3ac85c1a6202f3d6a2f1ca6d0ba 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -127,8 +127,6 @@ struct udp_table udp_table __read_mostly; long sysctl_udp_mem[3] __read_mostly; EXPORT_IPV6_MOD(sysctl_udp_mem); -atomic_long_t udp_memory_allocated ____cacheline_aligned_in_smp; -EXPORT_IPV6_MOD(udp_memory_allocated); DEFINE_PER_CPU(int, udp_memory_per_cpu_fw_alloc); EXPORT_PER_CPU_SYMBOL_GPL(udp_memory_per_cpu_fw_alloc); @@ -3235,7 +3233,7 @@ struct proto udp_prot = { #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = udp_bpf_update_proto, #endif - .memory_allocated = &udp_memory_allocated, + .memory_allocated = &net_aligned_data.udp_memory_allocated, .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, .sysctl_mem = sysctl_udp_mem, diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index e1ff3a37599614b18a0b621534019a7bd71ea901..c7142213fc2112c9e423caa5e6d84bafeaca9936 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _UDP4_IMPL_H #define _UDP4_IMPL_H +#include #include #include #include diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index af37af3ab727bffeebe5c41d84cb7c130f49c50d..d3e621a11a1aa4cafb62eb53ddc0ed1ca517a7fe 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -60,7 +60,7 @@ struct proto udplite_prot = { .rehash = udp_v4_rehash, .get_port = udp_v4_get_port, - .memory_allocated = &udp_memory_allocated, + .memory_allocated = &net_aligned_data.udp_memory_allocated, .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, .sysctl_mem = sysctl_udp_mem, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ebb95d8bc6819f72842fd1567e73fcef4f1e0ed0..6bbdadbd5fecccfb7de99f05c6fb179393e162f2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1925,7 +1925,7 @@ struct proto udpv6_prot = { .psock_update_sk_prot = udp_bpf_update_proto, #endif - .memory_allocated = &udp_memory_allocated, + .memory_allocated = &net_aligned_data.udp_memory_allocated, .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, .sysctl_mem = sysctl_udp_mem, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 0590f566379d7d07dfdd1b0ae808b9d8964eb5aa..8a406be25a3a6dee687a6a02ea0b6a28428abb86 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _UDP6_IMPL_H #define _UDP6_IMPL_H +#include #include #include #include diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index a60bec9b14f14a5b2d271f9965b5fca3d2a440c8..2cec542437f74eba9540fc464ee70d8b0bc0be79 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -59,7 +59,7 @@ struct proto udplitev6_prot = { .rehash = udp_v6_rehash, .get_port = udp_v6_get_port, - .memory_allocated = &udp_memory_allocated, + .memory_allocated = &net_aligned_data.udp_memory_allocated, .per_cpu_fw_alloc = &udp_memory_per_cpu_fw_alloc, .sysctl_mem = sysctl_udp_mem, -- 2.50.0.727.gbf7dc18ff4-goog