aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2009-04-19 21:25:59 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-21 08:42:45 -0400
commit43b39dcdbdf823a1c0ac1f2aa2d76bd2f210adc8 (patch)
tree117c9b756380b59c8c29955f02c4d9ff504b047a /drivers/net/tun.c
parent0a1ec07a67bd8b0033dace237249654d015efa21 (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.c11
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 */
684static __inline__ ssize_t tun_put_user(struct tun_struct *tun, 684static __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 }