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>
This commit is contained in:
Hideo Aoki 2007-12-31 00:29:24 -08:00 коммит произвёл David S. Miller
Родитель 3ab224be6d
Коммит 95766fff6b
7 изменённых файлов: 157 добавлений и 7 удалений

Просмотреть файл

@ -446,6 +446,33 @@ tcp_dma_copybreak - INTEGER
and CONFIG_NET_DMA is enabled. and CONFIG_NET_DMA is enabled.
Default: 4096 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: CIPSOv4 Variables:
cipso_cache_enable - BOOLEAN cipso_cache_enable - BOOLEAN

Просмотреть файл

@ -65,6 +65,13 @@ extern rwlock_t udp_hash_lock;
extern struct proto udp_prot; 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;
extern int sysctl_udp_wmem_min;
struct sk_buff; struct sk_buff;
/* /*
@ -198,4 +205,6 @@ extern void udp_proc_unregister(struct udp_seq_afinfo *afinfo);
extern int udp4_proc_init(void); extern int udp4_proc_init(void);
extern void udp4_proc_exit(void); extern void udp4_proc_exit(void);
#endif #endif
extern void udp_init(void);
#endif /* _UDP_H */ #endif /* _UDP_H */

Просмотреть файл

@ -139,6 +139,8 @@ void inet_sock_destruct(struct sock *sk)
__skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_error_queue); __skb_queue_purge(&sk->sk_error_queue);
sk_mem_reclaim(sk);
if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
printk("Attempt to release TCP socket in state %d %p\n", printk("Attempt to release TCP socket in state %d %p\n",
sk->sk_state, sk); sk->sk_state, sk);
@ -1417,6 +1419,9 @@ static int __init inet_init(void)
/* Setup TCP slab cache for open requests. */ /* Setup TCP slab cache for open requests. */
tcp_init(); tcp_init();
/* Setup UDP memory threshold */
udp_init();
/* Add UDP-Lite (RFC 3828) */ /* Add UDP-Lite (RFC 3828) */
udplite4_register(); udplite4_register();

Просмотреть файл

@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count), sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
atomic_read(&tcp_memory_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, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot)); seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
seq_printf(seq, "FRAG: inuse %d memory %d\n", seq_printf(seq, "FRAG: inuse %d memory %d\n",

Просмотреть файл

@ -19,6 +19,7 @@
#include <net/ip.h> #include <net/ip.h>
#include <net/route.h> #include <net/route.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h>
#include <net/cipso_ipv4.h> #include <net/cipso_ipv4.h>
#include <net/inet_frag.h> #include <net/inet_frag.h>
@ -812,6 +813,36 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec, .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 } { .ctl_name = 0 }
}; };

Просмотреть файл

@ -82,6 +82,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <linux/bootmem.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/module.h> #include <linux/module.h>
@ -118,6 +119,17 @@ EXPORT_SYMBOL(udp_stats_in6);
struct hlist_head udp_hash[UDP_HTABLE_SIZE]; struct hlist_head udp_hash[UDP_HTABLE_SIZE];
DEFINE_RWLOCK(udp_hash_lock); 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);
atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);
static inline int __udp_lib_lport_inuse(__u16 num, static inline int __udp_lib_lport_inuse(__u16 num,
const struct hlist_head udptable[]) const struct hlist_head udptable[])
{ {
@ -901,13 +913,17 @@ try_again:
err = ulen; err = ulen;
out_free: out_free:
lock_sock(sk);
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
release_sock(sk);
out: out:
return err; return err;
csum_copy_err: csum_copy_err:
lock_sock(sk);
if (!skb_kill_datagram(sk, skb, flags)) if (!skb_kill_datagram(sk, skb, flags))
UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
release_sock(sk);
if (noblock) if (noblock)
return -EAGAIN; return -EAGAIN;
@ -1072,7 +1088,15 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
skb1 = skb_clone(skb, GFP_ATOMIC); skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1) { 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) if (ret > 0)
/* we should probably re-process instead /* we should probably re-process instead
* of dropping packets here. */ * of dropping packets here. */
@ -1165,7 +1189,13 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
inet_iif(skb), udptable); inet_iif(skb), udptable);
if (sk != NULL) { 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); sock_put(sk);
/* a return value > 0 means to resubmit the input, but /* a return value > 0 means to resubmit the input, but
@ -1460,6 +1490,10 @@ struct proto udp_prot = {
.hash = udp_lib_hash, .hash = udp_lib_hash,
.unhash = udp_lib_unhash, .unhash = udp_lib_unhash,
.get_port = udp_v4_get_port, .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,
.obj_size = sizeof(struct udp_sock), .obj_size = sizeof(struct udp_sock),
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udp_setsockopt, .compat_setsockopt = compat_udp_setsockopt,
@ -1655,6 +1689,25 @@ void udp4_proc_exit(void)
} }
#endif /* CONFIG_PROC_FS */ #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_disconnect);
EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash);
EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_hash_lock);

Просмотреть файл

@ -204,13 +204,17 @@ try_again:
err = ulen; err = ulen;
out_free: out_free:
lock_sock(sk);
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
release_sock(sk);
out: out:
return err; return err;
csum_copy_err: csum_copy_err:
lock_sock(sk);
if (!skb_kill_datagram(sk, skb, flags)) if (!skb_kill_datagram(sk, skb, flags))
UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
release_sock(sk);
if (flags & MSG_DONTWAIT) if (flags & MSG_DONTWAIT)
return -EAGAIN; return -EAGAIN;
@ -366,10 +370,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr,
while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr,
uh->source, saddr, dif))) { uh->source, saddr, dif))) {
struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
if (buff) if (buff) {
udpv6_queue_rcv_skb(sk2, 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: out:
read_unlock(&udp_hash_lock); read_unlock(&udp_hash_lock);
return 0; return 0;
@ -482,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
/* deliver */ /* 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); sock_put(sk);
return 0; return 0;
@ -994,6 +1014,10 @@ struct proto udpv6_prot = {
.hash = udp_lib_hash, .hash = udp_lib_hash,
.unhash = udp_lib_unhash, .unhash = udp_lib_unhash,
.get_port = udp_v6_get_port, .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), .obj_size = sizeof(struct udp6_sock),
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udpv6_setsockopt, .compat_setsockopt = compat_udpv6_setsockopt,