|
@@ -451,11 +451,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
|
|
unsigned int mask;
|
|
|
struct sock *sk = sock->sk;
|
|
|
const struct tcp_sock *tp = tcp_sk(sk);
|
|
|
+ int state;
|
|
|
|
|
|
sock_rps_record_flow(sk);
|
|
|
|
|
|
sock_poll_wait(file, sk_sleep(sk), wait);
|
|
|
- if (sk->sk_state == TCP_LISTEN)
|
|
|
+
|
|
|
+ state = sk_state_load(sk);
|
|
|
+ if (state == TCP_LISTEN)
|
|
|
return inet_csk_listen_poll(sk);
|
|
|
|
|
|
/* Socket is not locked. We are protected from async events
|
|
@@ -492,14 +495,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
|
|
* NOTE. Check for TCP_CLOSE is added. The goal is to prevent
|
|
|
* blocking on fresh not-connected or disconnected socket. --ANK
|
|
|
*/
|
|
|
- if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
|
|
|
+ if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
|
|
|
mask |= POLLHUP;
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
|
|
mask |= POLLIN | POLLRDNORM | POLLRDHUP;
|
|
|
|
|
|
/* Connected or passive Fast Open socket? */
|
|
|
- if (sk->sk_state != TCP_SYN_SENT &&
|
|
|
- (sk->sk_state != TCP_SYN_RECV || tp->fastopen_rsk)) {
|
|
|
+ if (state != TCP_SYN_SENT &&
|
|
|
+ (state != TCP_SYN_RECV || tp->fastopen_rsk)) {
|
|
|
int target = sock_rcvlowat(sk, 0, INT_MAX);
|
|
|
|
|
|
if (tp->urg_seq == tp->copied_seq &&
|
|
@@ -507,9 +510,6 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
|
|
|
tp->urg_data)
|
|
|
target++;
|
|
|
|
|
|
- /* Potential race condition. If read of tp below will
|
|
|
- * escape above sk->sk_state, we can be illegally awaken
|
|
|
- * in SYN_* states. */
|
|
|
if (tp->rcv_nxt - tp->copied_seq >= target)
|
|
|
mask |= POLLIN | POLLRDNORM;
|
|
|
|
|
@@ -1934,7 +1934,7 @@ void tcp_set_state(struct sock *sk, int state)
|
|
|
/* Change state AFTER socket is unhashed to avoid closed
|
|
|
* socket sitting in hash tables.
|
|
|
*/
|
|
|
- sk->sk_state = state;
|
|
|
+ sk_state_store(sk, state);
|
|
|
|
|
|
#ifdef STATE_TRACE
|
|
|
SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]);
|
|
@@ -2644,7 +2644,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
|
|
|
if (sk->sk_type != SOCK_STREAM)
|
|
|
return;
|
|
|
|
|
|
- info->tcpi_state = sk->sk_state;
|
|
|
+ info->tcpi_state = sk_state_load(sk);
|
|
|
+
|
|
|
info->tcpi_ca_state = icsk->icsk_ca_state;
|
|
|
info->tcpi_retransmits = icsk->icsk_retransmits;
|
|
|
info->tcpi_probes = icsk->icsk_probes_out;
|
|
@@ -2672,7 +2673,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
|
|
|
info->tcpi_snd_mss = tp->mss_cache;
|
|
|
info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss;
|
|
|
|
|
|
- if (sk->sk_state == TCP_LISTEN) {
|
|
|
+ if (info->tcpi_state == TCP_LISTEN) {
|
|
|
info->tcpi_unacked = sk->sk_ack_backlog;
|
|
|
info->tcpi_sacked = sk->sk_max_ack_backlog;
|
|
|
} else {
|