diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2014-11-07 08:22:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-07 12:13:34 -0500 |
commit | e0b46d0ee9c240c7430a47e9b0365674d4a04522 (patch) | |
tree | 383f614a420a3b5b843ee6147e39d3449e6d06e1 /drivers/net/tun.c | |
parent | a8f820aa4066d2c97e75ecd1bbca8a7920b66f2c (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.c | 65 |
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, | |||
1230 | static ssize_t tun_put_user(struct tun_struct *tun, | 1231 | static 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 | ||
1340 | done: | 1332 | done: |
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 | ||
1347 | static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, | 1339 | static 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; |