Thread (7 messages) 7 messages, 3 authors, 2020-01-17
STALE2351d

[PATCH net 3/3] udp: avoid bulk memory scheduling on memory pressure.

From: Paolo Abeni <pabeni@redhat.com>
Date: 2020-01-17 17:28:38
Subsystem: networking [general], the rest, user datagram protocol (udp) · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Willem de Bruijn

Williem reported that after commit 0d4a6608f68c ("udp: do rmem bulk
free even if the rx sk queue is empty") the memory allocated by
an almost idle system with many UDP sockets can grow a lot.

This change addresses the issue enabling memory pressure tracking
for UDP and flushing the fwd allocated memory on dequeue if the
UDP protocol is under memory pressure.

Note that with this patch applied, the system allocates more
liberally memory for UDP sockets while the total memory usage is
below udp_mem[1], while the vanilla kernel would allow at most a
single page per socket when UDP memory usage goes above udp_mem[0]
- see __sk_mem_raise_allocated().

Reported-and-diagnosed-by: Willem de Bruijn [off-list ref]
Fixes: commit 0d4a6608f68c ("udp: do rmem bulk free even if the rx sk queue is empty")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
 include/net/udp.h |  2 ++
 net/ipv4/udp.c    | 13 ++++++++++++-
 net/ipv6/udp.c    |  2 ++
 3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/include/net/udp.h b/include/net/udp.h
index bad74f780831..cff730798291 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -94,6 +94,8 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
 extern struct proto udp_prot;
 
 extern atomic_long_t udp_memory_allocated;
+extern unsigned long udp_memory_pressure;
+extern struct percpu_counter udp_sockets_allocated;
 
 /* sysctl variables for udp */
 extern long sysctl_udp_mem[3];
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 93a355b6b092..3a68ec6c3410 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -119,6 +119,12 @@ EXPORT_SYMBOL(udp_table);
 long sysctl_udp_mem[3] __read_mostly;
 EXPORT_SYMBOL(sysctl_udp_mem);
 
+unsigned long udp_memory_pressure __read_mostly;
+EXPORT_SYMBOL(udp_memory_pressure);
+
+struct percpu_counter udp_sockets_allocated;
+EXPORT_SYMBOL(udp_sockets_allocated);
+
 atomic_long_t udp_memory_allocated;
 EXPORT_SYMBOL(udp_memory_allocated);
 
@@ -1368,7 +1374,8 @@ static void udp_rmem_release(struct sock *sk, int size, int partial,
 	if (likely(partial)) {
 		up->forward_deficit += size;
 		size = up->forward_deficit;
-		if (size < (sk->sk_rcvbuf >> 2))
+		if (size < (sk->sk_rcvbuf >> 2) &&
+		    !READ_ONCE(udp_memory_pressure))
 			return;
 	} else {
 		size += up->forward_deficit;
@@ -2789,7 +2796,9 @@ struct proto udp_prot = {
 	.unhash			= udp_lib_unhash,
 	.rehash			= udp_v4_rehash,
 	.get_port		= udp_v4_get_port,
+	.memory_pressure	= &udp_memory_pressure,
 	.memory_allocated	= &udp_memory_allocated,
+	.sockets_allocated	= &udp_sockets_allocated,
 	.sysctl_mem		= sysctl_udp_mem,
 	.sysctl_wmem_offset	= offsetof(struct net, ipv4.sysctl_udp_wmem_min),
 	.sysctl_rmem_offset	= offsetof(struct net, ipv4.sysctl_udp_rmem_min),
@@ -3062,6 +3071,8 @@ void __init udp_init(void)
 	sysctl_udp_mem[1] = limit;
 	sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2;
 
+	percpu_counter_init(&udp_sockets_allocated, 0, GFP_KERNEL);
+
 	__udp_sysctl_init(&init_net);
 
 	/* 16 spinlocks per cpu */
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9fec580c968e..b29d92574ccc 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1670,7 +1670,9 @@ struct proto udpv6_prot = {
 	.unhash			= udp_lib_unhash,
 	.rehash			= udp_v6_rehash,
 	.get_port		= udp_v6_get_port,
+	.memory_pressure	= &udp_memory_pressure,
 	.memory_allocated	= &udp_memory_allocated,
+	.sockets_allocated	= &udp_sockets_allocated,
 	.sysctl_mem		= sysctl_udp_mem,
 	.sysctl_wmem_offset     = offsetof(struct net, ipv4.sysctl_udp_wmem_min),
 	.sysctl_rmem_offset     = offsetof(struct net, ipv4.sysctl_udp_rmem_min),
-- 
2.21.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help