[TCP]: Adjust {p,f}ackets_out correctly in tcp_retransmit_skb()
Well I've only found one potential cause for the assertion failure in tcp_mark_head_lost. First of all, this can only occur if cnt > 1 since tp->packets_out is never zero here. If it did hit zero we'd have much bigger problems. So cnt is equal to fackets_out - reordering. Normally fackets_out is less than packets_out. The only reason I've found that might cause fackets_out to exceed packets_out is if tcp_fragment is called from tcp_retransmit_skb with a TSO skb and the current MSS is greater than the MSS stored in the TSO skb. This might occur as the result of an expiring dst entry. In that case, packets_out may decrease (line 1380-1381 in tcp_output.c). However, fackets_out is unchanged which means that it may in fact exceed packets_out. Previously tcp_retrans_try_collapse was the only place where packets_out can go down and it takes care of this by decrementing fackets_out. So we should make sure that fackets_out is reduced by an appropriate amount here as well. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
bc68552faa
Коммит
b5da623ae9
|
@ -1370,15 +1370,21 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
|
||||||
|
|
||||||
if (skb->len > cur_mss) {
|
if (skb->len > cur_mss) {
|
||||||
int old_factor = tcp_skb_pcount(skb);
|
int old_factor = tcp_skb_pcount(skb);
|
||||||
int new_factor;
|
int diff;
|
||||||
|
|
||||||
if (tcp_fragment(sk, skb, cur_mss, cur_mss))
|
if (tcp_fragment(sk, skb, cur_mss, cur_mss))
|
||||||
return -ENOMEM; /* We'll try again later. */
|
return -ENOMEM; /* We'll try again later. */
|
||||||
|
|
||||||
/* New SKB created, account for it. */
|
/* New SKB created, account for it. */
|
||||||
new_factor = tcp_skb_pcount(skb);
|
diff = old_factor - tcp_skb_pcount(skb) -
|
||||||
tp->packets_out -= old_factor - new_factor;
|
tcp_skb_pcount(skb->next);
|
||||||
tp->packets_out += tcp_skb_pcount(skb->next);
|
tp->packets_out -= diff;
|
||||||
|
|
||||||
|
if (diff > 0) {
|
||||||
|
tp->fackets_out -= diff;
|
||||||
|
if ((int)tp->fackets_out < 0)
|
||||||
|
tp->fackets_out = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Collapse two adjacent packets if worthwhile and we can. */
|
/* Collapse two adjacent packets if worthwhile and we can. */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче