tcp: fix retransmission in repair mode
Currently if a socket was repaired with a few packet in a write queue, a kernel bug may be triggered: kernel BUG at net/ipv4/tcp_output.c:2330! RIP: 0010:[<ffffffff8155784f>] tcp_retransmit_skb+0x5ff/0x610 According to the initial realization v3.4-rc2-963-gc0e88ff, all skb-s should look like already posted. This patch fixes code according with this sentence. Here are three points, which were not done in the initial patch: 1. A tcp send head should not be changed 2. Initialize TSO state of a skb 3. Reset the retransmission time This patch moves logic from tcp_sendmsg to tcp_write_xmit. A packet passes the ussual way, but isn't sent to network. This patch solves all described problems and handles tcp_sendpages. Cc: Pavel Emelyanov <xemul@parallels.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> Cc: James Morris <jmorris@namei.org> Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> Cc: Patrick McHardy <kaber@trash.net> Signed-off-by: Andrey Vagin <avagin@openvz.org> Acked-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
0da9a0c263
Коммит
ec34232575
|
@ -1212,7 +1212,7 @@ new_segment:
|
||||||
wait_for_sndbuf:
|
wait_for_sndbuf:
|
||||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||||
wait_for_memory:
|
wait_for_memory:
|
||||||
if (copied && likely(!tp->repair))
|
if (copied)
|
||||||
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
|
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
|
||||||
|
|
||||||
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
|
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
|
||||||
|
@ -1223,7 +1223,7 @@ wait_for_memory:
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (copied && likely(!tp->repair))
|
if (copied)
|
||||||
tcp_push(sk, flags, mss_now, tp->nonagle);
|
tcp_push(sk, flags, mss_now, tp->nonagle);
|
||||||
release_sock(sk);
|
release_sock(sk);
|
||||||
return copied + copied_syn;
|
return copied + copied_syn;
|
||||||
|
|
|
@ -1986,6 +1986,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
|
||||||
tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
|
tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
|
||||||
BUG_ON(!tso_segs);
|
BUG_ON(!tso_segs);
|
||||||
|
|
||||||
|
if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE)
|
||||||
|
goto repair; /* Skip network transmission */
|
||||||
|
|
||||||
cwnd_quota = tcp_cwnd_test(tp, skb);
|
cwnd_quota = tcp_cwnd_test(tp, skb);
|
||||||
if (!cwnd_quota)
|
if (!cwnd_quota)
|
||||||
break;
|
break;
|
||||||
|
@ -2026,6 +2029,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
|
||||||
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
|
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
repair:
|
||||||
/* Advance the send_head. This one is sent out.
|
/* Advance the send_head. This one is sent out.
|
||||||
* This call will increment packets_out.
|
* This call will increment packets_out.
|
||||||
*/
|
*/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче