tun: Use iovec iterators
authorHerbert Xu <herbert@gondor.apana.org.au>
Fri, 7 Nov 2014 13:22:23 +0000 (21:22 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Nov 2014 17:13:34 +0000 (12:13 -0500)
This patch removes the use of skb_copy_datagram_const_iovec in
favour of the iovec iterator-based skb_copy_datagram_iter.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tun.c

index 9dd3746..2ff769b 100644 (file)
@@ -71,6 +71,7 @@
 #include <net/rtnetlink.h>
 #include <net/sock.h>
 #include <linux/seq_file.h>
+#include <linux/uio.h>
 
 #include <asm/uaccess.h>
 
@@ -1230,11 +1231,11 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 static ssize_t tun_put_user(struct tun_struct *tun,
                            struct tun_file *tfile,
                            struct sk_buff *skb,
-                           const struct iovec *iv, int len)
+                           struct iov_iter *iter)
 {
        struct tun_pi pi = { 0, skb->protocol };
-       ssize_t total = 0;
-       int vlan_offset = 0, copied;
+       ssize_t total;
+       int vlan_offset;
        int vlan_hlen = 0;
        int vnet_hdr_sz = 0;
 
@@ -1244,23 +1245,25 @@ static ssize_t tun_put_user(struct tun_struct *tun,
        if (tun->flags & TUN_VNET_HDR)
                vnet_hdr_sz = tun->vnet_hdr_sz;
 
+       total = skb->len + vlan_hlen + vnet_hdr_sz;
+
        if (!(tun->flags & TUN_NO_PI)) {
-               if ((len -= sizeof(pi)) < 0)
+               if (iov_iter_count(iter) < sizeof(pi))
                        return -EINVAL;
 
-               if (len < skb->len + vlan_hlen + vnet_hdr_sz) {
+               total += sizeof(pi);
+               if (iov_iter_count(iter) < total) {
                        /* Packet will be striped */
                        pi.flags |= TUN_PKT_STRIP;
                }
 
-               if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi)))
+               if (copy_to_iter(&pi, sizeof(pi), iter) != sizeof(pi))
                        return -EFAULT;
-               total += sizeof(pi);
        }
 
        if (vnet_hdr_sz) {
                struct virtio_net_hdr gso = { 0 }; /* no info leak */
-               if ((len -= vnet_hdr_sz) < 0)
+               if (iov_iter_count(iter) < vnet_hdr_sz)
                        return -EINVAL;
 
                if (skb_is_gso(skb)) {
@@ -1299,17 +1302,12 @@ static ssize_t tun_put_user(struct tun_struct *tun,
                        gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
                } /* else everything is zero */
 
-               if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
-                                              sizeof(gso))))
+               if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
                        return -EFAULT;
-               total += vnet_hdr_sz;
        }
 
-       copied = total;
-       len = min_t(int, skb->len + vlan_hlen, len);
-       total += skb->len + vlan_hlen;
        if (vlan_hlen) {
-               int copy, ret;
+               int ret;
                struct {
                        __be16 h_vlan_proto;
                        __be16 h_vlan_TCI;
@@ -1320,36 +1318,32 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 
                vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
 
-               copy = min_t(int, vlan_offset, len);
-               ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
-               len -= copy;
-               copied += copy;
-               if (ret || !len)
+               ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
+               if (ret || !iov_iter_count(iter))
                        goto done;
 
-               copy = min_t(int, sizeof(veth), len);
-               ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy);
-               len -= copy;
-               copied += copy;
-               if (ret || !len)
+               ret = copy_to_iter(&veth, sizeof(veth), iter);
+               if (ret != sizeof(veth) || !iov_iter_count(iter))
                        goto done;
        }
 
-       skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
+       skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
 
 done:
        tun->dev->stats.tx_packets++;
-       tun->dev->stats.tx_bytes += len;
+       tun->dev->stats.tx_bytes += skb->len + vlan_hlen;
 
        return total;
 }
 
 static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
-                          const struct iovec *iv, ssize_t len, int noblock)
+                          const struct iovec *iv, unsigned long segs,
+                          ssize_t len, int noblock)
 {
        struct sk_buff *skb;
        ssize_t ret = 0;
        int peeked, err, off = 0;
+       struct iov_iter iter;
 
        tun_debug(KERN_INFO, tun, "tun_do_read\n");
 
@@ -1362,11 +1356,12 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
        /* Read frames from queue */
        skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
                                  &peeked, &off, &err);
-       if (skb) {
-               ret = tun_put_user(tun, tfile, skb, iv, len);
-               kfree_skb(skb);
-       } else
-               ret = err;
+       if (!skb)
+               return ret;
+
+       iov_iter_init(&iter, READ, iv, segs, len);
+       ret = tun_put_user(tun, tfile, skb, &iter);
+       kfree_skb(skb);
 
        return ret;
 }
@@ -1387,7 +1382,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
                goto out;
        }
 
-       ret = tun_do_read(tun, tfile, iv, len,
+       ret = tun_do_read(tun, tfile, iv, count, len,
                          file->f_flags & O_NONBLOCK);
        ret = min_t(ssize_t, ret, len);
        if (ret > 0)
@@ -1488,7 +1483,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
                                         SOL_PACKET, TUN_TX_TIMESTAMP);
                goto out;
        }
-       ret = tun_do_read(tun, tfile, m->msg_iov, total_len,
+       ret = tun_do_read(tun, tfile, m->msg_iov, m->msg_iovlen, total_len,
                          flags & MSG_DONTWAIT);
        if (ret > total_len) {
                m->msg_flags |= MSG_TRUNC;