static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; while (count) { skb = skb_dequeue(&data->readq); if (skb) { ret = vhci_put_user(data, skb, buf, count); if (ret < 0) skb_queue_head(&data->readq, skb); else kfree_skb(skb); break; } if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } ret = wait_event_interruptible(data->read_wait, !skb_queue_empty(&data->readq)); if (ret < 0) break; } return ret; }
static ssize_t vhci_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { DECLARE_WAITQUEUE(wait, current); struct vhci_data *data = file->private_data; struct sk_buff *skb; ssize_t ret = 0; add_wait_queue(&data->read_wait, &wait); while (count) { set_current_state(TASK_INTERRUPTIBLE); skb = skb_dequeue(&data->readq); if (!skb) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -ERESTARTSYS; break; } schedule(); continue; } if (access_ok(VERIFY_WRITE, buf, count)) ret = vhci_put_user(data, skb, buf, count); else ret = -EFAULT; kfree_skb(skb); break; } set_current_state(TASK_RUNNING); remove_wait_queue(&data->read_wait, &wait); return ret; }