提交 f8269a49 编写于 作者: I Ilpo Järvinen 提交者: David S. Miller

tcp: make urg+gso work for real this time

I should have noticed this earlier... :-) The previous solution
to URG+GSO/TSO will cause SACK block tcp_fragment to do zig-zig
patterns, or even worse, a steep downward slope into packet
counting because each skb pcount would be truncated to pcount
of 2 and then the following fragments of the later portion would
restore the window again.

Basically this reverts "tcp: Do not use TSO/GSO when there is
urgent data" (33cf71ce). It also removes some unnecessary code
from tcp_current_mss that didn't work as intented either (could
be that something was changed down the road, or it might have
been broken since the dawn of time) because it only works once
urg is already written while this bug shows up starting from
~64k before the urg point.

The retransmissions already are split to mss sized chunks, so
only new data sending paths need splitting in case they have
a segment otherwise suitable for gso/tso. The actually check
can be improved to be more narrow but since this is late -rc
already, I'll postpone thinking the more fine-grained things.
Signed-off-by: NIlpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 5176da7e
...@@ -722,8 +722,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ...@@ -722,8 +722,7 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb,
unsigned int mss_now) unsigned int mss_now)
{ {
if (skb->len <= mss_now || !sk_can_gso(sk) || if (skb->len <= mss_now || !sk_can_gso(sk)) {
tcp_urg_mode(tcp_sk(sk))) {
/* Avoid the costly divide in the normal /* Avoid the costly divide in the normal
* non-TSO case. * non-TSO case.
*/ */
...@@ -1029,10 +1028,6 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu) ...@@ -1029,10 +1028,6 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
/* Compute the current effective MSS, taking SACKs and IP options, /* Compute the current effective MSS, taking SACKs and IP options,
* and even PMTU discovery events into account. * and even PMTU discovery events into account.
*
* LARGESEND note: !tcp_urg_mode is overkill, only frames up to snd_up
* cannot be large. However, taking into account rare use of URG, this
* is not a big flaw.
*/ */
unsigned int tcp_current_mss(struct sock *sk, int large_allowed) unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
{ {
...@@ -1047,7 +1042,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) ...@@ -1047,7 +1042,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
mss_now = tp->mss_cache; mss_now = tp->mss_cache;
if (large_allowed && sk_can_gso(sk) && !tcp_urg_mode(tp)) if (large_allowed && sk_can_gso(sk))
doing_tso = 1; doing_tso = 1;
if (dst) { if (dst) {
...@@ -1164,9 +1159,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, ...@@ -1164,9 +1159,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb,
{ {
int tso_segs = tcp_skb_pcount(skb); int tso_segs = tcp_skb_pcount(skb);
if (!tso_segs || if (!tso_segs || (tso_segs > 1 && tcp_skb_mss(skb) != mss_now)) {
(tso_segs > 1 && (tcp_skb_mss(skb) != mss_now ||
tcp_urg_mode(tcp_sk(sk))))) {
tcp_set_skb_tso_segs(sk, skb, mss_now); tcp_set_skb_tso_segs(sk, skb, mss_now);
tso_segs = tcp_skb_pcount(skb); tso_segs = tcp_skb_pcount(skb);
} }
...@@ -1519,6 +1512,10 @@ static int tcp_mtu_probe(struct sock *sk) ...@@ -1519,6 +1512,10 @@ static int tcp_mtu_probe(struct sock *sk)
* send_head. This happens as incoming acks open up the remote * send_head. This happens as incoming acks open up the remote
* window for us. * window for us.
* *
* LARGESEND note: !tcp_urg_mode is overkill, only frames between
* snd_up-64k-mss .. snd_up cannot be large. However, taking into
* account rare use of URG, this is not a big flaw.
*
* Returns 1, if no segments are in flight and we have queued segments, but * Returns 1, if no segments are in flight and we have queued segments, but
* cannot send anything now because of SWS or another problem. * cannot send anything now because of SWS or another problem.
*/ */
...@@ -1570,7 +1567,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) ...@@ -1570,7 +1567,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
} }
limit = mss_now; limit = mss_now;
if (tso_segs > 1) if (tso_segs > 1 && !tcp_urg_mode(tp))
limit = tcp_mss_split_point(sk, skb, mss_now, limit = tcp_mss_split_point(sk, skb, mss_now,
cwnd_quota); cwnd_quota);
...@@ -1619,6 +1616,7 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, ...@@ -1619,6 +1616,7 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
*/ */
void tcp_push_one(struct sock *sk, unsigned int mss_now) void tcp_push_one(struct sock *sk, unsigned int mss_now)
{ {
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb = tcp_send_head(sk); struct sk_buff *skb = tcp_send_head(sk);
unsigned int tso_segs, cwnd_quota; unsigned int tso_segs, cwnd_quota;
...@@ -1633,7 +1631,7 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now) ...@@ -1633,7 +1631,7 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now)
BUG_ON(!tso_segs); BUG_ON(!tso_segs);
limit = mss_now; limit = mss_now;
if (tso_segs > 1) if (tso_segs > 1 && !tcp_urg_mode(tp))
limit = tcp_mss_split_point(sk, skb, mss_now, limit = tcp_mss_split_point(sk, skb, mss_now,
cwnd_quota); cwnd_quota);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册