Commit 0f317464 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp: annotate tp->write_seq lockless reads

There are few places where we fetch tp->write_seq while
this field can change from IRQ or other cpu.

We need to add READ_ONCE() annotations, and also make
sure write sides use corresponding WRITE_ONCE() to avoid
store-tearing.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7db48e98
...@@ -1917,7 +1917,7 @@ static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp) ...@@ -1917,7 +1917,7 @@ static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp)
static inline bool tcp_stream_memory_free(const struct sock *sk, int wake) static inline bool tcp_stream_memory_free(const struct sock *sk, int wake)
{ {
const struct tcp_sock *tp = tcp_sk(sk); const struct tcp_sock *tp = tcp_sk(sk);
u32 notsent_bytes = tp->write_seq - tp->snd_nxt; u32 notsent_bytes = READ_ONCE(tp->write_seq) - tp->snd_nxt;
return (notsent_bytes << wake) < tcp_notsent_lowat(tp); return (notsent_bytes << wake) < tcp_notsent_lowat(tp);
} }
......
...@@ -616,7 +616,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -616,7 +616,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
answ = 0; answ = 0;
else else
answ = tp->write_seq - tp->snd_una; answ = READ_ONCE(tp->write_seq) - tp->snd_una;
break; break;
case SIOCOUTQNSD: case SIOCOUTQNSD:
if (sk->sk_state == TCP_LISTEN) if (sk->sk_state == TCP_LISTEN)
...@@ -625,7 +625,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -625,7 +625,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
answ = 0; answ = 0;
else else
answ = tp->write_seq - tp->snd_nxt; answ = READ_ONCE(tp->write_seq) - tp->snd_nxt;
break; break;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
...@@ -1035,7 +1035,7 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ...@@ -1035,7 +1035,7 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
sk->sk_wmem_queued += copy; sk->sk_wmem_queued += copy;
sk_mem_charge(sk, copy); sk_mem_charge(sk, copy);
skb->ip_summed = CHECKSUM_PARTIAL; skb->ip_summed = CHECKSUM_PARTIAL;
tp->write_seq += copy; WRITE_ONCE(tp->write_seq, tp->write_seq + copy);
TCP_SKB_CB(skb)->end_seq += copy; TCP_SKB_CB(skb)->end_seq += copy;
tcp_skb_pcount_set(skb, 0); tcp_skb_pcount_set(skb, 0);
...@@ -1362,7 +1362,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) ...@@ -1362,7 +1362,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
if (!copied) if (!copied)
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
tp->write_seq += copy; WRITE_ONCE(tp->write_seq, tp->write_seq + copy);
TCP_SKB_CB(skb)->end_seq += copy; TCP_SKB_CB(skb)->end_seq += copy;
tcp_skb_pcount_set(skb, 0); tcp_skb_pcount_set(skb, 0);
...@@ -2562,6 +2562,7 @@ int tcp_disconnect(struct sock *sk, int flags) ...@@ -2562,6 +2562,7 @@ int tcp_disconnect(struct sock *sk, int flags)
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
int old_state = sk->sk_state; int old_state = sk->sk_state;
u32 seq;
if (old_state != TCP_CLOSE) if (old_state != TCP_CLOSE)
tcp_set_state(sk, TCP_CLOSE); tcp_set_state(sk, TCP_CLOSE);
...@@ -2604,9 +2605,12 @@ int tcp_disconnect(struct sock *sk, int flags) ...@@ -2604,9 +2605,12 @@ int tcp_disconnect(struct sock *sk, int flags)
tp->srtt_us = 0; tp->srtt_us = 0;
tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
tp->rcv_rtt_last_tsecr = 0; tp->rcv_rtt_last_tsecr = 0;
tp->write_seq += tp->max_window + 2;
if (tp->write_seq == 0) seq = tp->write_seq + tp->max_window + 2;
tp->write_seq = 1; if (!seq)
seq = 1;
WRITE_ONCE(tp->write_seq, seq);
icsk->icsk_backoff = 0; icsk->icsk_backoff = 0;
tp->snd_cwnd = 2; tp->snd_cwnd = 2;
icsk->icsk_probes_out = 0; icsk->icsk_probes_out = 0;
...@@ -2933,7 +2937,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, ...@@ -2933,7 +2937,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
if (sk->sk_state != TCP_CLOSE) if (sk->sk_state != TCP_CLOSE)
err = -EPERM; err = -EPERM;
else if (tp->repair_queue == TCP_SEND_QUEUE) else if (tp->repair_queue == TCP_SEND_QUEUE)
tp->write_seq = val; WRITE_ONCE(tp->write_seq, val);
else if (tp->repair_queue == TCP_RECV_QUEUE) else if (tp->repair_queue == TCP_RECV_QUEUE)
WRITE_ONCE(tp->rcv_nxt, val); WRITE_ONCE(tp->rcv_nxt, val);
else else
......
...@@ -28,7 +28,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, ...@@ -28,7 +28,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
r->idiag_rqueue = max_t(int, READ_ONCE(tp->rcv_nxt) - r->idiag_rqueue = max_t(int, READ_ONCE(tp->rcv_nxt) -
READ_ONCE(tp->copied_seq), 0); READ_ONCE(tp->copied_seq), 0);
r->idiag_wqueue = tp->write_seq - tp->snd_una; r->idiag_wqueue = READ_ONCE(tp->write_seq) - tp->snd_una;
} }
if (info) if (info)
tcp_get_info(sk, info); tcp_get_info(sk, info);
......
...@@ -164,9 +164,11 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) ...@@ -164,9 +164,11 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
* without appearing to create any others. * without appearing to create any others.
*/ */
if (likely(!tp->repair)) { if (likely(!tp->repair)) {
tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; u32 seq = tcptw->tw_snd_nxt + 65535 + 2;
if (tp->write_seq == 0)
tp->write_seq = 1; if (!seq)
seq = 1;
WRITE_ONCE(tp->write_seq, seq);
tp->rx_opt.ts_recent = tcptw->tw_ts_recent; tp->rx_opt.ts_recent = tcptw->tw_ts_recent;
tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
} }
...@@ -253,7 +255,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -253,7 +255,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tp->rx_opt.ts_recent = 0; tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0; tp->rx_opt.ts_recent_stamp = 0;
if (likely(!tp->repair)) if (likely(!tp->repair))
tp->write_seq = 0; WRITE_ONCE(tp->write_seq, 0);
} }
inet->inet_dport = usin->sin_port; inet->inet_dport = usin->sin_port;
...@@ -291,10 +293,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -291,10 +293,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (likely(!tp->repair)) { if (likely(!tp->repair)) {
if (!tp->write_seq) if (!tp->write_seq)
tp->write_seq = secure_tcp_seq(inet->inet_saddr, WRITE_ONCE(tp->write_seq,
inet->inet_daddr, secure_tcp_seq(inet->inet_saddr,
inet->inet_sport, inet->inet_daddr,
usin->sin_port); inet->inet_sport,
usin->sin_port));
tp->tsoffset = secure_tcp_ts_off(sock_net(sk), tp->tsoffset = secure_tcp_ts_off(sock_net(sk),
inet->inet_saddr, inet->inet_saddr,
inet->inet_daddr); inet->inet_daddr);
...@@ -2461,7 +2464,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) ...@@ -2461,7 +2464,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d", "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
i, src, srcp, dest, destp, state, i, src, srcp, dest, destp, state,
tp->write_seq - tp->snd_una, READ_ONCE(tp->write_seq) - tp->snd_una,
rx_queue, rx_queue,
timer_active, timer_active,
jiffies_delta_to_clock_t(timer_expires - jiffies), jiffies_delta_to_clock_t(timer_expires - jiffies),
......
...@@ -498,7 +498,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, ...@@ -498,7 +498,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
newtp->total_retrans = req->num_retrans; newtp->total_retrans = req->num_retrans;
tcp_init_xmit_timers(newsk); tcp_init_xmit_timers(newsk);
newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1; WRITE_ONCE(newtp->write_seq, newtp->pushed_seq = treq->snt_isn + 1);
if (sock_flag(newsk, SOCK_KEEPOPEN)) if (sock_flag(newsk, SOCK_KEEPOPEN))
inet_csk_reset_keepalive_timer(newsk, inet_csk_reset_keepalive_timer(newsk,
......
...@@ -1196,7 +1196,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ...@@ -1196,7 +1196,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
/* Advance write_seq and place onto the write_queue. */ /* Advance write_seq and place onto the write_queue. */
tp->write_seq = TCP_SKB_CB(skb)->end_seq; WRITE_ONCE(tp->write_seq, TCP_SKB_CB(skb)->end_seq);
__skb_header_release(skb); __skb_header_release(skb);
tcp_add_write_queue_tail(sk, skb); tcp_add_write_queue_tail(sk, skb);
sk->sk_wmem_queued += skb->truesize; sk->sk_wmem_queued += skb->truesize;
...@@ -3449,7 +3449,7 @@ static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) ...@@ -3449,7 +3449,7 @@ static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb)
__skb_header_release(skb); __skb_header_release(skb);
sk->sk_wmem_queued += skb->truesize; sk->sk_wmem_queued += skb->truesize;
sk_mem_charge(sk, skb->truesize); sk_mem_charge(sk, skb->truesize);
tp->write_seq = tcb->end_seq; WRITE_ONCE(tp->write_seq, tcb->end_seq);
tp->packets_out += tcp_skb_pcount(skb); tp->packets_out += tcp_skb_pcount(skb);
} }
......
...@@ -215,7 +215,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -215,7 +215,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
!ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) { !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) {
tp->rx_opt.ts_recent = 0; tp->rx_opt.ts_recent = 0;
tp->rx_opt.ts_recent_stamp = 0; tp->rx_opt.ts_recent_stamp = 0;
tp->write_seq = 0; WRITE_ONCE(tp->write_seq, 0);
} }
sk->sk_v6_daddr = usin->sin6_addr; sk->sk_v6_daddr = usin->sin6_addr;
...@@ -311,10 +311,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -311,10 +311,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (likely(!tp->repair)) { if (likely(!tp->repair)) {
if (!tp->write_seq) if (!tp->write_seq)
tp->write_seq = secure_tcpv6_seq(np->saddr.s6_addr32, WRITE_ONCE(tp->write_seq,
sk->sk_v6_daddr.s6_addr32, secure_tcpv6_seq(np->saddr.s6_addr32,
inet->inet_sport, sk->sk_v6_daddr.s6_addr32,
inet->inet_dport); inet->inet_sport,
inet->inet_dport));
tp->tsoffset = secure_tcpv6_ts_off(sock_net(sk), tp->tsoffset = secure_tcpv6_ts_off(sock_net(sk),
np->saddr.s6_addr32, np->saddr.s6_addr32,
sk->sk_v6_daddr.s6_addr32); sk->sk_v6_daddr.s6_addr32);
...@@ -1907,7 +1908,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) ...@@ -1907,7 +1908,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp, dest->s6_addr32[2], dest->s6_addr32[3], destp,
state, state,
tp->write_seq - tp->snd_una, READ_ONCE(tp->write_seq) - tp->snd_una,
rx_queue, rx_queue,
timer_active, timer_active,
jiffies_delta_to_clock_t(timer_expires - jiffies), jiffies_delta_to_clock_t(timer_expires - jiffies),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment