/* Readv */ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, unsigned long count, loff_t *pos) { struct tun_struct *tun = (struct tun_struct *)file->private_data; DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; unsigned long i; if (!tun) return -EBADFD; DBG(KERN_INFO "%s: tun_chr_read\n", tun->name); for (i = 0, len = 0; i < count; i++) { if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len)) return -EFAULT; len += iv[i].iov_len; } add_wait_queue(&tun->read_wait, &wait); while (len) { current->state = TASK_INTERRUPTIBLE; /* Read frames from the queue */ if (!(skb=skb_dequeue(&tun->readq))) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } /* Nothing to read, let's sleep */ schedule(); continue; } netif_start_queue(&tun->dev); ret = tun_put_user(tun, skb, (struct iovec *) iv, len); kfree_skb(skb); break; } current->state = TASK_RUNNING; remove_wait_queue(&tun->read_wait, &wait); return ret; }
/* Read */ static ssize_t tun_chr_read(struct file * file, char * buf, size_t count, loff_t *pos) { struct tun_struct *tun = (struct tun_struct *)file->private_data; DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t ret = 0; DBG(KERN_INFO "%s: tun_chr_read\n", tun->name); add_wait_queue(&tun->read_wait, &wait); while (count) { current->state = TASK_INTERRUPTIBLE; /* Read frames from device queue */ if (!(skb=skb_dequeue(&tun->txq))) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } /* Nothing to read, let's sleep */ schedule(); continue; } netif_start_queue(&tun->dev); if (!verify_area(VERIFY_WRITE, buf, count)) ret = tun_put_user(tun, skb, buf, count); else ret = -EFAULT; kfree_skb(skb); break; } current->state = TASK_RUNNING; remove_wait_queue(&tun->read_wait, &wait); return ret; }