diff options
Diffstat (limited to 'net/ipv4/tcp_timer.c')
| -rw-r--r-- | net/ipv4/tcp_timer.c | 72 |
1 files changed, 39 insertions, 33 deletions
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e911e6c523ec..b774a03bd1dc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
| @@ -32,17 +32,6 @@ int sysctl_tcp_retries2 __read_mostly = TCP_RETR2; | |||
| 32 | int sysctl_tcp_orphan_retries __read_mostly; | 32 | int sysctl_tcp_orphan_retries __read_mostly; |
| 33 | int sysctl_tcp_thin_linear_timeouts __read_mostly; | 33 | int sysctl_tcp_thin_linear_timeouts __read_mostly; |
| 34 | 34 | ||
| 35 | static void tcp_write_timer(unsigned long); | ||
| 36 | static void tcp_delack_timer(unsigned long); | ||
| 37 | static void tcp_keepalive_timer (unsigned long data); | ||
| 38 | |||
| 39 | void tcp_init_xmit_timers(struct sock *sk) | ||
| 40 | { | ||
| 41 | inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, | ||
| 42 | &tcp_keepalive_timer); | ||
| 43 | } | ||
| 44 | EXPORT_SYMBOL(tcp_init_xmit_timers); | ||
| 45 | |||
| 46 | static void tcp_write_err(struct sock *sk) | 35 | static void tcp_write_err(struct sock *sk) |
| 47 | { | 36 | { |
| 48 | sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; | 37 | sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; |
| @@ -205,21 +194,11 @@ static int tcp_write_timeout(struct sock *sk) | |||
| 205 | return 0; | 194 | return 0; |
| 206 | } | 195 | } |
| 207 | 196 | ||
| 208 | static void tcp_delack_timer(unsigned long data) | 197 | void tcp_delack_timer_handler(struct sock *sk) |
| 209 | { | 198 | { |
| 210 | struct sock *sk = (struct sock *)data; | ||
| 211 | struct tcp_sock *tp = tcp_sk(sk); | 199 | struct tcp_sock *tp = tcp_sk(sk); |
| 212 | struct inet_connection_sock *icsk = inet_csk(sk); | 200 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 213 | 201 | ||
| 214 | bh_lock_sock(sk); | ||
| 215 | if (sock_owned_by_user(sk)) { | ||
| 216 | /* Try again later. */ | ||
| 217 | icsk->icsk_ack.blocked = 1; | ||
| 218 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); | ||
| 219 | sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN); | ||
| 220 | goto out_unlock; | ||
| 221 | } | ||
| 222 | |||
| 223 | sk_mem_reclaim_partial(sk); | 202 | sk_mem_reclaim_partial(sk); |
| 224 | 203 | ||
| 225 | if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) | 204 | if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) |
| @@ -260,7 +239,22 @@ static void tcp_delack_timer(unsigned long data) | |||
| 260 | out: | 239 | out: |
| 261 | if (sk_under_memory_pressure(sk)) | 240 | if (sk_under_memory_pressure(sk)) |
| 262 | sk_mem_reclaim(sk); | 241 | sk_mem_reclaim(sk); |
| 263 | out_unlock: | 242 | } |
| 243 | |||
| 244 | static void tcp_delack_timer(unsigned long data) | ||
| 245 | { | ||
| 246 | struct sock *sk = (struct sock *)data; | ||
| 247 | |||
| 248 | bh_lock_sock(sk); | ||
| 249 | if (!sock_owned_by_user(sk)) { | ||
| 250 | tcp_delack_timer_handler(sk); | ||
| 251 | } else { | ||
| 252 | inet_csk(sk)->icsk_ack.blocked = 1; | ||
| 253 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); | ||
| 254 | /* deleguate our work to tcp_release_cb() */ | ||
| 255 | if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) | ||
| 256 | sock_hold(sk); | ||
| 257 | } | ||
| 264 | bh_unlock_sock(sk); | 258 | bh_unlock_sock(sk); |
| 265 | sock_put(sk); | 259 | sock_put(sk); |
| 266 | } | 260 | } |
| @@ -450,19 +444,11 @@ out_reset_timer: | |||
| 450 | out:; | 444 | out:; |
| 451 | } | 445 | } |
| 452 | 446 | ||
| 453 | static void tcp_write_timer(unsigned long data) | 447 | void tcp_write_timer_handler(struct sock *sk) |
| 454 | { | 448 | { |
| 455 | struct sock *sk = (struct sock *)data; | ||
| 456 | struct inet_connection_sock *icsk = inet_csk(sk); | 449 | struct inet_connection_sock *icsk = inet_csk(sk); |
| 457 | int event; | 450 | int event; |
| 458 | 451 | ||
| 459 | bh_lock_sock(sk); | ||
| 460 | if (sock_owned_by_user(sk)) { | ||
| 461 | /* Try again later */ | ||
| 462 | sk_reset_timer(sk, &icsk->icsk_retransmit_timer, jiffies + (HZ / 20)); | ||
| 463 | goto out_unlock; | ||
| 464 | } | ||
| 465 | |||
| 466 | if (sk->sk_state == TCP_CLOSE || !icsk->icsk_pending) | 452 | if (sk->sk_state == TCP_CLOSE || !icsk->icsk_pending) |
| 467 | goto out; | 453 | goto out; |
| 468 | 454 | ||
| @@ -485,7 +471,20 @@ static void tcp_write_timer(unsigned long data) | |||
| 485 | 471 | ||
| 486 | out: | 472 | out: |
| 487 | sk_mem_reclaim(sk); | 473 | sk_mem_reclaim(sk); |
| 488 | out_unlock: | 474 | } |
| 475 | |||
| 476 | static void tcp_write_timer(unsigned long data) | ||
| 477 | { | ||
| 478 | struct sock *sk = (struct sock *)data; | ||
| 479 | |||
| 480 | bh_lock_sock(sk); | ||
| 481 | if (!sock_owned_by_user(sk)) { | ||
| 482 | tcp_write_timer_handler(sk); | ||
| 483 | } else { | ||
| 484 | /* deleguate our work to tcp_release_cb() */ | ||
| 485 | if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) | ||
| 486 | sock_hold(sk); | ||
| 487 | } | ||
| 489 | bh_unlock_sock(sk); | 488 | bh_unlock_sock(sk); |
| 490 | sock_put(sk); | 489 | sock_put(sk); |
| 491 | } | 490 | } |
| @@ -602,3 +601,10 @@ out: | |||
| 602 | bh_unlock_sock(sk); | 601 | bh_unlock_sock(sk); |
| 603 | sock_put(sk); | 602 | sock_put(sk); |
| 604 | } | 603 | } |
| 604 | |||
| 605 | void tcp_init_xmit_timers(struct sock *sk) | ||
| 606 | { | ||
| 607 | inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, | ||
| 608 | &tcp_keepalive_timer); | ||
| 609 | } | ||
| 610 | EXPORT_SYMBOL(tcp_init_xmit_timers); | ||
