diff options
author | Jason Wang <jasowang@redhat.com> | 2013-08-06 05:45:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-07 19:52:34 -0400 |
commit | c3bdeb5c7cc073ccf5ff9624642022a8613a956e (patch) | |
tree | 59dd31538e9da9d5adecbc9c96d7d8a1aa0aa50d /drivers/net/macvtap.c | |
parent | b4bf07771faaf959b0a916d35b1b930c030e30a8 (diff) |
net: move zerocopy_sg_from_iovec() to net/core/datagram.c
To let it be reused and reduce code duplication. Also document this function.
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvtap.c')
-rw-r--r-- | drivers/net/macvtap.c | 80 |
1 files changed, 0 insertions, 80 deletions
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index dfec20df17ba..182364abfa35 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c | |||
@@ -536,86 +536,6 @@ static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad, | |||
536 | return skb; | 536 | return skb; |
537 | } | 537 | } |
538 | 538 | ||
539 | /* set skb frags from iovec, this can move to core network code for reuse */ | ||
540 | static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, | ||
541 | int offset, size_t count) | ||
542 | { | ||
543 | int len = iov_length(from, count) - offset; | ||
544 | int copy = skb_headlen(skb); | ||
545 | int size, offset1 = 0; | ||
546 | int i = 0; | ||
547 | |||
548 | /* Skip over from offset */ | ||
549 | while (count && (offset >= from->iov_len)) { | ||
550 | offset -= from->iov_len; | ||
551 | ++from; | ||
552 | --count; | ||
553 | } | ||
554 | |||
555 | /* copy up to skb headlen */ | ||
556 | while (count && (copy > 0)) { | ||
557 | size = min_t(unsigned int, copy, from->iov_len - offset); | ||
558 | if (copy_from_user(skb->data + offset1, from->iov_base + offset, | ||
559 | size)) | ||
560 | return -EFAULT; | ||
561 | if (copy > size) { | ||
562 | ++from; | ||
563 | --count; | ||
564 | offset = 0; | ||
565 | } else | ||
566 | offset += size; | ||
567 | copy -= size; | ||
568 | offset1 += size; | ||
569 | } | ||
570 | |||
571 | if (len == offset1) | ||
572 | return 0; | ||
573 | |||
574 | while (count--) { | ||
575 | struct page *page[MAX_SKB_FRAGS]; | ||
576 | int num_pages; | ||
577 | unsigned long base; | ||
578 | unsigned long truesize; | ||
579 | |||
580 | len = from->iov_len - offset; | ||
581 | if (!len) { | ||
582 | offset = 0; | ||
583 | ++from; | ||
584 | continue; | ||
585 | } | ||
586 | base = (unsigned long)from->iov_base + offset; | ||
587 | size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; | ||
588 | if (i + size > MAX_SKB_FRAGS) | ||
589 | return -EMSGSIZE; | ||
590 | num_pages = get_user_pages_fast(base, size, 0, &page[i]); | ||
591 | if (num_pages != size) { | ||
592 | int j; | ||
593 | |||
594 | for (j = 0; j < num_pages; j++) | ||
595 | put_page(page[i + j]); | ||
596 | return -EFAULT; | ||
597 | } | ||
598 | truesize = size * PAGE_SIZE; | ||
599 | skb->data_len += len; | ||
600 | skb->len += len; | ||
601 | skb->truesize += truesize; | ||
602 | atomic_add(truesize, &skb->sk->sk_wmem_alloc); | ||
603 | while (len) { | ||
604 | int off = base & ~PAGE_MASK; | ||
605 | int size = min_t(int, len, PAGE_SIZE - off); | ||
606 | __skb_fill_page_desc(skb, i, page[i], off, size); | ||
607 | skb_shinfo(skb)->nr_frags++; | ||
608 | /* increase sk_wmem_alloc */ | ||
609 | base += size; | ||
610 | len -= size; | ||
611 | i++; | ||
612 | } | ||
613 | offset = 0; | ||
614 | ++from; | ||
615 | } | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | /* | 539 | /* |
620 | * macvtap_skb_from_vnet_hdr and macvtap_skb_to_vnet_hdr should | 540 | * macvtap_skb_from_vnet_hdr and macvtap_skb_to_vnet_hdr should |
621 | * be shared with the tun/tap driver. | 541 | * be shared with the tun/tap driver. |