diff options
| author | Eric Dumazet <edumazet@google.com> | 2014-10-03 23:59:19 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-10-06 00:37:30 -0400 |
| commit | bec3cfdca36bf43cfa3751ad7b56db1a307e0760 (patch) | |
| tree | d9c2d8352b0cc41d43dc23b7a7eafdac6758aeb3 /net | |
| parent | 45d9cc7c609680e921060d3eb4e399043eb5e4be (diff) | |
net: skb_segment() provides list head and tail
Its unfortunate we have to walk again skb list to find the tail
after segmentation, even if data is probably hot in cpu caches.
skb_segment() can store the tail of the list into segs->prev,
and validate_xmit_skb_list() can immediately get the tail.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/dev.c | 27 | ||||
| -rw-r--r-- | net/core/skbuff.c | 5 |
2 files changed, 20 insertions, 12 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 1a90530f83ff..7d5691cc1f47 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2724,22 +2724,25 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *d | |||
| 2724 | { | 2724 | { |
| 2725 | struct sk_buff *next, *head = NULL, *tail; | 2725 | struct sk_buff *next, *head = NULL, *tail; |
| 2726 | 2726 | ||
| 2727 | while (skb) { | 2727 | for (; skb != NULL; skb = next) { |
| 2728 | next = skb->next; | 2728 | next = skb->next; |
| 2729 | skb->next = NULL; | 2729 | skb->next = NULL; |
| 2730 | |||
| 2731 | /* in case skb wont be segmented, point to itself */ | ||
| 2732 | skb->prev = skb; | ||
| 2733 | |||
| 2730 | skb = validate_xmit_skb(skb, dev); | 2734 | skb = validate_xmit_skb(skb, dev); |
| 2731 | if (skb) { | 2735 | if (!skb) |
| 2732 | struct sk_buff *end = skb; | 2736 | continue; |
| 2733 | 2737 | ||
| 2734 | while (end->next) | 2738 | if (!head) |
| 2735 | end = end->next; | 2739 | head = skb; |
| 2736 | if (!head) | 2740 | else |
| 2737 | head = skb; | 2741 | tail->next = skb; |
| 2738 | else | 2742 | /* If skb was segmented, skb->prev points to |
| 2739 | tail->next = skb; | 2743 | * the last segment. If not, it still contains skb. |
| 2740 | tail = end; | 2744 | */ |
| 2741 | } | 2745 | tail = skb->prev; |
| 2742 | skb = next; | ||
| 2743 | } | 2746 | } |
| 2744 | return head; | 2747 | return head; |
| 2745 | } | 2748 | } |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9a423e2c5766..7b3df0d518ab 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -3083,6 +3083,11 @@ perform_csum_check: | |||
| 3083 | } | 3083 | } |
| 3084 | } while ((offset += len) < head_skb->len); | 3084 | } while ((offset += len) < head_skb->len); |
| 3085 | 3085 | ||
| 3086 | /* Some callers want to get the end of the list. | ||
| 3087 | * Put it in segs->prev to avoid walking the list. | ||
| 3088 | * (see validate_xmit_skb_list() for example) | ||
| 3089 | */ | ||
| 3090 | segs->prev = tail; | ||
| 3086 | return segs; | 3091 | return segs; |
| 3087 | 3092 | ||
| 3088 | err: | 3093 | err: |
