diff options
-rw-r--r-- | include/linux/tcp.h | 6 | ||||
-rw-r--r-- | net/core/request_sock.c | 2 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 11 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 13 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_timer.c | 11 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
11 files changed, 35 insertions, 24 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 99617e528ea2..668e25a76d69 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h | |||
@@ -393,7 +393,7 @@ struct tcp_sock { | |||
393 | /* fastopen_rsk points to request_sock that resulted in this big | 393 | /* fastopen_rsk points to request_sock that resulted in this big |
394 | * socket. Used to retransmit SYNACKs etc. | 394 | * socket. Used to retransmit SYNACKs etc. |
395 | */ | 395 | */ |
396 | struct request_sock *fastopen_rsk; | 396 | struct request_sock __rcu *fastopen_rsk; |
397 | u32 *saved_syn; | 397 | u32 *saved_syn; |
398 | }; | 398 | }; |
399 | 399 | ||
@@ -447,8 +447,8 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) | |||
447 | 447 | ||
448 | static inline bool tcp_passive_fastopen(const struct sock *sk) | 448 | static inline bool tcp_passive_fastopen(const struct sock *sk) |
449 | { | 449 | { |
450 | return (sk->sk_state == TCP_SYN_RECV && | 450 | return sk->sk_state == TCP_SYN_RECV && |
451 | tcp_sk(sk)->fastopen_rsk != NULL); | 451 | rcu_access_pointer(tcp_sk(sk)->fastopen_rsk) != NULL; |
452 | } | 452 | } |
453 | 453 | ||
454 | static inline void fastopen_queue_tune(struct sock *sk, int backlog) | 454 | static inline void fastopen_queue_tune(struct sock *sk, int backlog) |
diff --git a/net/core/request_sock.c b/net/core/request_sock.c index c9bb00008528..f35c2e998406 100644 --- a/net/core/request_sock.c +++ b/net/core/request_sock.c | |||
@@ -96,7 +96,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, | |||
96 | 96 | ||
97 | fastopenq = &inet_csk(lsk)->icsk_accept_queue.fastopenq; | 97 | fastopenq = &inet_csk(lsk)->icsk_accept_queue.fastopenq; |
98 | 98 | ||
99 | tcp_sk(sk)->fastopen_rsk = NULL; | 99 | RCU_INIT_POINTER(tcp_sk(sk)->fastopen_rsk, NULL); |
100 | spin_lock_bh(&fastopenq->lock); | 100 | spin_lock_bh(&fastopenq->lock); |
101 | fastopenq->qlen--; | 101 | fastopenq->qlen--; |
102 | tcp_rsk(req)->tfo_listener = false; | 102 | tcp_rsk(req)->tfo_listener = false; |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index dbcf34ec8dd2..eb30fc1770de 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -906,7 +906,7 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, | |||
906 | percpu_counter_inc(sk->sk_prot->orphan_count); | 906 | percpu_counter_inc(sk->sk_prot->orphan_count); |
907 | 907 | ||
908 | if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) { | 908 | if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) { |
909 | BUG_ON(tcp_sk(child)->fastopen_rsk != req); | 909 | BUG_ON(rcu_access_pointer(tcp_sk(child)->fastopen_rsk) != req); |
910 | BUG_ON(sk != req->rsk_listener); | 910 | BUG_ON(sk != req->rsk_listener); |
911 | 911 | ||
912 | /* Paranoid, to prevent race condition if | 912 | /* Paranoid, to prevent race condition if |
@@ -915,7 +915,7 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, | |||
915 | * Also to satisfy an assertion in | 915 | * Also to satisfy an assertion in |
916 | * tcp_v4_destroy_sock(). | 916 | * tcp_v4_destroy_sock(). |
917 | */ | 917 | */ |
918 | tcp_sk(child)->fastopen_rsk = NULL; | 918 | RCU_INIT_POINTER(tcp_sk(child)->fastopen_rsk, NULL); |
919 | } | 919 | } |
920 | inet_csk_destroy_sock(child); | 920 | inet_csk_destroy_sock(child); |
921 | } | 921 | } |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8781a92ea4b6..c59d0bd29c5c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -543,7 +543,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
543 | 543 | ||
544 | /* Connected or passive Fast Open socket? */ | 544 | /* Connected or passive Fast Open socket? */ |
545 | if (state != TCP_SYN_SENT && | 545 | if (state != TCP_SYN_SENT && |
546 | (state != TCP_SYN_RECV || tp->fastopen_rsk)) { | 546 | (state != TCP_SYN_RECV || rcu_access_pointer(tp->fastopen_rsk))) { |
547 | int target = sock_rcvlowat(sk, 0, INT_MAX); | 547 | int target = sock_rcvlowat(sk, 0, INT_MAX); |
548 | 548 | ||
549 | if (tp->urg_seq == tp->copied_seq && | 549 | if (tp->urg_seq == tp->copied_seq && |
@@ -2487,7 +2487,10 @@ adjudge_to_death: | |||
2487 | } | 2487 | } |
2488 | 2488 | ||
2489 | if (sk->sk_state == TCP_CLOSE) { | 2489 | if (sk->sk_state == TCP_CLOSE) { |
2490 | struct request_sock *req = tcp_sk(sk)->fastopen_rsk; | 2490 | struct request_sock *req; |
2491 | |||
2492 | req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk, | ||
2493 | lockdep_sock_is_held(sk)); | ||
2491 | /* We could get here with a non-NULL req if the socket is | 2494 | /* We could get here with a non-NULL req if the socket is |
2492 | * aborted (e.g., closed with unread data) before 3WHS | 2495 | * aborted (e.g., closed with unread data) before 3WHS |
2493 | * finishes. | 2496 | * finishes. |
@@ -3831,8 +3834,10 @@ EXPORT_SYMBOL(tcp_md5_hash_key); | |||
3831 | 3834 | ||
3832 | void tcp_done(struct sock *sk) | 3835 | void tcp_done(struct sock *sk) |
3833 | { | 3836 | { |
3834 | struct request_sock *req = tcp_sk(sk)->fastopen_rsk; | 3837 | struct request_sock *req; |
3835 | 3838 | ||
3839 | req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk, | ||
3840 | lockdep_sock_is_held(sk)); | ||
3836 | if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) | 3841 | if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) |
3837 | TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); | 3842 | TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); |
3838 | 3843 | ||
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 3fd451271a70..a915ade0c818 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -253,7 +253,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, | |||
253 | */ | 253 | */ |
254 | tp = tcp_sk(child); | 254 | tp = tcp_sk(child); |
255 | 255 | ||
256 | tp->fastopen_rsk = req; | 256 | rcu_assign_pointer(tp->fastopen_rsk, req); |
257 | tcp_rsk(req)->tfo_listener = true; | 257 | tcp_rsk(req)->tfo_listener = true; |
258 | 258 | ||
259 | /* RFC1323: The window in SYN & SYN/ACK segments is never | 259 | /* RFC1323: The window in SYN & SYN/ACK segments is never |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3578357abe30..5f9b102c3b55 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2666,7 +2666,7 @@ static void tcp_process_loss(struct sock *sk, int flag, int num_dupack, | |||
2666 | struct tcp_sock *tp = tcp_sk(sk); | 2666 | struct tcp_sock *tp = tcp_sk(sk); |
2667 | bool recovered = !before(tp->snd_una, tp->high_seq); | 2667 | bool recovered = !before(tp->snd_una, tp->high_seq); |
2668 | 2668 | ||
2669 | if ((flag & FLAG_SND_UNA_ADVANCED || tp->fastopen_rsk) && | 2669 | if ((flag & FLAG_SND_UNA_ADVANCED || rcu_access_pointer(tp->fastopen_rsk)) && |
2670 | tcp_try_undo_loss(sk, false)) | 2670 | tcp_try_undo_loss(sk, false)) |
2671 | return; | 2671 | return; |
2672 | 2672 | ||
@@ -2990,7 +2990,7 @@ void tcp_rearm_rto(struct sock *sk) | |||
2990 | /* If the retrans timer is currently being used by Fast Open | 2990 | /* If the retrans timer is currently being used by Fast Open |
2991 | * for SYN-ACK retrans purpose, stay put. | 2991 | * for SYN-ACK retrans purpose, stay put. |
2992 | */ | 2992 | */ |
2993 | if (tp->fastopen_rsk) | 2993 | if (rcu_access_pointer(tp->fastopen_rsk)) |
2994 | return; | 2994 | return; |
2995 | 2995 | ||
2996 | if (!tp->packets_out) { | 2996 | if (!tp->packets_out) { |
@@ -6087,6 +6087,8 @@ reset_and_undo: | |||
6087 | 6087 | ||
6088 | static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) | 6088 | static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) |
6089 | { | 6089 | { |
6090 | struct request_sock *req; | ||
6091 | |||
6090 | tcp_try_undo_loss(sk, false); | 6092 | tcp_try_undo_loss(sk, false); |
6091 | 6093 | ||
6092 | /* Reset rtx states to prevent spurious retransmits_timed_out() */ | 6094 | /* Reset rtx states to prevent spurious retransmits_timed_out() */ |
@@ -6096,7 +6098,9 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) | |||
6096 | /* Once we leave TCP_SYN_RECV or TCP_FIN_WAIT_1, | 6098 | /* Once we leave TCP_SYN_RECV or TCP_FIN_WAIT_1, |
6097 | * we no longer need req so release it. | 6099 | * we no longer need req so release it. |
6098 | */ | 6100 | */ |
6099 | reqsk_fastopen_remove(sk, tcp_sk(sk)->fastopen_rsk, false); | 6101 | req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk, |
6102 | lockdep_sock_is_held(sk)); | ||
6103 | reqsk_fastopen_remove(sk, req, false); | ||
6100 | 6104 | ||
6101 | /* Re-arm the timer because data may have been sent out. | 6105 | /* Re-arm the timer because data may have been sent out. |
6102 | * This is similar to the regular data transmission case | 6106 | * This is similar to the regular data transmission case |
@@ -6171,7 +6175,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) | |||
6171 | 6175 | ||
6172 | tcp_mstamp_refresh(tp); | 6176 | tcp_mstamp_refresh(tp); |
6173 | tp->rx_opt.saw_tstamp = 0; | 6177 | tp->rx_opt.saw_tstamp = 0; |
6174 | req = tp->fastopen_rsk; | 6178 | req = rcu_dereference_protected(tp->fastopen_rsk, |
6179 | lockdep_sock_is_held(sk)); | ||
6175 | if (req) { | 6180 | if (req) { |
6176 | bool req_stolen; | 6181 | bool req_stolen; |
6177 | 6182 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 492bf6a6b023..ffa366099eb2 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -478,7 +478,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
478 | icsk = inet_csk(sk); | 478 | icsk = inet_csk(sk); |
479 | tp = tcp_sk(sk); | 479 | tp = tcp_sk(sk); |
480 | /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ | 480 | /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ |
481 | fastopen = tp->fastopen_rsk; | 481 | fastopen = rcu_dereference(tp->fastopen_rsk); |
482 | snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; | 482 | snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; |
483 | if (sk->sk_state != TCP_LISTEN && | 483 | if (sk->sk_state != TCP_LISTEN && |
484 | !between(seq, snd_una, tp->snd_nxt)) { | 484 | !between(seq, snd_una, tp->snd_nxt)) { |
@@ -2121,7 +2121,7 @@ void tcp_v4_destroy_sock(struct sock *sk) | |||
2121 | if (inet_csk(sk)->icsk_bind_hash) | 2121 | if (inet_csk(sk)->icsk_bind_hash) |
2122 | inet_put_port(sk); | 2122 | inet_put_port(sk); |
2123 | 2123 | ||
2124 | BUG_ON(tp->fastopen_rsk); | 2124 | BUG_ON(rcu_access_pointer(tp->fastopen_rsk)); |
2125 | 2125 | ||
2126 | /* If socket is aborted during connect operation */ | 2126 | /* If socket is aborted during connect operation */ |
2127 | tcp_free_fastopen_req(tp); | 2127 | tcp_free_fastopen_req(tp); |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index bb140a5db8c0..5401dbd39c8f 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -541,7 +541,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, | |||
541 | newtp->rx_opt.mss_clamp = req->mss; | 541 | newtp->rx_opt.mss_clamp = req->mss; |
542 | tcp_ecn_openreq_child(newtp, req); | 542 | tcp_ecn_openreq_child(newtp, req); |
543 | newtp->fastopen_req = NULL; | 543 | newtp->fastopen_req = NULL; |
544 | newtp->fastopen_rsk = NULL; | 544 | RCU_INIT_POINTER(newtp->fastopen_rsk, NULL); |
545 | 545 | ||
546 | __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); | 546 | __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); |
547 | 547 | ||
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fec6d67bfd14..84ae4d1449ea 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -2482,7 +2482,7 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto) | |||
2482 | /* Don't do any loss probe on a Fast Open connection before 3WHS | 2482 | /* Don't do any loss probe on a Fast Open connection before 3WHS |
2483 | * finishes. | 2483 | * finishes. |
2484 | */ | 2484 | */ |
2485 | if (tp->fastopen_rsk) | 2485 | if (rcu_access_pointer(tp->fastopen_rsk)) |
2486 | return false; | 2486 | return false; |
2487 | 2487 | ||
2488 | early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans; | 2488 | early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans; |
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 05be564414e9..dd5a6317a801 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -386,15 +386,13 @@ abort: tcp_write_err(sk); | |||
386 | * Timer for Fast Open socket to retransmit SYNACK. Note that the | 386 | * Timer for Fast Open socket to retransmit SYNACK. Note that the |
387 | * sk here is the child socket, not the parent (listener) socket. | 387 | * sk here is the child socket, not the parent (listener) socket. |
388 | */ | 388 | */ |
389 | static void tcp_fastopen_synack_timer(struct sock *sk) | 389 | static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req) |
390 | { | 390 | { |
391 | struct inet_connection_sock *icsk = inet_csk(sk); | 391 | struct inet_connection_sock *icsk = inet_csk(sk); |
392 | int max_retries = icsk->icsk_syn_retries ? : | 392 | int max_retries = icsk->icsk_syn_retries ? : |
393 | sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */ | 393 | sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */ |
394 | struct tcp_sock *tp = tcp_sk(sk); | 394 | struct tcp_sock *tp = tcp_sk(sk); |
395 | struct request_sock *req; | ||
396 | 395 | ||
397 | req = tcp_sk(sk)->fastopen_rsk; | ||
398 | req->rsk_ops->syn_ack_timeout(req); | 396 | req->rsk_ops->syn_ack_timeout(req); |
399 | 397 | ||
400 | if (req->num_timeout >= max_retries) { | 398 | if (req->num_timeout >= max_retries) { |
@@ -435,11 +433,14 @@ void tcp_retransmit_timer(struct sock *sk) | |||
435 | struct tcp_sock *tp = tcp_sk(sk); | 433 | struct tcp_sock *tp = tcp_sk(sk); |
436 | struct net *net = sock_net(sk); | 434 | struct net *net = sock_net(sk); |
437 | struct inet_connection_sock *icsk = inet_csk(sk); | 435 | struct inet_connection_sock *icsk = inet_csk(sk); |
436 | struct request_sock *req; | ||
438 | 437 | ||
439 | if (tp->fastopen_rsk) { | 438 | req = rcu_dereference_protected(tp->fastopen_rsk, |
439 | lockdep_sock_is_held(sk)); | ||
440 | if (req) { | ||
440 | WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && | 441 | WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && |
441 | sk->sk_state != TCP_FIN_WAIT1); | 442 | sk->sk_state != TCP_FIN_WAIT1); |
442 | tcp_fastopen_synack_timer(sk); | 443 | tcp_fastopen_synack_timer(sk, req); |
443 | /* Before we receive ACK to our SYN-ACK don't retransmit | 444 | /* Before we receive ACK to our SYN-ACK don't retransmit |
444 | * anything else (e.g., data or FIN segments). | 445 | * anything else (e.g., data or FIN segments). |
445 | */ | 446 | */ |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e3d9f4559c99..45a95e032bdf 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -406,7 +406,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
406 | 406 | ||
407 | tp = tcp_sk(sk); | 407 | tp = tcp_sk(sk); |
408 | /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ | 408 | /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ |
409 | fastopen = tp->fastopen_rsk; | 409 | fastopen = rcu_dereference(tp->fastopen_rsk); |
410 | snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; | 410 | snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; |
411 | if (sk->sk_state != TCP_LISTEN && | 411 | if (sk->sk_state != TCP_LISTEN && |
412 | !between(seq, snd_una, tp->snd_nxt)) { | 412 | !between(seq, snd_una, tp->snd_nxt)) { |