diff options
author | Neil Horman <nhorman@tuxdriver.com> | 2007-08-15 19:07:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:48:09 -0400 |
commit | 4d93df0abd50b9c9e2d4561439a1a1d21ec5e68f (patch) | |
tree | 47e5bde0c37ed7ce68032ffa9110f252533fc710 /net/sctp/socket.c | |
parent | 13c99b248f06e0b71d925f162d8e3b0084886a21 (diff) |
[SCTP]: Rewrite of sctp buffer management code
This patch introduces autotuning to the sctp buffer management code
similar to the TCP. The buffer space can be grown if the advertised
receive window still has room. This might happen if small message
sizes are used, which is common in telecom environmens.
New tunables are introduced that provide limits to buffer growth
and memory pressure is entered if to much buffer spaces is used.
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 69 |
1 files changed, 57 insertions, 12 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 772fbfb4bfda..b9952425c79a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -107,23 +107,42 @@ static void sctp_sock_migrate(struct sock *, struct sock *, | |||
107 | struct sctp_association *, sctp_socket_type_t); | 107 | struct sctp_association *, sctp_socket_type_t); |
108 | static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; | 108 | static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; |
109 | 109 | ||
110 | extern struct kmem_cache *sctp_bucket_cachep; | ||
111 | extern int sysctl_sctp_mem[3]; | ||
112 | extern int sysctl_sctp_rmem[3]; | ||
113 | extern int sysctl_sctp_wmem[3]; | ||
114 | |||
115 | int sctp_memory_pressure; | ||
116 | atomic_t sctp_memory_allocated; | ||
117 | atomic_t sctp_sockets_allocated; | ||
118 | |||
119 | static void sctp_enter_memory_pressure(void) | ||
120 | { | ||
121 | sctp_memory_pressure = 1; | ||
122 | } | ||
123 | |||
124 | |||
110 | /* Get the sndbuf space available at the time on the association. */ | 125 | /* Get the sndbuf space available at the time on the association. */ |
111 | static inline int sctp_wspace(struct sctp_association *asoc) | 126 | static inline int sctp_wspace(struct sctp_association *asoc) |
112 | { | 127 | { |
113 | struct sock *sk = asoc->base.sk; | 128 | int amt; |
114 | int amt = 0; | ||
115 | 129 | ||
116 | if (asoc->ep->sndbuf_policy) { | 130 | if (asoc->ep->sndbuf_policy) |
117 | /* make sure that no association uses more than sk_sndbuf */ | 131 | amt = asoc->sndbuf_used; |
118 | amt = sk->sk_sndbuf - asoc->sndbuf_used; | 132 | else |
133 | amt = atomic_read(&asoc->base.sk->sk_wmem_alloc); | ||
134 | |||
135 | if (amt >= asoc->base.sk->sk_sndbuf) { | ||
136 | if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) | ||
137 | amt = 0; | ||
138 | else { | ||
139 | amt = sk_stream_wspace(asoc->base.sk); | ||
140 | if (amt < 0) | ||
141 | amt = 0; | ||
142 | } | ||
119 | } else { | 143 | } else { |
120 | /* do socket level accounting */ | 144 | amt = asoc->base.sk->sk_sndbuf - amt; |
121 | amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); | ||
122 | } | 145 | } |
123 | |||
124 | if (amt < 0) | ||
125 | amt = 0; | ||
126 | |||
127 | return amt; | 146 | return amt; |
128 | } | 147 | } |
129 | 148 | ||
@@ -155,6 +174,7 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) | |||
155 | sizeof(struct sctp_chunk); | 174 | sizeof(struct sctp_chunk); |
156 | 175 | ||
157 | atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); | 176 | atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); |
177 | sk_charge_skb(sk, chunk->skb); | ||
158 | } | 178 | } |
159 | 179 | ||
160 | /* Verify that this is a valid address. */ | 180 | /* Verify that this is a valid address. */ |
@@ -3293,6 +3313,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3293 | sp->hmac = NULL; | 3313 | sp->hmac = NULL; |
3294 | 3314 | ||
3295 | SCTP_DBG_OBJCNT_INC(sock); | 3315 | SCTP_DBG_OBJCNT_INC(sock); |
3316 | atomic_inc(&sctp_sockets_allocated); | ||
3296 | return 0; | 3317 | return 0; |
3297 | } | 3318 | } |
3298 | 3319 | ||
@@ -3306,7 +3327,7 @@ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) | |||
3306 | /* Release our hold on the endpoint. */ | 3327 | /* Release our hold on the endpoint. */ |
3307 | ep = sctp_sk(sk)->ep; | 3328 | ep = sctp_sk(sk)->ep; |
3308 | sctp_endpoint_free(ep); | 3329 | sctp_endpoint_free(ep); |
3309 | 3330 | atomic_dec(&sctp_sockets_allocated); | |
3310 | return 0; | 3331 | return 0; |
3311 | } | 3332 | } |
3312 | 3333 | ||
@@ -5720,6 +5741,12 @@ static void sctp_wfree(struct sk_buff *skb) | |||
5720 | 5741 | ||
5721 | atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); | 5742 | atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); |
5722 | 5743 | ||
5744 | /* | ||
5745 | * This undoes what is done via sk_charge_skb | ||
5746 | */ | ||
5747 | sk->sk_wmem_queued -= skb->truesize; | ||
5748 | sk->sk_forward_alloc += skb->truesize; | ||
5749 | |||
5723 | sock_wfree(skb); | 5750 | sock_wfree(skb); |
5724 | __sctp_write_space(asoc); | 5751 | __sctp_write_space(asoc); |
5725 | 5752 | ||
@@ -5737,6 +5764,11 @@ void sctp_sock_rfree(struct sk_buff *skb) | |||
5737 | struct sctp_ulpevent *event = sctp_skb2event(skb); | 5764 | struct sctp_ulpevent *event = sctp_skb2event(skb); |
5738 | 5765 | ||
5739 | atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); | 5766 | atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); |
5767 | |||
5768 | /* | ||
5769 | * Mimic the behavior of sk_stream_rfree | ||
5770 | */ | ||
5771 | sk->sk_forward_alloc += event->rmem_len; | ||
5740 | } | 5772 | } |
5741 | 5773 | ||
5742 | 5774 | ||
@@ -6126,6 +6158,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
6126 | sctp_release_sock(newsk); | 6158 | sctp_release_sock(newsk); |
6127 | } | 6159 | } |
6128 | 6160 | ||
6161 | |||
6129 | /* This proto struct describes the ULP interface for SCTP. */ | 6162 | /* This proto struct describes the ULP interface for SCTP. */ |
6130 | struct proto sctp_prot = { | 6163 | struct proto sctp_prot = { |
6131 | .name = "SCTP", | 6164 | .name = "SCTP", |
@@ -6148,6 +6181,12 @@ struct proto sctp_prot = { | |||
6148 | .unhash = sctp_unhash, | 6181 | .unhash = sctp_unhash, |
6149 | .get_port = sctp_get_port, | 6182 | .get_port = sctp_get_port, |
6150 | .obj_size = sizeof(struct sctp_sock), | 6183 | .obj_size = sizeof(struct sctp_sock), |
6184 | .sysctl_mem = sysctl_sctp_mem, | ||
6185 | .sysctl_rmem = sysctl_sctp_rmem, | ||
6186 | .sysctl_wmem = sysctl_sctp_wmem, | ||
6187 | .memory_pressure = &sctp_memory_pressure, | ||
6188 | .enter_memory_pressure = sctp_enter_memory_pressure, | ||
6189 | .memory_allocated = &sctp_memory_allocated, | ||
6151 | }; | 6190 | }; |
6152 | 6191 | ||
6153 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 6192 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
@@ -6172,5 +6211,11 @@ struct proto sctpv6_prot = { | |||
6172 | .unhash = sctp_unhash, | 6211 | .unhash = sctp_unhash, |
6173 | .get_port = sctp_get_port, | 6212 | .get_port = sctp_get_port, |
6174 | .obj_size = sizeof(struct sctp6_sock), | 6213 | .obj_size = sizeof(struct sctp6_sock), |
6214 | .sysctl_mem = sysctl_sctp_mem, | ||
6215 | .sysctl_rmem = sysctl_sctp_rmem, | ||
6216 | .sysctl_wmem = sysctl_sctp_wmem, | ||
6217 | .memory_pressure = &sctp_memory_pressure, | ||
6218 | .enter_memory_pressure = sctp_enter_memory_pressure, | ||
6219 | .memory_allocated = &sctp_memory_allocated, | ||
6175 | }; | 6220 | }; |
6176 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 6221 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |