Consider two threads calling read() on the same uinput-fd, both non-blocking. Assume there is data-available so both will simultaneously pass: udev->head == udev->tail Then the first thread goes to sleep and the second one pops the message from the queue. Now assume udev->head == udev->tail. If the first thread wakes up it will call wait_event_*() and sleep in the waitq. This effectively turns the non-blocking FD into a blocking one. We fix this by never calling wait_event_*() for non-blocking FDs hence we will never sleep in the waitq here. Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxxxxxxx> Acked-by: Aristeu Rozanski <aris@xxxxxxxxx> --- drivers/input/misc/uinput.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 7360568..1526814 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -460,13 +460,15 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, if (udev->state != UIST_CREATED) return -ENODEV; - if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - - retval = wait_event_interruptible(udev->waitq, + if (file->f_flags & O_NONBLOCK) { + if (udev->head == udev->tail) + return -EAGAIN; + } else { + retval = wait_event_interruptible(udev->waitq, udev->head != udev->tail || udev->state != UIST_CREATED); - if (retval) - return retval; + if (retval) + return retval; + } retval = mutex_lock_interruptible(&udev->mutex); if (retval) -- 1.7.9.4 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html