aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2014-11-07 08:22:23 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-07 12:13:34 -0500
commite0b46d0ee9c240c7430a47e9b0365674d4a04522 (patch)
tree383f614a420a3b5b843ee6147e39d3449e6d06e1 /drivers/net/tun.c
parenta8f820aa4066d2c97e75ecd1bbca8a7920b66f2c (diff)
tun: Use iovec iterators
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>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c65
1 files changed, 30 insertions, 35 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9dd3746994a4..2ff769bf3f35 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -71,6 +71,7 @@
71#include <net/rtnetlink.h> 71#include <net/rtnetlink.h>
72#include <net/sock.h> 72#include <net/sock.h>
73#include <linux/seq_file.h> 73#include <linux/seq_file.h>
74#include <linux/uio.h>
74 75
75#include <asm/uaccess.h> 76#include <asm/uaccess.h>
76 77
@@ -1230,11 +1231,11 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
1230static ssize_t tun_put_user(struct tun_struct *tun, 1231static ssize_t tun_put_user(struct tun_struct *tun,
1231 struct tun_file *tfile, 1232 struct tun_file *tfile,
1232 struct sk_buff *skb, 1233 struct sk_buff *skb,
1233 const struct iovec *iv, int len) 1234 struct iov_iter *iter)
1234{ 1235{
1235 struct tun_pi pi = { 0, skb->protocol }; 1236 struct tun_pi pi = { 0, skb->protocol };
1236 ssize_t total = 0; 1237 ssize_t total;
1237 int vlan_offset = 0, copied; 1238 int vlan_offset;
1238 int vlan_hlen = 0; 1239 int vlan_hlen = 0;
1239 int vnet_hdr_sz = 0; 1240 int vnet_hdr_sz = 0;
1240 1241
@@ -1244,23 +1245,25 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1244 if (tun->flags & TUN_VNET_HDR) 1245 if (tun->flags & TUN_VNET_HDR)
1245 vnet_hdr_sz = tun->vnet_hdr_sz; 1246 vnet_hdr_sz = tun->vnet_hdr_sz;
1246 1247
1248 total = skb->len + vlan_hlen + vnet_hdr_sz;
1249
1247 if (!(tun->flags & TUN_NO_PI)) { 1250 if (!(tun->flags & TUN_NO_PI)) {
1248 if ((len -= sizeof(pi)) < 0) 1251 if (iov_iter_count(iter) < sizeof(pi))
1249 return -EINVAL; 1252 return -EINVAL;
1250 1253
1251 if (len < skb->len + vlan_hlen + vnet_hdr_sz) { 1254 total += sizeof(pi);
1255 if (iov_iter_count(iter) < total) {
1252 /* Packet will be striped */ 1256 /* Packet will be striped */
1253 pi.flags |= TUN_PKT_STRIP; 1257 pi.flags |= TUN_PKT_STRIP;
1254 } 1258 }
1255 1259
1256 if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi))) 1260 if (copy_to_iter(&pi, sizeof(pi), iter) != sizeof(pi))
1257 return -EFAULT; 1261 return -EFAULT;
1258 total += sizeof(pi);
1259 } 1262 }
1260 1263
1261 if (vnet_hdr_sz) { 1264 if (vnet_hdr_sz) {
1262 struct virtio_net_hdr gso = { 0 }; /* no info leak */ 1265 struct virtio_net_hdr gso = { 0 }; /* no info leak */
1263 if ((len -= vnet_hdr_sz) < 0) 1266 if (iov_iter_count(iter) < vnet_hdr_sz)
1264 return -EINVAL; 1267 return -EINVAL;
1265 1268
1266 if (skb_is_gso(skb)) { 1269 if (skb_is_gso(skb)) {
@@ -1299,17 +1302,12 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1299 gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; 1302 gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
1300 } /* else everything is zero */ 1303 } /* else everything is zero */
1301 1304
1302 if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, 1305 if (copy_to_iter(&gso, sizeof(gso), iter) != sizeof(gso))
1303 sizeof(gso))))
1304 return -EFAULT; 1306 return -EFAULT;
1305 total += vnet_hdr_sz;
1306 } 1307 }
1307 1308
1308 copied = total;
1309 len = min_t(int, skb->len + vlan_hlen, len);
1310 total += skb->len + vlan_hlen;
1311 if (vlan_hlen) { 1309 if (vlan_hlen) {
1312 int copy, ret; 1310 int ret;
1313 struct { 1311 struct {
1314 __be16 h_vlan_proto; 1312 __be16 h_vlan_proto;
1315 __be16 h_vlan_TCI; 1313 __be16 h_vlan_TCI;
@@ -1320,36 +1318,32 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1320 1318
1321 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); 1319 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
1322 1320
1323 copy = min_t(int, vlan_offset, len); 1321 ret = skb_copy_datagram_iter(skb, 0, iter, vlan_offset);
1324 ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); 1322 if (ret || !iov_iter_count(iter))
1325 len -= copy;
1326 copied += copy;
1327 if (ret || !len)
1328 goto done; 1323 goto done;
1329 1324
1330 copy = min_t(int, sizeof(veth), len); 1325 ret = copy_to_iter(&veth, sizeof(veth), iter);
1331 ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); 1326 if (ret != sizeof(veth) || !iov_iter_count(iter))
1332 len -= copy;
1333 copied += copy;
1334 if (ret || !len)
1335 goto done; 1327 goto done;
1336 } 1328 }
1337 1329
1338 skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); 1330 skb_copy_datagram_iter(skb, vlan_offset, iter, skb->len - vlan_offset);
1339 1331
1340done: 1332done:
1341 tun->dev->stats.tx_packets++; 1333 tun->dev->stats.tx_packets++;
1342 tun->dev->stats.tx_bytes += len; 1334 tun->dev->stats.tx_bytes += skb->len + vlan_hlen;
1343 1335
1344 return total; 1336 return total;
1345} 1337}
1346 1338
1347static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, 1339static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
1348 const struct iovec *iv, ssize_t len, int noblock) 1340 const struct iovec *iv, unsigned long segs,
1341 ssize_t len, int noblock)
1349{ 1342{
1350 struct sk_buff *skb; 1343 struct sk_buff *skb;
1351 ssize_t ret = 0; 1344 ssize_t ret = 0;
1352 int peeked, err, off = 0; 1345 int peeked, err, off = 0;
1346 struct iov_iter iter;
1353 1347
1354 tun_debug(KERN_INFO, tun, "tun_do_read\n"); 1348 tun_debug(KERN_INFO, tun, "tun_do_read\n");
1355 1349
@@ -1362,11 +1356,12 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
1362 /* Read frames from queue */ 1356 /* Read frames from queue */
1363 skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0, 1357 skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
1364 &peeked, &off, &err); 1358 &peeked, &off, &err);
1365 if (skb) { 1359 if (!skb)
1366 ret = tun_put_user(tun, tfile, skb, iv, len); 1360 return ret;
1367 kfree_skb(skb); 1361
1368 } else 1362 iov_iter_init(&iter, READ, iv, segs, len);
1369 ret = err; 1363 ret = tun_put_user(tun, tfile, skb, &iter);
1364 kfree_skb(skb);
1370 1365
1371 return ret; 1366 return ret;
1372} 1367}
@@ -1387,7 +1382,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
1387 goto out; 1382 goto out;
1388 } 1383 }
1389 1384
1390 ret = tun_do_read(tun, tfile, iv, len, 1385 ret = tun_do_read(tun, tfile, iv, count, len,
1391 file->f_flags & O_NONBLOCK); 1386 file->f_flags & O_NONBLOCK);
1392 ret = min_t(ssize_t, ret, len); 1387 ret = min_t(ssize_t, ret, len);
1393 if (ret > 0) 1388 if (ret > 0)
@@ -1488,7 +1483,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
1488 SOL_PACKET, TUN_TX_TIMESTAMP); 1483 SOL_PACKET, TUN_TX_TIMESTAMP);
1489 goto out; 1484 goto out;
1490 } 1485 }
1491 ret = tun_do_read(tun, tfile, m->msg_iov, total_len, 1486 ret = tun_do_read(tun, tfile, m->msg_iov, m->msg_iovlen, total_len,
1492 flags & MSG_DONTWAIT); 1487 flags & MSG_DONTWAIT);
1493 if (ret > total_len) { 1488 if (ret > total_len) {
1494 m->msg_flags |= MSG_TRUNC; 1489 m->msg_flags |= MSG_TRUNC;