From patchwork Sat Feb 21 11:44:27 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: 2.6.29-rc5-git3 Leak r=1 3 Date: Sat, 21 Feb 2009 01:44:27 -0000 From: =?utf-8?q?Ilpo_J=C3=A4rvinen?= X-Patchwork-Id: 23517 Message-Id: To: Denys Fedoryschenko Cc: Netdev , David Miller On Fri, 20 Feb 2009, Denys Fedoryschenko wrote: > On Friday 20 February 2009 18:09:54 Ilpo Järvinen wrote: > > > [45853.641072] TCP: Peer 172.16.193.87:1259/8080 unexpectedly shrunk > > > window 1905466446:1905480750 (repaired) > > > > Hmm, we might have sent past our allowed window due to some bug. ...Or > > combined some segments in the new shifting code incorrectly past the > > right edge of the window though I quickly checked and we do check for > > tcp_send_head there so it should be right. > > > This message (about window), i have tons of them, and had before a lot. > > I think it is not related, just i paste whole dmesg part where i see > more "Leak" messages. I'm sure i have more of them now. Indeed, there's a possiblity that tcp_sacktag_one didn't behave as expected wrt. retrans_out. You shouldn't have had any Leak in or before 2.6.28 (except perhaps in some ancient dev kernels). I also noticed that end_seq usage in tcp_sacktag_one is a bit suspicious too but found out that it mostly works. It would be safer to make partial end_seq available there though it's not too easy to find a sane scenario where the wrong end_seq makes any difference though. No need to do that in mainline for sure considering how small the worst case effect is. ...What a can of worms that tcp_sacktag_one is... Tested-by: Denys Fedoryshchenko diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a6961d7..c28976a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1374,7 +1374,8 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, struct tcp_sacktag_state *state, - unsigned int pcount, int shifted, int mss) + unsigned int pcount, int shifted, int mss, + int dup_sack) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *prev = tcp_write_queue_prev(sk, skb); @@ -1410,7 +1411,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, } /* We discard results */ - tcp_sacktag_one(skb, sk, state, 0, pcount); + tcp_sacktag_one(skb, sk, state, dup_sack, pcount); /* Difference in this won't matter, both ACKed by the same cumul. ACK */ TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); @@ -1561,7 +1562,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, if (!skb_shift(prev, skb, len)) goto fallback; - if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss)) + if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack)) goto out; /* Hole filled allows collapsing with the next as well, this is very @@ -1580,7 +1581,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, len = skb->len; if (skb_shift(prev, skb, len)) { pcount += tcp_skb_pcount(skb); - tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss); + tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0); } out: