| Submitter | Eric Dumazet |
|---|---|
| Date | Dec. 1, 2012, 10:32 p.m. |
| Message ID | <1354401121.20109.531.camel@edumazet-glaptop> |
| Download | mbox | patch |
| Permalink | /patch/203155/ |
| State | RFC |
| Delegated to: | David Miller |
| Headers | show |
Comments
On Sat, Dec 01, 2012 at 02:32:01PM -0800, Eric Dumazet wrote: > On Sat, 2012-12-01 at 13:47 -0800, Eric Dumazet wrote: > > > Thanks a lot Willy > > > > I believe do_tcp_sendpages() needs a fix, I'll send a patch asap > > > > Could you try the following patch ? > > do_tcp_sendpages() looks really wrong, as only one page is provided by > the caller. Excellent Eric, it's rock solid now both with the reproducer and with haproxy! Feel free to add my Tested-By if you want. I really think we should feed this to Linus quickly before he releases 3.7, as I'm realizing that it would really not be nice to have a user-triggerable crash in a release :-/ Thanks ! Willy -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Sat, 2012-12-01 at 23:40 +0100, Willy Tarreau wrote: > Excellent Eric, it's rock solid now both with the reproducer and with > haproxy! Feel free to add my Tested-By if you want. You did a very good work, thanks again Willy. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Patch
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e6eace1..6976dba 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -831,8 +831,8 @@ static int tcp_send_mss(struct sock *sk, int *size_goal, int flags) return mss_now; } -static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, - size_t psize, int flags) +static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, + size_t size, int flags) { struct tcp_sock *tp = tcp_sk(sk); int mss_now, size_goal; @@ -859,12 +859,9 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto out_err; - while (psize > 0) { + while (size > 0) { struct sk_buff *skb = tcp_write_queue_tail(sk); - struct page *page = pages[poffset / PAGE_SIZE]; int copy, i; - int offset = poffset % PAGE_SIZE; - int size = min_t(size_t, psize, PAGE_SIZE - offset); bool can_coalesce; if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0) { @@ -913,8 +910,8 @@ new_segment: TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; copied += copy; - poffset += copy; - if (!(psize -= copy)) + offset += copy; + if (!(size -= copy)) goto out; if (skb->len < size_goal || (flags & MSG_OOB)) @@ -961,7 +958,7 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset, flags); lock_sock(sk); - res = do_tcp_sendpages(sk, &page, offset, size, flags); + res = do_tcp_sendpages(sk, page, offset, size, flags); release_sock(sk); return res; }