Skip to contentSkip to conversation

UDP memory accounting and limitation (take 12)

PATCH In review Hideo AOKI 4 participants 14 messages Dec 30, 2007 – Jan 11, 2008

Subsystems (6)
lore
Share & tools
lore

Hideo AOKI

author
#0 lore raw

cover UDP memory accounting and limitation (take 12)

Hello,

This is the latest patch set of UDP memory accounting and limitation.

I split my patch set into accounting interface consolidation and UDP memory accounting support. This patch set implements UDP memory accounting support.

To use consolidated accounting functions, I matched format of udp_mem sysctl with tcp_mem. UDP IPv6 is finally supported.

However, currently, only receive buffer accounting is implemented.

The patch set was tested on net-2.6.25 tree.

Changelog take 11 -> take 12:
* split into accounting interface consolidation and UDP memory accounting support.
* used new accounting interface
* supported IPv6
* dropped send buffer accounting

Changelog take 10 -> take 11:
* stoped using spin lock in memory accounting function
* socket lock and backlog processing were used to avoid conflict between receive system call processing and BH
* revised memory accounting functions
* stooped changing sock_queue_rcv_skb() and skb_set_owner_r()
* added __udp_queue_rcv_skb to set proper destructor
* removed udp_set_owner_r()
* removed reclaim in inet_sock_destruct()

Changelog take 9 -> take 10:
* supported using sk_forward_alloc
* introduced several memory accounting functions with spin lock
* changed detagram receive functions to be able to customize destructor
* fixed accounting bugs in previous takes

Best regards,
Hideo Aoki

--
Hitachi Computer Products (America) Inc.

author
#1 lore raw

PATCH 1/3 : add udp_mem, udp_rmem_min and udp_wmem_min

This patch adds sysctl parameters for customizing UDP memory accounting:

     /proc/sys/net/ipv4/udp_mem
     /proc/sys/net/ipv4/udp_rmem_min
     /proc/sys/net/ipv4/udp_wmem_min

Udp_mem indicates number of pages which can be used for all UDP scokets. Each UDP packet is dropped, when the number of pages for socket buffer is beyond udp_mem and the socket already consumes minimum buffer.

Cc Satoshi Oshima <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 Documentation/networking/ip-sysctl.txt |   27 +++++++++++++++++++++++++++
 include/net/udp.h                      |    7 +++++++
 net/ipv4/af_inet.c                     |    3 +++
 net/ipv4/proc.c                        |    3 ++-
 net/ipv4/sysctl_net_ipv4.c             |   31 +++++++++++++++++++++++++++++++
 net/ipv4/udp.c                         |   31 +++++++++++++++++++++++++++++++
 6 files changed, 101 insertions(+), 1 deletion(-)
Documentation/networking/ip-sysctl.txt +27 -0
diff -pruN net-2.6.25-t12t19m-p4/Documentation/networking/ip-sysctl.txt net-2.6.25-t12t19m-p5/Documentation/networking/ip-sysctl.txt
@@ -446,6 +446,33 @@ tcp_dma_copybreak - INTEGER
 	and CONFIG_NET_DMA is enabled.
 	Default: 4096
 
+UDP variables:
+
+udp_mem - vector of 3 INTEGERs: min, pressure, max
+	Number of pages allowed for queueing by all UDP sockets.
+
+	min: Below this number of pages UDP is not bothered about its
+	memory appetite. When amount of memory allocated by UDP exceeds
+	this number, UDP starts to moderate memory usage.
+
+	pressure: This value was introduced to follow format of tcp_mem.
+
+	max: Number of pages allowed for queueing by all UDP sockets.
+
+	Default is calculated at boot time from amount of available memory.
+
+udp_rmem_min - INTEGER
+	Minimal size of receive buffer used by UDP sockets in moderation.
+	Each UDP socket is able to use the size for receiving data, even if
+	total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
+	Default: 4096
+
+udp_wmem_min - INTEGER
+	Minimal size of send buffer used by UDP sockets in moderation.
+	Each UDP socket is able to use the size for sending data, even if
+	total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
+	Default: 4096
+
 CIPSOv4 Variables:
 
 cipso_cache_enable - BOOLEAN
include/net/udp.h +7 -0
diff -pruN net-2.6.25-t12t19m-p4/include/net/udp.h net-2.6.25-t12t19m-p5/include/net/udp.h
@@ -65,6 +65,11 @@ extern rwlock_t udp_hash_lock;
 
 extern struct proto udp_prot;
 
+/* sysctl variables for udp */
+extern int sysctl_udp_mem[3];
+extern int sysctl_udp_rmem_min;
+extern int sysctl_udp_wmem_min;
+
 struct sk_buff;
 
 /*
@@ -198,4 +203,6 @@ extern void udp_proc_unregister(struct u
 extern int  udp4_proc_init(void);
 extern void udp4_proc_exit(void);
 #endif
+
+extern void udp_init(void);
 #endif	/* _UDP_H */
net/ipv4/af_inet.c +3 -0
diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/af_inet.c net-2.6.25-t12t19m-p5/net/ipv4/af_inet.c
@@ -1417,6 +1417,9 @@ static int __init inet_init(void)
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
 
+	/* Setup UDP memory threshold */
+	udp_init();
+
 	/* Add UDP-Lite (RFC 3828) */
 	udplite4_register();
 
net/ipv4/proc.c +2 -1
diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/proc.c net-2.6.25-t12t19m-p5/net/ipv4/proc.c
@@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_
 		   sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n",
net/ipv4/sysctl_net_ipv4.c +31 -0
diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/sysctl_net_ipv4.c net-2.6.25-t12t19m-p5/net/ipv4/sysctl_net_ipv4.c
@@ -19,6 +19,7 @@
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/tcp.h>
+#include <net/udp.h>
 #include <net/cipso_ipv4.h>
 #include <net/inet_frag.h>
 
@@ -812,6 +813,36 @@ static struct ctl_table ipv4_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
 	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "udp_mem",
+		.data		= &sysctl_udp_mem,
+		.maxlen		= sizeof(sysctl_udp_mem),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "udp_rmem_min",
+		.data		= &sysctl_udp_rmem_min,
+		.maxlen		= sizeof(sysctl_udp_rmem_min),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "udp_wmem_min",
+		.data		= &sysctl_udp_wmem_min,
+		.maxlen		= sizeof(sysctl_udp_wmem_min),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &zero
+	},
 	{ .ctl_name = 0 }
 };
 
net/ipv4/udp.c +31 -0
diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/udp.c net-2.6.25-t12t19m-p5/net/ipv4/udp.c
@@ -82,6 +82,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
+#include <linux/bootmem.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/module.h>
@@ -118,6 +119,14 @@ EXPORT_SYMBOL(udp_stats_in6);
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
 
+int sysctl_udp_mem[3] __read_mostly;
+int sysctl_udp_rmem_min __read_mostly;
+int sysctl_udp_wmem_min __read_mostly;
+
+EXPORT_SYMBOL(sysctl_udp_mem);
+EXPORT_SYMBOL(sysctl_udp_rmem_min);
+EXPORT_SYMBOL(sysctl_udp_wmem_min);
+
 static inline int __udp_lib_lport_inuse(__u16 num,
 					const struct hlist_head udptable[])
 {
@@ -1460,6 +1469,9 @@ struct proto udp_prot = {
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
+	.sysctl_mem	   = sysctl_udp_mem,
+	.sysctl_wmem	   = &sysctl_udp_wmem_min,
+	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp_sock),
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
@@ -1655,6 +1667,25 @@ void udp4_proc_exit(void)
 }
 #endif /* CONFIG_PROC_FS */
 
+void __init udp_init(void)
+{
+	unsigned long limit;
+
+	/* Set the pressure threshold up by the same strategy of TCP. It is a
+	 * fraction of global memory that is up to 1/2 at 256 MB, decreasing
+	 * toward zero with the amount of memory, with a floor of 128 pages.
+	 */
+	limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
+	limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
+	limit = max(limit, 128UL);
+	sysctl_udp_mem[0] = limit / 4 * 3;
+	sysctl_udp_mem[1] = limit;
+	sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2;
+
+	sysctl_udp_rmem_min = SK_MEM_QUANTUM;
+	sysctl_udp_wmem_min = SK_MEM_QUANTUM;
+}
+
 EXPORT_SYMBOL(udp_disconnect);
 EXPORT_SYMBOL(udp_hash);
 EXPORT_SYMBOL(udp_hash_lock);
Signature · 1 line
Hitachi Computer Products (America) Inc.
maintainer
#2 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

From: Hideo AOKI <[email protected]>
Date: Sun, 30 Dec 2007 04:01:46 -0500

net/ipv4/proc.c static int sockstat_seq_show(struct seq_ · line 63

Quoted 13 lines

diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/proc.c net-2.6.25-t12t19m-p5/net/ipv4/proc.c

net/ipv4/proc.c +2 -1
@@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_
 		   sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n",

More careless patch creation. :-/

This breaks the build because udp_memory_allocated is not added until patch 2.

Once again I'll combine all three patches into one but I am extremely angry about how careless and broken these two patch submissions were.

#3 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

Quoted 19 lines · David Miller

From: Hideo AOKI <[email protected]>
Date: Sun, 30 Dec 2007 04:01:46 -0500

net/ipv4/proc.c static int sockstat_seq_show(struct seq_ · line 63

Quoted 13 lines

diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/proc.c net-2.6.25-t12t19m-p5/net/ipv4/proc.c

net/ipv4/proc.c +2 -1
@@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_
 		   sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n",

More careless patch creation. :-/

Quoted 5 lines

This breaks the build because udp_memory_allocated is not added until patch 2.

Once again I'll combine all three patches into one but I am extremely angry about how careless and broken these two patch submissions were.

I am a litle bit concerned about performance of IVR servers using SIP protocol.

On those servers, each active channel typically emits/receives 50 UDP/RTP frames per second. With G729 codec, each packet contains 10 bytes of payload, and about 40 bytes of IP/UDP/RTP encapsulation. (So these messages are very small)

As I am currently enjoying hollidays at home, I am not able to test on my server farm the performance impact of this new UDP receive accounting.

If I understand well the patch, each time a packet is received (on a socket
with no previous message available in its receive queue), we are going to atomic_inc(&some_global_var). Then the user thread that will transfert this message to user land will atomic_dec(&some_global_var). (Granted server is
in normal condition, ie each UDP socket holds at most one message in its
receive or transmit queue)

I have some machines with 400 active SIP channels, so that new hot cache line will probably slow down our SMP servers, because of cache line ping pong.

I will probably setup a test next week and let you know the results.

Maybe I read the patch incorrectly, or we could add some new sysctl so that
we not try to uncharge memory if a socket 'forward_alloc' is beyond a given limit (say 2 pages), so that number of atomic_inc/dec on udp_memory_allocated (or tcp_memory_allocated) is reduced.

Thank you

#4 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

Quoted 5 lines · Eric Dumazet

Maybe I read the patch incorrectly, or we could add some new sysctl so that we not try to uncharge memory if a socket 'forward_alloc' is beyond a given limit (say 2 pages), so that number of atomic_inc/dec on udp_memory_allocated (or tcp_memory_allocated) is reduced.

I don't have time to go through these patches right now but that was the whole point of using forward_alloc, i.e., avoid touching the global for every packet.

So if it's still doing that then we're doing something wrong.

Cheers,

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
maintainer
#5 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

In reply to Eric Dumazet

From: Eric Dumazet <[email protected]>
Date: Mon, 31 Dec 2007 09:54:32 +0100

Quoted 4 lines

Maybe I read the patch incorrectly, or we could add some new sysctl so that we not try to uncharge memory if a socket 'forward_alloc' is beyond a given limit (say 2 pages), so that number of atomic_inc/dec on udp_memory_allocated (or tcp_memory_allocated) is reduced.

This is what we should be striving for, using forward_alloc as much as possible as a "cache" to avoid the atomics on the global var as much as possible.

#6 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

Quoted 9 lines · David Miller

From: Eric Dumazet <[email protected]>
Date: Mon, 31 Dec 2007 09:54:32 +0100

Quoted 2 lines

Maybe I read the patch incorrectly, or we could add some new sysctl so that
we not try to uncharge memory if a socket 'forward_alloc' is beyond a given limit (say 2 pages), so that number of atomic_inc/dec on udp_memory_allocated (or tcp_memory_allocated) is reduced.

This is what we should be striving for, using forward_alloc as much as possible as a "cache" to avoid the atomics on the global var as much as possible.

Thank you for this confirmation David, I understand now that tcp doesnt currently satisfy the contract.

For example, tcp_delack_timer() calls sk_mem_reclaim().

So on a machine with a lot of mostly idle sockets (but all sockets are doing some trafic, say one message per minute / socket), we can see :

$ grep TCP /proc/net/sockstat
TCP: inuse 1083667 orphan 8840 tw 6646 alloc 1083809 mem 262305
$ cat /proc/sys/net/ipv4/tcp_mem
2000000 3000000 4000000

so an average of 1/4 page are 'allocated' per socket :(

On this machine, we constantly change tcp_memory_allocated, even if we always are under tcp_mem[0] limit.

Maybe we need to introduce some mechanism to let sk_forward between 0 and SK_MEM_QUANTUM (inclusive).

static inline void sk_mem_reclaim_overpage(struct sock *sk)

{
        if (sk->sk_forward_alloc > SK_MEM_QUANTUM) {
                __sk_mem_reclaim(sk);
		}
}

and use sk_mem_reclaim_overpage() instead of sk_mem_reclaim() in tcp_delack_timer() ?

Thank you

Small program output :

$ gcc -o prog prog.c ; ./prog
TCP: inuse 1035 orphan 0 tw 271 alloc 1203 mem 16
TCP: inuse 1035 orphan 0 tw 271 alloc 1203 mem 4016
TCP: inuse 1034 orphan 0 tw 272 alloc 1202 mem 3015
TCP: inuse 1034 orphan 0 tw 272 alloc 1202 mem 3016
TCP: inuse 1034 orphan 0 tw 272 alloc 1202 mem 3516
TCP: inuse 1034 orphan 0 tw 272 alloc 1202 mem 14 <OOPS>
$ cat prog.c
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <asm/ioctls.h>
#include <stdio.h>

int SOCK_COUNT = 1000;
int *sockets_fd_tab;
unsigned int count;

static void open_sockets(int domain, int type)

{
        int fdlisten=-1, on = 1;
        socklen_t addrlen;
        struct sockaddr_in host, peer;

        if (domain == AF_INET && type == SOCK_STREAM) {
                fdlisten = socket(AF_INET, type, 0);
                setsockopt(fdlisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
                memset(&host, 0, sizeof(host));
                host.sin_family = AF_INET;
                bind(fdlisten, (struct sockaddr *)&host, sizeof(host));
                addrlen = sizeof(host);
                getsockname(fdlisten, (struct sockaddr *)&host, &addrlen);
                listen(fdlisten, 5);
        }
        while (1) {
                int res, vec[2];
                if (domain == AF_UNIX) {
                        res = socketpair(AF_UNIX, type, 0, vec);
                        if (res == -1)
                                break;
                } else {
                        vec[0] = socket(AF_INET, type, 0);
                        if (vec[0] == -1)
                                break;
                        ioctl(vec[0], FIONBIO, &on);
                        if (type == SOCK_STREAM) {
                                connect(vec[0], (struct sockaddr *)&host, 
sizeof(host));
                                addrlen = sizeof(peer);
                                vec[1] = accept(fdlisten, (struct sockaddr 
*)&peer, &addrlen);
                                if (vec[1] == -1) {
                                        close(vec[0]);
                                        break;
                                }
                        } else {
                        }
                }
                sockets_fd_tab[count++] = vec[0];
                sockets_fd_tab[count++] = vec[1];
                if (count == SOCK_COUNT)
                        break;
        }
}

const char some_msg[1024] = "One dummy message";

static void fill_sockets()

{
        unsigned int ui;
        for (ui = 0; ui < count; ui++)
                send(sockets_fd_tab[ui], some_msg, 100, 0);
        for (ui = 0; ui < count; ui++)
                send(sockets_fd_tab[ui], some_msg, 100, 0);
}

static void empty_sockets()

{
        unsigned int ui;
        char buffer[4096];

        for (ui = 0; ui < count; ui++)
                recv(sockets_fd_tab[ui], buffer, sizeof(buffer), 0);
}

static void dump_infos()

{
        system("grep TCP /proc/net/sockstat");
}

int main(int argc, char *argv[])

{
        int c;
        while ((c = getopt(argc, argv, "n:")) != EOF) {
                if (c == 'n')
                        SOCK_COUNT = atoi(optarg);
        }
        sockets_fd_tab = malloc(SOCK_COUNT * sizeof(int));
        open_sockets(AF_INET, SOCK_STREAM);
        dump_infos();

        fill_sockets();
        dump_infos();
        sleep(1); /* to see effect of delayed acks */
        dump_infos();
        empty_sockets();
        dump_infos();

        fill_sockets();
        dump_infos();
        empty_sockets();
        sleep(1); /* to see effect of delayed acks */
        dump_infos();

        return 0;
}
maintainer
#7 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

From: Eric Dumazet <[email protected]>
Date: Mon, 31 Dec 2007 15:42:42 +0100

Quoted 4 lines

Maybe we need to introduce some mechanism to let sk_forward between 0 and SK_MEM_QUANTUM (inclusive).

static inline void sk_mem_reclaim_overpage(struct sock *sk)

Quoted 8 lines
{
         if (sk->sk_forward_alloc > SK_MEM_QUANTUM) {
                 __sk_mem_reclaim(sk);
		}
}

and use sk_mem_reclaim_overpage() instead of sk_mem_reclaim() in tcp_delack_timer() ?

This makes a lot of sense to me, it is definitely doing the wrong thing here for the load you describe.

I've applied the following to net-2.6.25 and I am definitely willing to put this into 2.6.24 and -stable if you think that's worthwhile too.

[TCP]: Do not purge sk_forward_alloc entirely in tcp_delack_timer().

Otherwise we beat heavily on the global tcp_memory atomics when all of the sockets in the system are slowly sending perioding packet clumps.

Noticed and suggested by Eric Dumazet.

---
 include/net/sock.h   |    8 ++++++++
 net/ipv4/tcp_timer.c |    2 +-
 2 files changed, 9 insertions(+), 1 deletions(-)
include/net/sock.h +8 -0
index 89e04e4..d24b826 100644
@@ -759,6 +759,14 @@ static inline void sk_mem_reclaim(struct sock *sk)
 		__sk_mem_reclaim(sk);
 }
 
+static inline void sk_mem_reclaim_partial(struct sock *sk)
+{
+	if (!sk_has_account(sk))
+		return;
+	if (sk->sk_forward_alloc > SK_MEM_QUANTUM)
+		__sk_mem_reclaim(sk);
+}
+
 static inline void sk_mem_charge(struct sock *sk, int size)
 {
 	if (!sk_has_account(sk))
net/ipv4/tcp_timer.c +1 -1
index 17931be..803d758 100644
@@ -186,7 +186,7 @@ static void tcp_delack_timer(unsigned long data)
 		goto out_unlock;
 	}
 
-	sk_mem_reclaim(sk);
+	sk_mem_reclaim_partial(sk);
 
 	if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
 		goto out;
Signature · 1 line
1.5.4.rc2.84.gf85fd
author
#8 lore raw

Re: [PATCH 1/3] [UDP]: add udp_mem, udp_rmem_min and udp_wmem_min

In reply to David Miller
Quoted 19 lines · David Miller

From: Hideo AOKI <[email protected]>
Date: Sun, 30 Dec 2007 04:01:46 -0500

net/ipv4/proc.c static int sockstat_seq_show(struct seq_ · line 63

Quoted 13 lines

diff -pruN net-2.6.25-t12t19m-p4/net/ipv4/proc.c net-2.6.25-t12t19m-p5/net/ipv4/proc.c

net/ipv4/proc.c +2 -1
@@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_
 		   sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n",

More careless patch creation. :-/

Quoted 2 lines

This breaks the build because udp_memory_allocated is not added until patch 2.

Hello David,

You are absolutely right.

Quoted 2 lines

Once again I'll combine all three patches into one but I am extremely angry about how careless and broken these two patch submissions were.

I really apologize for wasting your time twice.
I do not do this kind mess again.

Many thanks for your support.

Best regards,
Hideo

Signature · 1 line
Hitachi Computer Products (America) Inc.
author
#9 lore raw

PATCH 2/3 : memory accounting in IPv4

In reply to Hideo AOKI

This patch adds UDP memory usage accounting in IPv4. Currently, receiving buffer accounting is only supported.

This patch is also introduced memory_allocated variable for UDP protocol.

Cc Satoshi Oshima <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 include/net/udp.h  |    2 ++
 net/ipv4/af_inet.c |    2 ++
 net/ipv4/udp.c     |   26 ++++++++++++++++++++++++--
 3 files changed, 28 insertions(+), 2 deletions(-)
include/net/udp.h +2 -0
diff -pruN net-2.6.25-t12t19m-p5/include/net/udp.h net-2.6.25-t12t19m-p6/include/net/udp.h
@@ -65,6 +65,8 @@ extern rwlock_t udp_hash_lock;
 
 extern struct proto udp_prot;
 
+extern atomic_t udp_memory_allocated;
+
 /* sysctl variables for udp */
 extern int sysctl_udp_mem[3];
 extern int sysctl_udp_rmem_min;
net/ipv4/af_inet.c +2 -0
diff -pruN net-2.6.25-t12t19m-p5/net/ipv4/af_inet.c net-2.6.25-t12t19m-p6/net/ipv4/af_inet.c
@@ -139,6 +139,8 @@ void inet_sock_destruct(struct sock *sk)
 	__skb_queue_purge(&sk->sk_receive_queue);
 	__skb_queue_purge(&sk->sk_error_queue);
 
+	sk_mem_reclaim(sk);
+
 	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
 		printk("Attempt to release TCP socket in state %d %p\n",
 		       sk->sk_state, sk);
net/ipv4/udp.c +24 -2
diff -pruN net-2.6.25-t12t19m-p5/net/ipv4/udp.c net-2.6.25-t12t19m-p6/net/ipv4/udp.c
@@ -127,6 +127,9 @@ EXPORT_SYMBOL(sysctl_udp_mem);
 EXPORT_SYMBOL(sysctl_udp_rmem_min);
 EXPORT_SYMBOL(sysctl_udp_wmem_min);
 
+atomic_t udp_memory_allocated;
+EXPORT_SYMBOL(udp_memory_allocated);
+
 static inline int __udp_lib_lport_inuse(__u16 num,
 					const struct hlist_head udptable[])
 {
@@ -910,13 +913,17 @@ try_again:
 		err = ulen;
 
 out_free:
+	lock_sock(sk);
 	skb_free_datagram(sk, skb);
+	release_sock(sk);
 out:
 	return err;
 
 csum_copy_err:
+	lock_sock(sk);
 	if (!skb_kill_datagram(sk, skb, flags))
 		UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
+	release_sock(sk);
 
 	if (noblock)
 		return -EAGAIN;
@@ -1081,7 +1088,15 @@ static int __udp4_lib_mcast_deliver(stru
 				skb1 = skb_clone(skb, GFP_ATOMIC);
 
 			if (skb1) {
-				int ret = udp_queue_rcv_skb(sk, skb1);
+				int ret = 0;
+
+				bh_lock_sock_nested(sk);
+				if (!sock_owned_by_user(sk))
+					ret = udp_queue_rcv_skb(sk, skb1);
+				else
+					sk_add_backlog(sk, skb1);
+				bh_unlock_sock(sk);
+
 				if (ret > 0)
 					/* we should probably re-process instead
 					 * of dropping packets here. */
@@ -1174,7 +1189,13 @@ int __udp4_lib_rcv(struct sk_buff *skb,
 			       inet_iif(skb), udptable);
 
 	if (sk != NULL) {
-		int ret = udp_queue_rcv_skb(sk, skb);
+		int ret = 0;
+		bh_lock_sock_nested(sk);
+		if (!sock_owned_by_user(sk))
+			ret = udp_queue_rcv_skb(sk, skb);
+		else
+			sk_add_backlog(sk, skb);
+		bh_unlock_sock(sk);
 		sock_put(sk);
 
 		/* a return value > 0 means to resubmit the input, but
@@ -1469,6 +1490,7 @@ struct proto udp_prot = {
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
+	.memory_allocated  = &udp_memory_allocated,
 	.sysctl_mem	   = sysctl_udp_mem,
 	.sysctl_wmem	   = &sysctl_udp_wmem_min,
 	.sysctl_rmem	   = &sysctl_udp_rmem_min,
Signature · 1 line
Hitachi Computer Products (America) Inc.
#10 lore raw

Re: [PATCH 2/3] [UDP]: memory accounting in IPv4

Quoted 4 lines · Hideo AOKI

This patch adds UDP memory usage accounting in IPv4. Currently, receiving buffer accounting is only supported.

This patch is also introduced memory_allocated variable for UDP protocol.

OK, but sockstat_seq_show() should be updated so that this udp_memory_allocated value can be read from /proc/net/sockstat ?

Thank you

author
#11 lore raw

Re: [PATCH 2/3] [UDP]: memory accounting in IPv4

Quoted 8 lines · Eric Dumazet
Quoted 4 lines · Hideo AOKI

This patch adds UDP memory usage accounting in IPv4. Currently, receiving buffer accounting is only supported.

This patch is also introduced memory_allocated variable for UDP protocol.

OK, but sockstat_seq_show() should be updated so that this udp_memory_allocated value can be read from /proc/net/sockstat ?

Yes, and I updated it in the first patch of the patch set.

I thought dividing patch made easy to review. But I was wrong. Sorry about that.

Regards,
Hideo

Signature · 1 line
Hitachi Computer Products (America) Inc.
#12 lore raw

Re: [PATCH 2/3] [UDP]: memory accounting in IPv4

Quoted 5 lines · Hideo AOKI
Quoted 4 lines · Eric Dumazet
Quoted 3 lines · Hideo AOKI

This patch adds UDP memory usage accounting in IPv4. Currently, receiving buffer accounting is only supported.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

This patch is also introduced memory_allocated variable for UDP protocol.

OK, but sockstat_seq_show() should be updated so that this udp_memory_allocated value can be read from /proc/net/sockstat ?

Yes, and I updated it in the first patch of the patch set.

I thought dividing patch made easy to review. But I was wrong. Sorry about that.

No problem Hideo, I think you did a good job with this UDP memory accounting and were very patient.

Thank you

author
#13 lore raw

PATCH 3/3 : memory accounting in IPv6

In reply to Hideo AOKI

This patch adds UDP memory usage accounting in IPv6. Currently, receiving buffer accounting is only supported.

This patch is also introduced memory_allocated variable for UDP protocol.

Cc Satoshi Oshima <[email protected]>
Cc Masami Hiramatsu <[email protected]>

---

 udp.c |   32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)
net/ipv6/udp.c +28 -4
diff -pruN net-2.6.25-t12t19m-p6/net/ipv6/udp.c net-2.6.25-t12t19m-p7/net/ipv6/udp.c
@@ -204,13 +204,17 @@ try_again:
 		err = ulen;
 
 out_free:
+	lock_sock(sk);
 	skb_free_datagram(sk, skb);
+	release_sock(sk);
 out:
 	return err;
 
 csum_copy_err:
+	lock_sock(sk);
 	if (!skb_kill_datagram(sk, skb, flags))
 		UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
+	release_sock(sk);
 
 	if (flags & MSG_DONTWAIT)
 		return -EAGAIN;
@@ -366,10 +370,21 @@ static int __udp6_lib_mcast_deliver(stru
 	while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr,
 					uh->source, saddr, dif))) {
 		struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
-		if (buff)
-			udpv6_queue_rcv_skb(sk2, buff);
+		if (buff) {
+			bh_lock_sock_nested(sk2);
+			if (!sock_owned_by_user(sk2))
+				udpv6_queue_rcv_skb(sk2, buff);
+			else
+				sk_add_backlog(sk2, buff);
+			bh_unlock_sock(sk2);
+		}
 	}
-	udpv6_queue_rcv_skb(sk, skb);
+	bh_lock_sock_nested(sk);
+	if (!sock_owned_by_user(sk))
+		udpv6_queue_rcv_skb(sk, skb);
+	else
+		sk_add_backlog(sk, skb);
+	bh_unlock_sock(sk);
 out:
 	read_unlock(&udp_hash_lock);
 	return 0;
@@ -482,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb,
 
 	/* deliver */
 
-	udpv6_queue_rcv_skb(sk, skb);
+	bh_lock_sock_nested(sk);
+	if (!sock_owned_by_user(sk))
+		udpv6_queue_rcv_skb(sk, skb);
+	else
+		sk_add_backlog(sk, skb);
+	bh_unlock_sock(sk);
 	sock_put(sk);
 	return 0;
 
@@ -994,6 +1014,10 @@ struct proto udpv6_prot = {
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v6_get_port,
+	.memory_allocated  = &udp_memory_allocated,
+	.sysctl_mem	   = sysctl_udp_mem,
+	.sysctl_wmem	   = &sysctl_udp_wmem_min,
+	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp6_sock),
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udpv6_setsockopt,
Signature · 1 line
Hitachi Computer Products (America) Inc.