|
@@ -4358,6 +4358,23 @@ static bool tcp_try_coalesce(struct sock *sk,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool tcp_ooo_try_coalesce(struct sock *sk,
|
|
|
|
+ struct sk_buff *to,
|
|
|
|
+ struct sk_buff *from,
|
|
|
|
+ bool *fragstolen)
|
|
|
|
+{
|
|
|
|
+ bool res = tcp_try_coalesce(sk, to, from, fragstolen);
|
|
|
|
+
|
|
|
|
+ /* In case tcp_drop() is called later, update to->gso_segs */
|
|
|
|
+ if (res) {
|
|
|
|
+ u32 gso_segs = max_t(u16, 1, skb_shinfo(to)->gso_segs) +
|
|
|
|
+ max_t(u16, 1, skb_shinfo(from)->gso_segs);
|
|
|
|
+
|
|
|
|
+ skb_shinfo(to)->gso_segs = min_t(u32, gso_segs, 0xFFFF);
|
|
|
|
+ }
|
|
|
|
+ return res;
|
|
|
|
+}
|
|
|
|
+
|
|
static void tcp_drop(struct sock *sk, struct sk_buff *skb)
|
|
static void tcp_drop(struct sock *sk, struct sk_buff *skb)
|
|
{
|
|
{
|
|
sk_drops_add(sk, skb);
|
|
sk_drops_add(sk, skb);
|
|
@@ -4481,8 +4498,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
|
|
/* In the typical case, we are adding an skb to the end of the list.
|
|
/* In the typical case, we are adding an skb to the end of the list.
|
|
* Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup.
|
|
* Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup.
|
|
*/
|
|
*/
|
|
- if (tcp_try_coalesce(sk, tp->ooo_last_skb,
|
|
|
|
- skb, &fragstolen)) {
|
|
|
|
|
|
+ if (tcp_ooo_try_coalesce(sk, tp->ooo_last_skb,
|
|
|
|
+ skb, &fragstolen)) {
|
|
coalesce_done:
|
|
coalesce_done:
|
|
tcp_grow_window(sk, skb);
|
|
tcp_grow_window(sk, skb);
|
|
kfree_skb_partial(skb, fragstolen);
|
|
kfree_skb_partial(skb, fragstolen);
|
|
@@ -4532,8 +4549,8 @@ coalesce_done:
|
|
tcp_drop(sk, skb1);
|
|
tcp_drop(sk, skb1);
|
|
goto merge_right;
|
|
goto merge_right;
|
|
}
|
|
}
|
|
- } else if (tcp_try_coalesce(sk, skb1,
|
|
|
|
- skb, &fragstolen)) {
|
|
|
|
|
|
+ } else if (tcp_ooo_try_coalesce(sk, skb1,
|
|
|
|
+ skb, &fragstolen)) {
|
|
goto coalesce_done;
|
|
goto coalesce_done;
|
|
}
|
|
}
|
|
p = &parent->rb_right;
|
|
p = &parent->rb_right;
|