From: David S. Miller Date: Fri, 21 Jan 2011 06:46:07 +0000 (-0800) Subject: ppp: Reconstruct fragmented packets using frag lists instead of copying. X-Git-Tag: v2.6.39-rc1~468^2~491 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=212bfb9e94e86b40684076f642b089b0565455d2;p=karo-tx-linux.git ppp: Reconstruct fragmented packets using frag lists instead of copying. [paulus@samba.org: fixed a couple of bugs] Signed-off-by: David S. Miller Signed-off-by: Paul Mackerras --- diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 3d7a38eeacda..1d4fb348488f 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -2055,16 +2055,6 @@ ppp_mp_reconstruct(struct ppp *ppp) netdev_printk(KERN_DEBUG, ppp->dev, "PPP: reconstructed packet" " is too long (%d)\n", len); - } else if (p == head) { - /* fragment is complete packet - reuse skb */ - tail = p; - skb = skb_get(p); - break; - } else if ((skb = dev_alloc_skb(len)) == NULL) { - ++ppp->dev->stats.rx_missed_errors; - netdev_printk(KERN_DEBUG, ppp->dev, - "PPP: no memory for " - "reconstructed packet"); } else { tail = p; break; @@ -2097,16 +2087,33 @@ ppp_mp_reconstruct(struct ppp *ppp) ppp_receive_error(ppp); } - if (head != tail) - /* copy to a single skb */ - for (p = head; p != tail->next; p = p->next) - skb_copy_bits(p, 0, skb_put(skb, p->len), p->len); + skb = head; + if (head != tail) { + struct sk_buff **fragpp = &skb_shinfo(skb)->frag_list; + p = skb_queue_next(list, head); + __skb_unlink(skb, list); + skb_queue_walk_from_safe(list, p, tmp) { + __skb_unlink(p, list); + *fragpp = p; + p->next = NULL; + fragpp = &p->next; + + skb->len += p->len; + skb->data_len += p->len; + skb->truesize += p->len; + + if (p == tail) + break; + } + } else { + __skb_unlink(skb, list); + } + ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; head = tail->next; } - /* Discard all the skbuffs that we have copied the data out of - or that we can't use. */ + /* Discard all the skbuffs that we can't use. */ while ((p = list->next) != head) { __skb_unlink(p, list); kfree_skb(p);