diff options
author | David S. Miller <davem@nuts.davemloft.net> | 2005-01-14 04:38:32 -0800 |
---|---|---|
committer | David S. Miller <davem@nuts.davemloft.net> | 2005-01-14 04:38:32 -0800 |
commit | d70ff6fd4876213458def03df3138f81399ccc26 (patch) | |
tree | b82661f59c17d7d88f4d33ab03542a5dd7cf36db /net | |
parent | 62343f7629a612d82f0314777b17dff7807976dc (diff) | |
download | history-d70ff6fd4876213458def03df3138f81399ccc26.tar.gz |
[TCP]: Do not underflow sk_forward_alloc in sendpage().
We need to do the proper checks before we try to
pull space out of it, just like sendmsg() does.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9a48486f7305de..c495e7ccd0c896 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -655,7 +655,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse while (psize > 0) { struct sk_buff *skb = sk->sk_write_queue.prev; struct page *page = pages[poffset / PAGE_SIZE]; - int copy, i; + int copy, i, can_coalesce; int offset = poffset % PAGE_SIZE; int size = min_t(size_t, psize, PAGE_SIZE - offset); @@ -677,14 +677,20 @@ new_segment: copy = size; i = skb_shinfo(skb)->nr_frags; - if (skb_can_coalesce(skb, i, page, offset)) { + can_coalesce = skb_can_coalesce(skb, i, page, offset); + if (!can_coalesce && i >= MAX_SKB_FRAGS) { + tcp_mark_push(tp, skb); + goto new_segment; + } + if (sk->sk_forward_alloc < copy && + !sk_stream_mem_schedule(sk, copy, 0)) + goto wait_for_memory; + + if (can_coalesce) { skb_shinfo(skb)->frags[i - 1].size += copy; - } else if (i < MAX_SKB_FRAGS) { + } else { get_page(page); skb_fill_page_desc(skb, i, page, offset, copy); - } else { - tcp_mark_push(tp, skb); - goto new_segment; } skb->len += copy; |