diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2009-04-19 21:25:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-21 08:42:45 -0400 |
commit | 43b39dcdbdf823a1c0ac1f2aa2d76bd2f210adc8 (patch) | |
tree | 117c9b756380b59c8c29955f02c4d9ff504b047a /drivers/net/tun.c | |
parent | 0a1ec07a67bd8b0033dace237249654d015efa21 (diff) |
tun: fix tun_chr_aio_read so that aio works
aio_read gets const struct iovec * but tun_chr_aio_read casts this to struct
iovec * and modifies the iovec. As a result, attempts to use io_submit
to get packets from a tun device fail with weird errors such as EINVAL.
Fix by using the new skb_copy_datagram_const_iovec.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 735bf41c654a..3b513e29d392 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -683,7 +683,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, | |||
683 | /* Put packet to the user space buffer */ | 683 | /* Put packet to the user space buffer */ |
684 | static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | 684 | static __inline__ ssize_t tun_put_user(struct tun_struct *tun, |
685 | struct sk_buff *skb, | 685 | struct sk_buff *skb, |
686 | struct iovec *iv, int len) | 686 | const struct iovec *iv, int len) |
687 | { | 687 | { |
688 | struct tun_pi pi = { 0, skb->protocol }; | 688 | struct tun_pi pi = { 0, skb->protocol }; |
689 | ssize_t total = 0; | 689 | ssize_t total = 0; |
@@ -697,7 +697,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
697 | pi.flags |= TUN_PKT_STRIP; | 697 | pi.flags |= TUN_PKT_STRIP; |
698 | } | 698 | } |
699 | 699 | ||
700 | if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi))) | 700 | if (memcpy_toiovecend(iv, (void *) &pi, 0, sizeof(pi))) |
701 | return -EFAULT; | 701 | return -EFAULT; |
702 | total += sizeof(pi); | 702 | total += sizeof(pi); |
703 | } | 703 | } |
@@ -730,14 +730,15 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, | |||
730 | gso.csum_offset = skb->csum_offset; | 730 | gso.csum_offset = skb->csum_offset; |
731 | } /* else everything is zero */ | 731 | } /* else everything is zero */ |
732 | 732 | ||
733 | if (unlikely(memcpy_toiovec(iv, (void *)&gso, sizeof(gso)))) | 733 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
734 | sizeof(gso)))) | ||
734 | return -EFAULT; | 735 | return -EFAULT; |
735 | total += sizeof(gso); | 736 | total += sizeof(gso); |
736 | } | 737 | } |
737 | 738 | ||
738 | len = min_t(int, skb->len, len); | 739 | len = min_t(int, skb->len, len); |
739 | 740 | ||
740 | skb_copy_datagram_iovec(skb, 0, iv, len); | 741 | skb_copy_datagram_const_iovec(skb, 0, iv, total, len); |
741 | total += len; | 742 | total += len; |
742 | 743 | ||
743 | tun->dev->stats.tx_packets++; | 744 | tun->dev->stats.tx_packets++; |
@@ -792,7 +793,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
792 | } | 793 | } |
793 | netif_wake_queue(tun->dev); | 794 | netif_wake_queue(tun->dev); |
794 | 795 | ||
795 | ret = tun_put_user(tun, skb, (struct iovec *) iv, len); | 796 | ret = tun_put_user(tun, skb, iv, len); |
796 | kfree_skb(skb); | 797 | kfree_skb(skb); |
797 | break; | 798 | break; |
798 | } | 799 | } |