On Tue, 2016-08-16 at 13:19 -0700, Cong Wang wrote: > On Tue, Aug 16, 2016 at 11:39 AM, Eric Dumazet <eric.duma...@gmail.com> wrote: > > On Tue, 2016-08-16 at 08:39 -0700, Eric Dumazet wrote: > >> On Tue, 2016-08-16 at 12:45 +0200, Greg KH wrote: > >> > For some reason Marco's emails can't make it to netdev, so I'm > >> > forwarding this on. Please cc: him on responses. > >> > >> Thanks for the report Greg and Marco. > >> > >> My first guess is this is caused by > >> > >> d41a69f1d390 tcp: make tcp_sendmsg() aware of socket backlog > >> > >> And a combination of funky sendmsg() flags (like FastOpen) > >> > >> I will look at this problem today. > >> > > > > No, above commit was innocent ;) > > > > It looks like the bug is very old, and following patch would fix it. > > I will submit it formally after few tests. > > > > > > diff --git a/include/net/tcp.h b/include/net/tcp.h > > index c00e7d51bb18..7717302cab91 100644 > > --- a/include/net/tcp.h > > +++ b/include/net/tcp.h > > @@ -1523,6 +1523,8 @@ static inline void tcp_check_send_head(struct sock > > *sk, struct sk_buff *skb_unli > > { > > if (sk->sk_send_head == skb_unlinked) > > sk->sk_send_head = NULL; > > + if (tcp_sk(sk)->highest_sack == skb_unlinked) > > + tcp_sk(sk)->highest_sack = NULL; > > } > > Hmm, but from the stack traces it indicates the skb is freed > inside tcp_sendmsg(), which must be: > > > do_fault: > if (!skb->len) { > tcp_unlink_write_queue(skb, sk); > /* It is the one place in all of TCP, except connection > * reset, where we can be unlinking the send_head. > */ > tcp_check_send_head(sk, skb); > sk_wmem_free_skb(sk, skb); > } > > In this case, skb->len == 0 means it is newly allocated skb by > sk_stream_alloc_skb(), so it should not have a chance to be > picked by tp->highest_sack yet b/c the whole function locks > the sock? > > I must miss something here.
Look at skb_entail() : It calls tcp_add_write_queue_tail() And tcp_add_write_queue_tail() looks like : static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) { __tcp_add_write_queue_tail(sk, skb); /* Queue it, remembering where we must start sending. */ if (sk->sk_send_head == NULL) { sk->sk_send_head = skb; if (tcp_sk(sk)->highest_sack == NULL) tcp_sk(sk)->highest_sack = skb; } } So we definitely need to undo what tcp_add_write_queue_tail() did.