diff options
Diffstat (limited to 'net/ipv4/tcp.c')
| -rw-r--r-- | net/ipv4/tcp.c | 74 |
1 files changed, 56 insertions, 18 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 64d0af675823..f1813bc71088 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -326,6 +326,43 @@ void tcp_enter_memory_pressure(struct sock *sk) | |||
| 326 | 326 | ||
| 327 | EXPORT_SYMBOL(tcp_enter_memory_pressure); | 327 | EXPORT_SYMBOL(tcp_enter_memory_pressure); |
| 328 | 328 | ||
| 329 | /* Convert seconds to retransmits based on initial and max timeout */ | ||
| 330 | static u8 secs_to_retrans(int seconds, int timeout, int rto_max) | ||
| 331 | { | ||
| 332 | u8 res = 0; | ||
| 333 | |||
| 334 | if (seconds > 0) { | ||
| 335 | int period = timeout; | ||
| 336 | |||
| 337 | res = 1; | ||
| 338 | while (seconds > period && res < 255) { | ||
| 339 | res++; | ||
| 340 | timeout <<= 1; | ||
| 341 | if (timeout > rto_max) | ||
| 342 | timeout = rto_max; | ||
| 343 | period += timeout; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | return res; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* Convert retransmits to seconds based on initial and max timeout */ | ||
| 350 | static int retrans_to_secs(u8 retrans, int timeout, int rto_max) | ||
| 351 | { | ||
| 352 | int period = 0; | ||
| 353 | |||
| 354 | if (retrans > 0) { | ||
| 355 | period = timeout; | ||
| 356 | while (--retrans) { | ||
| 357 | timeout <<= 1; | ||
| 358 | if (timeout > rto_max) | ||
| 359 | timeout = rto_max; | ||
| 360 | period += timeout; | ||
| 361 | } | ||
| 362 | } | ||
| 363 | return period; | ||
| 364 | } | ||
| 365 | |||
| 329 | /* | 366 | /* |
| 330 | * Wait for a TCP event. | 367 | * Wait for a TCP event. |
| 331 | * | 368 | * |
| @@ -1146,7 +1183,9 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied) | |||
| 1146 | #if TCP_DEBUG | 1183 | #if TCP_DEBUG |
| 1147 | struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); | 1184 | struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); |
| 1148 | 1185 | ||
| 1149 | WARN_ON(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); | 1186 | WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), |
| 1187 | KERN_INFO "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", | ||
| 1188 | tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); | ||
| 1150 | #endif | 1189 | #endif |
| 1151 | 1190 | ||
| 1152 | if (inet_csk_ack_scheduled(sk)) { | 1191 | if (inet_csk_ack_scheduled(sk)) { |
| @@ -1393,11 +1432,13 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1393 | /* Now that we have two receive queues this | 1432 | /* Now that we have two receive queues this |
| 1394 | * shouldn't happen. | 1433 | * shouldn't happen. |
| 1395 | */ | 1434 | */ |
| 1396 | if (before(*seq, TCP_SKB_CB(skb)->seq)) { | 1435 | if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), |
| 1397 | printk(KERN_INFO "recvmsg bug: copied %X " | 1436 | KERN_INFO "recvmsg bug: copied %X " |
| 1398 | "seq %X\n", *seq, TCP_SKB_CB(skb)->seq); | 1437 | "seq %X rcvnxt %X fl %X\n", *seq, |
| 1438 | TCP_SKB_CB(skb)->seq, tp->rcv_nxt, | ||
| 1439 | flags)) | ||
| 1399 | break; | 1440 | break; |
| 1400 | } | 1441 | |
| 1401 | offset = *seq - TCP_SKB_CB(skb)->seq; | 1442 | offset = *seq - TCP_SKB_CB(skb)->seq; |
| 1402 | if (tcp_hdr(skb)->syn) | 1443 | if (tcp_hdr(skb)->syn) |
| 1403 | offset--; | 1444 | offset--; |
| @@ -1405,7 +1446,10 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1405 | goto found_ok_skb; | 1446 | goto found_ok_skb; |
| 1406 | if (tcp_hdr(skb)->fin) | 1447 | if (tcp_hdr(skb)->fin) |
| 1407 | goto found_fin_ok; | 1448 | goto found_fin_ok; |
| 1408 | WARN_ON(!(flags & MSG_PEEK)); | 1449 | WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: " |
| 1450 | "copied %X seq %X rcvnxt %X fl %X\n", | ||
| 1451 | *seq, TCP_SKB_CB(skb)->seq, | ||
| 1452 | tp->rcv_nxt, flags); | ||
| 1409 | } | 1453 | } |
| 1410 | 1454 | ||
| 1411 | /* Well, if we have backlog, try to process it now yet. */ | 1455 | /* Well, if we have backlog, try to process it now yet. */ |
| @@ -2163,16 +2207,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
| 2163 | break; | 2207 | break; |
| 2164 | 2208 | ||
| 2165 | case TCP_DEFER_ACCEPT: | 2209 | case TCP_DEFER_ACCEPT: |
| 2166 | icsk->icsk_accept_queue.rskq_defer_accept = 0; | 2210 | /* Translate value in seconds to number of retransmits */ |
| 2167 | if (val > 0) { | 2211 | icsk->icsk_accept_queue.rskq_defer_accept = |
| 2168 | /* Translate value in seconds to number of | 2212 | secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, |
| 2169 | * retransmits */ | 2213 | TCP_RTO_MAX / HZ); |
| 2170 | while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && | ||
| 2171 | val > ((TCP_TIMEOUT_INIT / HZ) << | ||
| 2172 | icsk->icsk_accept_queue.rskq_defer_accept)) | ||
| 2173 | icsk->icsk_accept_queue.rskq_defer_accept++; | ||
| 2174 | icsk->icsk_accept_queue.rskq_defer_accept++; | ||
| 2175 | } | ||
| 2176 | break; | 2214 | break; |
| 2177 | 2215 | ||
| 2178 | case TCP_WINDOW_CLAMP: | 2216 | case TCP_WINDOW_CLAMP: |
| @@ -2353,8 +2391,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level, | |||
| 2353 | val = (val ? : sysctl_tcp_fin_timeout) / HZ; | 2391 | val = (val ? : sysctl_tcp_fin_timeout) / HZ; |
| 2354 | break; | 2392 | break; |
| 2355 | case TCP_DEFER_ACCEPT: | 2393 | case TCP_DEFER_ACCEPT: |
| 2356 | val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : | 2394 | val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept, |
| 2357 | ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); | 2395 | TCP_TIMEOUT_INIT / HZ, TCP_RTO_MAX / HZ); |
| 2358 | break; | 2396 | break; |
| 2359 | case TCP_WINDOW_CLAMP: | 2397 | case TCP_WINDOW_CLAMP: |
| 2360 | val = tp->window_clamp; | 2398 | val = tp->window_clamp; |
