diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2009-04-19 21:26:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-21 08:42:46 -0400 |
commit | 6f26c9a7555e5bcca3560919db9b852015077dae (patch) | |
tree | 9ca7509cd0cbbdae158b752c234cb23add8370f0 /net/core | |
parent | 43b39dcdbdf823a1c0ac1f2aa2d76bd2f210adc8 (diff) |
tun: fix tun_chr_aio_write so that aio works
aio_write gets const struct iovec * but tun_chr_aio_write casts this to struct
iovec * and modifies the iovec. As a result, attempts to use io_submit
to send packets to a tun device fail with weird errors such as EINVAL.
Since tun is the only user of skb_copy_datagram_from_iovec, we can
fix this simply by changing the later so that it does not
touch the iovec passed to it.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/datagram.c | 20 | ||||
-rw-r--r-- | net/core/iovec.c | 7 |
2 files changed, 18 insertions, 9 deletions
diff --git a/net/core/datagram.c b/net/core/datagram.c index 4dbb05cd572b..914d5fa773b4 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -435,13 +435,15 @@ EXPORT_SYMBOL(skb_copy_datagram_const_iovec); | |||
435 | * @skb: buffer to copy | 435 | * @skb: buffer to copy |
436 | * @offset: offset in the buffer to start copying to | 436 | * @offset: offset in the buffer to start copying to |
437 | * @from: io vector to copy to | 437 | * @from: io vector to copy to |
438 | * @from_offset: offset in the io vector to start copying from | ||
438 | * @len: amount of data to copy to buffer from iovec | 439 | * @len: amount of data to copy to buffer from iovec |
439 | * | 440 | * |
440 | * Returns 0 or -EFAULT. | 441 | * Returns 0 or -EFAULT. |
441 | * Note: the iovec is modified during the copy. | 442 | * Note: the iovec is not modified during the copy. |
442 | */ | 443 | */ |
443 | int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, | 444 | int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, |
444 | struct iovec *from, int len) | 445 | const struct iovec *from, int from_offset, |
446 | int len) | ||
445 | { | 447 | { |
446 | int start = skb_headlen(skb); | 448 | int start = skb_headlen(skb); |
447 | int i, copy = start - offset; | 449 | int i, copy = start - offset; |
@@ -450,11 +452,12 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, | |||
450 | if (copy > 0) { | 452 | if (copy > 0) { |
451 | if (copy > len) | 453 | if (copy > len) |
452 | copy = len; | 454 | copy = len; |
453 | if (memcpy_fromiovec(skb->data + offset, from, copy)) | 455 | if (memcpy_fromiovecend(skb->data + offset, from, 0, copy)) |
454 | goto fault; | 456 | goto fault; |
455 | if ((len -= copy) == 0) | 457 | if ((len -= copy) == 0) |
456 | return 0; | 458 | return 0; |
457 | offset += copy; | 459 | offset += copy; |
460 | from_offset += copy; | ||
458 | } | 461 | } |
459 | 462 | ||
460 | /* Copy paged appendix. Hmm... why does this look so complicated? */ | 463 | /* Copy paged appendix. Hmm... why does this look so complicated? */ |
@@ -473,8 +476,9 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, | |||
473 | if (copy > len) | 476 | if (copy > len) |
474 | copy = len; | 477 | copy = len; |
475 | vaddr = kmap(page); | 478 | vaddr = kmap(page); |
476 | err = memcpy_fromiovec(vaddr + frag->page_offset + | 479 | err = memcpy_fromiovecend(vaddr + frag->page_offset + |
477 | offset - start, from, copy); | 480 | offset - start, |
481 | from, from_offset, copy); | ||
478 | kunmap(page); | 482 | kunmap(page); |
479 | if (err) | 483 | if (err) |
480 | goto fault; | 484 | goto fault; |
@@ -482,6 +486,7 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, | |||
482 | if (!(len -= copy)) | 486 | if (!(len -= copy)) |
483 | return 0; | 487 | return 0; |
484 | offset += copy; | 488 | offset += copy; |
489 | from_offset += copy; | ||
485 | } | 490 | } |
486 | start = end; | 491 | start = end; |
487 | } | 492 | } |
@@ -500,11 +505,14 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset, | |||
500 | copy = len; | 505 | copy = len; |
501 | if (skb_copy_datagram_from_iovec(list, | 506 | if (skb_copy_datagram_from_iovec(list, |
502 | offset - start, | 507 | offset - start, |
503 | from, copy)) | 508 | from, |
509 | from_offset, | ||
510 | copy)) | ||
504 | goto fault; | 511 | goto fault; |
505 | if ((len -= copy) == 0) | 512 | if ((len -= copy) == 0) |
506 | return 0; | 513 | return 0; |
507 | offset += copy; | 514 | offset += copy; |
515 | from_offset += copy; | ||
508 | } | 516 | } |
509 | start = end; | 517 | start = end; |
510 | } | 518 | } |
diff --git a/net/core/iovec.c b/net/core/iovec.c index a215545c0a34..40a76ce19d9f 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c | |||
@@ -147,10 +147,11 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) | |||
147 | } | 147 | } |
148 | 148 | ||
149 | /* | 149 | /* |
150 | * For use with ip_build_xmit | 150 | * Copy iovec from kernel. Returns -EFAULT on error. |
151 | */ | 151 | */ |
152 | int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, | 152 | |
153 | int len) | 153 | int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, |
154 | int offset, int len) | ||
154 | { | 155 | { |
155 | /* Skip over the finished iovecs */ | 156 | /* Skip over the finished iovecs */ |
156 | while (offset >= iov->iov_len) { | 157 | while (offset >= iov->iov_len) { |