Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / net / tun.c
index 5235f48..9a6b382 100644 (file)
@@ -572,9 +572,9 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 
 /* prepad is the amount to reserve at front.  len is length after that.
  * linear is a hint as to how much to copy (usually headers). */
-static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
-                                           size_t prepad, size_t len,
-                                           size_t linear, int noblock)
+static struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
+                                    size_t prepad, size_t len,
+                                    size_t linear, int noblock)
 {
        struct sock *sk = tun->socket.sk;
        struct sk_buff *skb;
@@ -600,13 +600,13 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
 }
 
 /* Get packet from user space buffer */
-static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
-                                      const struct iovec *iv, size_t count,
-                                      int noblock)
+static ssize_t tun_get_user(struct tun_struct *tun,
+                           const struct iovec *iv, size_t count,
+                           int noblock)
 {
        struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
        struct sk_buff *skb;
-       size_t len = count, align = 0;
+       size_t len = count, align = NET_SKB_PAD;
        struct virtio_net_hdr gso = { 0 };
        int offset = 0;
 
@@ -636,7 +636,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        }
 
        if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
-               align = NET_IP_ALIGN;
+               align += NET_IP_ALIGN;
                if (unlikely(len < ETH_HLEN ||
                             (gso.hdr_len && gso.hdr_len < ETH_HLEN)))
                        return -EINVAL;
@@ -688,7 +688,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        case TUN_TAP_DEV:
                skb->protocol = eth_type_trans(skb, tun->dev);
                break;
-       };
+       }
 
        if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                pr_debug("GSO!\n");
@@ -751,9 +751,9 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 }
 
 /* Put packet to the user space buffer */
-static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
-                                      struct sk_buff *skb,
-                                      const struct iovec *iv, int len)
+static ssize_t tun_put_user(struct tun_struct *tun,
+                           struct sk_buff *skb,
+                           const struct iovec *iv, int len)
 {
        struct tun_pi pi = { 0, skb->protocol };
        ssize_t total = 0;
@@ -810,6 +810,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
                        gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
                        gso.csum_start = skb_checksum_start_offset(skb);
                        gso.csum_offset = skb->csum_offset;
+               } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+                       gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
                } /* else everything is zero */
 
                if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
@@ -839,7 +841,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,
 
        tun_debug(KERN_INFO, tun, "tun_chr_read\n");
 
-       add_wait_queue(&tun->wq.wait, &wait);
+       if (unlikely(!noblock))
+               add_wait_queue(&tun->wq.wait, &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
@@ -870,7 +873,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(&tun->wq.wait, &wait);
+       if (unlikely(!noblock))
+               remove_wait_queue(&tun->wq.wait, &wait);
 
        return ret;
 }