aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHideo Aoki <haoki@redhat.com>2007-12-31 03:29:24 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:00:19 -0500
commit95766fff6b9a78d11fc2d3812dd035381690b55d (patch)
treec1ec9386a3d9a76a9f74bd230d3e7d4ee8059c51 /net
parent3ab224be6d69de912ee21302745ea45a99274dbc (diff)
[UDP]: Add memory accounting.
Signed-off-by: Takahiro Yasui <tyasui@redhat.com> Signed-off-by: Hideo Aoki <haoki@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/af_inet.c5
-rw-r--r--net/ipv4/proc.c3
-rw-r--r--net/ipv4/sysctl_net_ipv4.c31
-rw-r--r--net/ipv4/udp.c57
-rw-r--r--net/ipv6/udp.c32
5 files changed, 121 insertions, 7 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 03633b7b9b4a..0e12cf646071 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -139,6 +139,8 @@ void inet_sock_destruct(struct sock *sk)
139 __skb_queue_purge(&sk->sk_receive_queue); 139 __skb_queue_purge(&sk->sk_receive_queue);
140 __skb_queue_purge(&sk->sk_error_queue); 140 __skb_queue_purge(&sk->sk_error_queue);
141 141
142 sk_mem_reclaim(sk);
143
142 if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { 144 if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
143 printk("Attempt to release TCP socket in state %d %p\n", 145 printk("Attempt to release TCP socket in state %d %p\n",
144 sk->sk_state, sk); 146 sk->sk_state, sk);
@@ -1417,6 +1419,9 @@ static int __init inet_init(void)
1417 /* Setup TCP slab cache for open requests. */ 1419 /* Setup TCP slab cache for open requests. */
1418 tcp_init(); 1420 tcp_init();
1419 1421
1422 /* Setup UDP memory threshold */
1423 udp_init();
1424
1420 /* Add UDP-Lite (RFC 3828) */ 1425 /* Add UDP-Lite (RFC 3828) */
1421 udplite4_register(); 1426 udplite4_register();
1422 1427
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 41734db677be..53bc010beefd 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
56 sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count), 56 sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
57 tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), 57 tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
58 atomic_read(&tcp_memory_allocated)); 58 atomic_read(&tcp_memory_allocated));
59 seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot)); 59 seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
60 atomic_read(&udp_memory_allocated));
60 seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot)); 61 seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
61 seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot)); 62 seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
62 seq_printf(seq, "FRAG: inuse %d memory %d\n", 63 seq_printf(seq, "FRAG: inuse %d memory %d\n",
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 844f26fab06f..a5a9f8e3bb25 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -19,6 +19,7 @@
19#include <net/ip.h> 19#include <net/ip.h>
20#include <net/route.h> 20#include <net/route.h>
21#include <net/tcp.h> 21#include <net/tcp.h>
22#include <net/udp.h>
22#include <net/cipso_ipv4.h> 23#include <net/cipso_ipv4.h>
23#include <net/inet_frag.h> 24#include <net/inet_frag.h>
24 25
@@ -812,6 +813,36 @@ static struct ctl_table ipv4_table[] = {
812 .mode = 0644, 813 .mode = 0644,
813 .proc_handler = &proc_dointvec, 814 .proc_handler = &proc_dointvec,
814 }, 815 },
816 {
817 .ctl_name = CTL_UNNUMBERED,
818 .procname = "udp_mem",
819 .data = &sysctl_udp_mem,
820 .maxlen = sizeof(sysctl_udp_mem),
821 .mode = 0644,
822 .proc_handler = &proc_dointvec_minmax,
823 .strategy = &sysctl_intvec,
824 .extra1 = &zero
825 },
826 {
827 .ctl_name = CTL_UNNUMBERED,
828 .procname = "udp_rmem_min",
829 .data = &sysctl_udp_rmem_min,
830 .maxlen = sizeof(sysctl_udp_rmem_min),
831 .mode = 0644,
832 .proc_handler = &proc_dointvec_minmax,
833 .strategy = &sysctl_intvec,
834 .extra1 = &zero
835 },
836 {
837 .ctl_name = CTL_UNNUMBERED,
838 .procname = "udp_wmem_min",
839 .data = &sysctl_udp_wmem_min,
840 .maxlen = sizeof(sysctl_udp_wmem_min),
841 .mode = 0644,
842 .proc_handler = &proc_dointvec_minmax,
843 .strategy = &sysctl_intvec,
844 .extra1 = &zero
845 },
815 { .ctl_name = 0 } 846 { .ctl_name = 0 }
816}; 847};
817 848
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1ce6b60b7f93..353284360751 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -82,6 +82,7 @@
82#include <asm/system.h> 82#include <asm/system.h>
83#include <asm/uaccess.h> 83#include <asm/uaccess.h>
84#include <asm/ioctls.h> 84#include <asm/ioctls.h>
85#include <linux/bootmem.h>
85#include <linux/types.h> 86#include <linux/types.h>
86#include <linux/fcntl.h> 87#include <linux/fcntl.h>
87#include <linux/module.h> 88#include <linux/module.h>
@@ -118,6 +119,17 @@ EXPORT_SYMBOL(udp_stats_in6);
118struct hlist_head udp_hash[UDP_HTABLE_SIZE]; 119struct hlist_head udp_hash[UDP_HTABLE_SIZE];
119DEFINE_RWLOCK(udp_hash_lock); 120DEFINE_RWLOCK(udp_hash_lock);
120 121
122int sysctl_udp_mem[3] __read_mostly;
123int sysctl_udp_rmem_min __read_mostly;
124int sysctl_udp_wmem_min __read_mostly;
125
126EXPORT_SYMBOL(sysctl_udp_mem);
127EXPORT_SYMBOL(sysctl_udp_rmem_min);
128EXPORT_SYMBOL(sysctl_udp_wmem_min);
129
130atomic_t udp_memory_allocated;
131EXPORT_SYMBOL(udp_memory_allocated);
132
121static inline int __udp_lib_lport_inuse(__u16 num, 133static inline int __udp_lib_lport_inuse(__u16 num,
122 const struct hlist_head udptable[]) 134 const struct hlist_head udptable[])
123{ 135{
@@ -901,13 +913,17 @@ try_again:
901 err = ulen; 913 err = ulen;
902 914
903out_free: 915out_free:
916 lock_sock(sk);
904 skb_free_datagram(sk, skb); 917 skb_free_datagram(sk, skb);
918 release_sock(sk);
905out: 919out:
906 return err; 920 return err;
907 921
908csum_copy_err: 922csum_copy_err:
923 lock_sock(sk);
909 if (!skb_kill_datagram(sk, skb, flags)) 924 if (!skb_kill_datagram(sk, skb, flags))
910 UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); 925 UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
926 release_sock(sk);
911 927
912 if (noblock) 928 if (noblock)
913 return -EAGAIN; 929 return -EAGAIN;
@@ -1072,7 +1088,15 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
1072 skb1 = skb_clone(skb, GFP_ATOMIC); 1088 skb1 = skb_clone(skb, GFP_ATOMIC);
1073 1089
1074 if (skb1) { 1090 if (skb1) {
1075 int ret = udp_queue_rcv_skb(sk, skb1); 1091 int ret = 0;
1092
1093 bh_lock_sock_nested(sk);
1094 if (!sock_owned_by_user(sk))
1095 ret = udp_queue_rcv_skb(sk, skb1);
1096 else
1097 sk_add_backlog(sk, skb1);
1098 bh_unlock_sock(sk);
1099
1076 if (ret > 0) 1100 if (ret > 0)
1077 /* we should probably re-process instead 1101 /* we should probably re-process instead
1078 * of dropping packets here. */ 1102 * of dropping packets here. */
@@ -1165,7 +1189,13 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1165 inet_iif(skb), udptable); 1189 inet_iif(skb), udptable);
1166 1190
1167 if (sk != NULL) { 1191 if (sk != NULL) {
1168 int ret = udp_queue_rcv_skb(sk, skb); 1192 int ret = 0;
1193 bh_lock_sock_nested(sk);
1194 if (!sock_owned_by_user(sk))
1195 ret = udp_queue_rcv_skb(sk, skb);
1196 else
1197 sk_add_backlog(sk, skb);
1198 bh_unlock_sock(sk);
1169 sock_put(sk); 1199 sock_put(sk);
1170 1200
1171 /* a return value > 0 means to resubmit the input, but 1201 /* a return value > 0 means to resubmit the input, but
@@ -1460,6 +1490,10 @@ struct proto udp_prot = {
1460 .hash = udp_lib_hash, 1490 .hash = udp_lib_hash,
1461 .unhash = udp_lib_unhash, 1491 .unhash = udp_lib_unhash,
1462 .get_port = udp_v4_get_port, 1492 .get_port = udp_v4_get_port,
1493 .memory_allocated = &udp_memory_allocated,
1494 .sysctl_mem = sysctl_udp_mem,
1495 .sysctl_wmem = &sysctl_udp_wmem_min,
1496 .sysctl_rmem = &sysctl_udp_rmem_min,
1463 .obj_size = sizeof(struct udp_sock), 1497 .obj_size = sizeof(struct udp_sock),
1464#ifdef CONFIG_COMPAT 1498#ifdef CONFIG_COMPAT
1465 .compat_setsockopt = compat_udp_setsockopt, 1499 .compat_setsockopt = compat_udp_setsockopt,
@@ -1655,6 +1689,25 @@ void udp4_proc_exit(void)
1655} 1689}
1656#endif /* CONFIG_PROC_FS */ 1690#endif /* CONFIG_PROC_FS */
1657 1691
1692void __init udp_init(void)
1693{
1694 unsigned long limit;
1695
1696 /* Set the pressure threshold up by the same strategy of TCP. It is a
1697 * fraction of global memory that is up to 1/2 at 256 MB, decreasing
1698 * toward zero with the amount of memory, with a floor of 128 pages.
1699 */
1700 limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
1701 limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
1702 limit = max(limit, 128UL);
1703 sysctl_udp_mem[0] = limit / 4 * 3;
1704 sysctl_udp_mem[1] = limit;
1705 sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2;
1706
1707 sysctl_udp_rmem_min = SK_MEM_QUANTUM;
1708 sysctl_udp_wmem_min = SK_MEM_QUANTUM;
1709}
1710
1658EXPORT_SYMBOL(udp_disconnect); 1711EXPORT_SYMBOL(udp_disconnect);
1659EXPORT_SYMBOL(udp_hash); 1712EXPORT_SYMBOL(udp_hash);
1660EXPORT_SYMBOL(udp_hash_lock); 1713EXPORT_SYMBOL(udp_hash_lock);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c9a97b405511..bf58acab2064 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -204,13 +204,17 @@ try_again:
204 err = ulen; 204 err = ulen;
205 205
206out_free: 206out_free:
207 lock_sock(sk);
207 skb_free_datagram(sk, skb); 208 skb_free_datagram(sk, skb);
209 release_sock(sk);
208out: 210out:
209 return err; 211 return err;
210 212
211csum_copy_err: 213csum_copy_err:
214 lock_sock(sk);
212 if (!skb_kill_datagram(sk, skb, flags)) 215 if (!skb_kill_datagram(sk, skb, flags))
213 UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); 216 UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
217 release_sock(sk);
214 218
215 if (flags & MSG_DONTWAIT) 219 if (flags & MSG_DONTWAIT)
216 return -EAGAIN; 220 return -EAGAIN;
@@ -366,10 +370,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr,
366 while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, 370 while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr,
367 uh->source, saddr, dif))) { 371 uh->source, saddr, dif))) {
368 struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); 372 struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
369 if (buff) 373 if (buff) {
370 udpv6_queue_rcv_skb(sk2, buff); 374 bh_lock_sock_nested(sk2);
375 if (!sock_owned_by_user(sk2))
376 udpv6_queue_rcv_skb(sk2, buff);
377 else
378 sk_add_backlog(sk2, buff);
379 bh_unlock_sock(sk2);
380 }
371 } 381 }
372 udpv6_queue_rcv_skb(sk, skb); 382 bh_lock_sock_nested(sk);
383 if (!sock_owned_by_user(sk))
384 udpv6_queue_rcv_skb(sk, skb);
385 else
386 sk_add_backlog(sk, skb);
387 bh_unlock_sock(sk);
373out: 388out:
374 read_unlock(&udp_hash_lock); 389 read_unlock(&udp_hash_lock);
375 return 0; 390 return 0;
@@ -482,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
482 497
483 /* deliver */ 498 /* deliver */
484 499
485 udpv6_queue_rcv_skb(sk, skb); 500 bh_lock_sock_nested(sk);
501 if (!sock_owned_by_user(sk))
502 udpv6_queue_rcv_skb(sk, skb);
503 else
504 sk_add_backlog(sk, skb);
505 bh_unlock_sock(sk);
486 sock_put(sk); 506 sock_put(sk);
487 return 0; 507 return 0;
488 508
@@ -994,6 +1014,10 @@ struct proto udpv6_prot = {
994 .hash = udp_lib_hash, 1014 .hash = udp_lib_hash,
995 .unhash = udp_lib_unhash, 1015 .unhash = udp_lib_unhash,
996 .get_port = udp_v6_get_port, 1016 .get_port = udp_v6_get_port,
1017 .memory_allocated = &udp_memory_allocated,
1018 .sysctl_mem = sysctl_udp_mem,
1019 .sysctl_wmem = &sysctl_udp_wmem_min,
1020 .sysctl_rmem = &sysctl_udp_rmem_min,
997 .obj_size = sizeof(struct udp6_sock), 1021 .obj_size = sizeof(struct udp6_sock),
998#ifdef CONFIG_COMPAT 1022#ifdef CONFIG_COMPAT
999 .compat_setsockopt = compat_udpv6_setsockopt, 1023 .compat_setsockopt = compat_udpv6_setsockopt,