aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-08-06 05:45:04 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-07 19:52:34 -0400
commitc3bdeb5c7cc073ccf5ff9624642022a8613a956e (patch)
tree59dd31538e9da9d5adecbc9c96d7d8a1aa0aa50d /drivers/net/tun.c
parentb4bf07771faaf959b0a916d35b1b930c030e30a8 (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/tun.c')
-rw-r--r--drivers/net/tun.c80
1 files changed, 0 insertions, 80 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 18527ef0cc75..b1630479d4a1 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -961,86 +961,6 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,
961 return skb; 961 return skb;
962} 962}
963 963
964/* set skb frags from iovec, this can move to core network code for reuse */
965static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
966 int offset, size_t count)
967{
968 int len = iov_length(from, count) - offset;
969 int copy = skb_headlen(skb);
970 int size, offset1 = 0;
971 int i = 0;
972
973 /* Skip over from offset */
974 while (count && (offset >= from->iov_len)) {
975 offset -= from->iov_len;
976 ++from;
977 --count;
978 }
979
980 /* copy up to skb headlen */
981 while (count && (copy > 0)) {
982 size = min_t(unsigned int, copy, from->iov_len - offset);
983 if (copy_from_user(skb->data + offset1, from->iov_base + offset,
984 size))
985 return -EFAULT;
986 if (copy > size) {
987 ++from;
988 --count;
989 offset = 0;
990 } else
991 offset += size;
992 copy -= size;
993 offset1 += size;
994 }
995
996 if (len == offset1)
997 return 0;
998
999 while (count--) {
1000 struct page *page[MAX_SKB_FRAGS];
1001 int num_pages;
1002 unsigned long base;
1003 unsigned long truesize;
1004
1005 len = from->iov_len - offset;
1006 if (!len) {
1007 offset = 0;
1008 ++from;
1009 continue;
1010 }
1011 base = (unsigned long)from->iov_base + offset;
1012 size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT;
1013 if (i + size > MAX_SKB_FRAGS)
1014 return -EMSGSIZE;
1015 num_pages = get_user_pages_fast(base, size, 0, &page[i]);
1016 if (num_pages != size) {
1017 int j;
1018
1019 for (j = 0; j < num_pages; j++)
1020 put_page(page[i + j]);
1021 return -EFAULT;
1022 }
1023 truesize = size * PAGE_SIZE;
1024 skb->data_len += len;
1025 skb->len += len;
1026 skb->truesize += truesize;
1027 atomic_add(truesize, &skb->sk->sk_wmem_alloc);
1028 while (len) {
1029 int off = base & ~PAGE_MASK;
1030 int size = min_t(int, len, PAGE_SIZE - off);
1031 __skb_fill_page_desc(skb, i, page[i], off, size);
1032 skb_shinfo(skb)->nr_frags++;
1033 /* increase sk_wmem_alloc */
1034 base += size;
1035 len -= size;
1036 i++;
1037 }
1038 offset = 0;
1039 ++from;
1040 }
1041 return 0;
1042}
1043
1044/* Get packet from user space buffer */ 964/* Get packet from user space buffer */
1045static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, 965static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
1046 void *msg_control, const struct iovec *iv, 966 void *msg_control, const struct iovec *iv,