diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 57 |
1 files changed, 55 insertions, 2 deletions
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); | |||
118 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; | 119 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; |
119 | DEFINE_RWLOCK(udp_hash_lock); | 120 | DEFINE_RWLOCK(udp_hash_lock); |
120 | 121 | ||
122 | int sysctl_udp_mem[3] __read_mostly; | ||
123 | int sysctl_udp_rmem_min __read_mostly; | ||
124 | int sysctl_udp_wmem_min __read_mostly; | ||
125 | |||
126 | EXPORT_SYMBOL(sysctl_udp_mem); | ||
127 | EXPORT_SYMBOL(sysctl_udp_rmem_min); | ||
128 | EXPORT_SYMBOL(sysctl_udp_wmem_min); | ||
129 | |||
130 | atomic_t udp_memory_allocated; | ||
131 | EXPORT_SYMBOL(udp_memory_allocated); | ||
132 | |||
121 | static inline int __udp_lib_lport_inuse(__u16 num, | 133 | static 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 | ||
903 | out_free: | 915 | out_free: |
916 | lock_sock(sk); | ||
904 | skb_free_datagram(sk, skb); | 917 | skb_free_datagram(sk, skb); |
918 | release_sock(sk); | ||
905 | out: | 919 | out: |
906 | return err; | 920 | return err; |
907 | 921 | ||
908 | csum_copy_err: | 922 | csum_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 | ||
1692 | void __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 | |||
1658 | EXPORT_SYMBOL(udp_disconnect); | 1711 | EXPORT_SYMBOL(udp_disconnect); |
1659 | EXPORT_SYMBOL(udp_hash); | 1712 | EXPORT_SYMBOL(udp_hash); |
1660 | EXPORT_SYMBOL(udp_hash_lock); | 1713 | EXPORT_SYMBOL(udp_hash_lock); |