* is not a big flaw.
*/
-static inline unsigned int tcp_current_mss(struct sock *sk, int large, int *factor)
+static inline unsigned int tcp_current_mss(struct sock *sk, int large)
{
struct tcp_opt *tp = tcp_sk(sk);
struct dst_entry *dst = __sk_dst_get(sk);
(sk->sk_route_caps & NETIF_F_TSO) &&
!tp->urg_mode);
mss_now = do_large ? tp->mss_cache : tp->mss_cache_std;
- if (factor)
- *factor = do_large ? tp->mss_tso_factor : 1;
if (dst) {
u32 mtu = dst_pmtu(dst);
static __inline__ void tcp_push_pending_frames(struct sock *sk,
struct tcp_opt *tp)
{
- __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1, NULL), tp->nonagle);
+ __tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1), tp->nonagle);
}
static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_opt *tp)
struct sk_buff *skb = sk->sk_send_head;
return (skb &&
- tcp_snd_test(tp, skb, tcp_current_mss(sk, 1, NULL),
+ tcp_snd_test(tp, skb, tcp_current_mss(sk, 1),
tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
}
}
static inline void skb_entail(struct sock *sk, struct tcp_opt *tp,
- struct sk_buff *skb, int tso_factor)
+ struct sk_buff *skb)
{
skb->csum = 0;
TCP_SKB_CB(skb)->seq = tp->write_seq;
TCP_SKB_CB(skb)->end_seq = tp->write_seq;
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(skb)->sacked = 0;
- TCP_SKB_CB(skb)->tso_factor = tso_factor;
__skb_queue_tail(&sk->sk_write_queue, skb);
sk_charge_skb(sk, skb);
if (!sk->sk_send_head)
size_t psize, int flags)
{
struct tcp_opt *tp = tcp_sk(sk);
- int mss_now, mss_factor_now;
+ int mss_now;
int err;
ssize_t copied;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
- mss_now = tcp_current_mss(sk, !(flags&MSG_OOB), &mss_factor_now);
+ mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
copied = 0;
err = -EPIPE;
if (!skb)
goto wait_for_memory;
- skb_entail(sk, tp, skb, mss_factor_now);
+ skb_entail(sk, tp, skb);
copy = mss_now;
}
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;
- mss_now = tcp_current_mss(sk, !(flags&MSG_OOB),
- &mss_factor_now);
+ mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
}
out:
struct tcp_opt *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags;
- int mss_now, mss_factor_now;
+ int mss_now;
int err, copied;
long timeo;
/* This should be in poll */
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
- mss_now = tcp_current_mss(sk, !(flags&MSG_OOB), &mss_factor_now);
+ mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
/* Ok commence sending. */
iovlen = msg->msg_iovlen;
NETIF_F_HW_CSUM))
skb->ip_summed = CHECKSUM_HW;
- skb_entail(sk, tp, skb, mss_factor_now);
+ skb_entail(sk, tp, skb);
copy = mss_now;
}
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;
- mss_now = tcp_current_mss(sk, !(flags&MSG_OOB),
- &mss_factor_now);
+ mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
}
}
}
}
+static void tcp_set_skb_tso_factor(struct sk_buff *skb, unsigned int mss,
+ unsigned int mss_std)
+{
+ if (skb->len <= mss_std) {
+ /* Avoid the costly divide in the normal
+ * non-TSO case.
+ */
+ TCP_SKB_CB(skb)->tso_factor = 1;
+ } else {
+ unsigned int factor;
+
+ factor = skb->len + (mss_std - 1);
+ factor /= mss;
+ TCP_SKB_CB(skb)->tso_factor = factor;
+ }
+}
+
/* Function to create two new TCP segments. Shrinks the given segment
* to the specified size and appends a new segment with the rest of the
* packet to the list. This won't be called frequently, I hope.
TCP_SKB_CB(buff)->sacked =
(TCP_SKB_CB(skb)->sacked &
(TCPCB_LOST | TCPCB_EVER_RETRANS | TCPCB_AT_TAIL));
- TCP_SKB_CB(buff)->tso_factor = tp->mss_tso_factor;
if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) {
tcp_inc_pcount(&tp->lost_out, buff);
tcp_inc_pcount(&tp->left_out, buff);
*/
TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
+ /* Fix up tso_factor for both original and new SKB. */
+ tcp_set_skb_tso_factor(skb, tp->mss_cache, tp->mss_cache_std);
+ tcp_set_skb_tso_factor(buff, tp->mss_cache, tp->mss_cache_std);
+
/* Link BUFF into the send queue. */
__skb_append(skb, buff);
/* And store cached results */
tp->pmtu_cookie = pmtu;
tp->mss_cache = tp->mss_cache_std = mss_now;
- tp->mss_tso_factor = 1;
if (sk->sk_route_caps & NETIF_F_TSO) {
int large_mss, factor;
factor = tp->snd_cwnd;
tp->mss_cache = mss_now * factor;
- tp->mss_tso_factor = factor;
}
return mss_now;
int tcp_write_xmit(struct sock *sk, int nonagle)
{
struct tcp_opt *tp = tcp_sk(sk);
- unsigned int mss_now;
+ unsigned int mss_now, mss_std;
/* If we are closed, the bytes will have to remain here.
* In time closedown will finish, we empty the write queue and all
* We also handle things correctly when the user adds some
* IP options mid-stream. Silly to do, but cover it.
*/
- mss_now = tcp_current_mss(sk, 1, NULL);
+ mss_now = tcp_current_mss(sk, 1);
+ mss_std = tp->mss_cache_std;
while ((skb = sk->sk_send_head) &&
tcp_snd_test(tp, skb, mss_now,
if (skb->len > mss_now) {
if (tcp_fragment(sk, skb, mss_now))
break;
- }
+ } else
+ tcp_set_skb_tso_factor(skb, mss_now, mss_std);
TCP_SKB_CB(skb)->when = tcp_time_stamp;
if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)))
{
struct tcp_opt *tp = tcp_sk(sk);
struct sk_buff *skb;
- unsigned int mss = tcp_current_mss(sk, 0, NULL);
+ unsigned int mss = tcp_current_mss(sk, 0);
int lost = 0;
sk_stream_for_retrans_queue(skb, sk) {
int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
struct tcp_opt *tp = tcp_sk(sk);
- unsigned int cur_mss = tcp_current_mss(sk, 0, NULL);
+ unsigned int cur_mss = tcp_current_mss(sk, 0);
int err;
/* Do not sent more than we queued. 1/4 is reserved for possible
sk->sk_route_caps &= ~NETIF_F_TSO;
sk->sk_no_largesend = 1;
tp->mss_cache = tp->mss_cache_std;
- tp->mss_tso_factor = 1;
}
if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
* unsent frames. But be careful about outgoing SACKS
* and IP options.
*/
- mss_now = tcp_current_mss(sk, 1, NULL);
+ mss_now = tcp_current_mss(sk, 1);
if (sk->sk_send_head != NULL) {
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
if ((skb = sk->sk_send_head) != NULL &&
before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) {
int err;
- int mss = tcp_current_mss(sk, 0, NULL);
- int seg_size = tp->snd_una+tp->snd_wnd-TCP_SKB_CB(skb)->seq;
+ unsigned int mss = tcp_current_mss(sk, 0);
+ unsigned int mss_std = tp->mss_cache_std;
+ unsigned int seg_size = tp->snd_una+tp->snd_wnd-TCP_SKB_CB(skb)->seq;
if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq))
tp->pushed_seq = TCP_SKB_CB(skb)->end_seq;
sk->sk_no_largesend = 1;
sk->sk_route_caps &= ~NETIF_F_TSO;
tp->mss_cache = tp->mss_cache_std;
- tp->mss_tso_factor = 1;
}
- }
+ } else
+ tcp_set_skb_tso_factor(skb, mss, mss_std);
+
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
TCP_SKB_CB(skb)->when = tcp_time_stamp;
err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));