Input: serio_raw - ensure we don't block in non-blocking read
Avoid calling wait_event_interruptible() if client requested non-blocking read, since it is not guaranteed that another thread will not consume event after we checked if serio_raw->head != serio_raw->tail. Also ensure we do not return 0 but keep waiting instead in blocking case, when another thread steals "our" byte. Reviewed-by: David Herrmann <dh.herrmann@googlemail.com> Reviewed-by: Che-Liang Chiou <clchiou@chromium.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
@@ -165,31 +165,38 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
|
|||||||
struct serio_raw *serio_raw = client->serio_raw;
|
struct serio_raw *serio_raw = client->serio_raw;
|
||||||
char uninitialized_var(c);
|
char uninitialized_var(c);
|
||||||
ssize_t read = 0;
|
ssize_t read = 0;
|
||||||
int retval;
|
int error = 0;
|
||||||
|
|
||||||
if (serio_raw->dead)
|
do {
|
||||||
return -ENODEV;
|
if (serio_raw->dead)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
|
if (serio_raw->head == serio_raw->tail &&
|
||||||
return -EAGAIN;
|
(file->f_flags & O_NONBLOCK))
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
retval = wait_event_interruptible(serio_raw->wait,
|
if (count == 0)
|
||||||
serio_raw->head != serio_raw->tail || serio_raw->dead);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (serio_raw->dead)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
|
|
||||||
if (put_user(c, buffer++)) {
|
|
||||||
retval = -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
read++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read ?: retval;
|
while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
|
||||||
|
if (put_user(c, buffer++)) {
|
||||||
|
error = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(file->f_flags & O_NONBLOCK))
|
||||||
|
error = wait_event_interruptible(serio_raw->wait,
|
||||||
|
serio_raw->head != serio_raw->tail ||
|
||||||
|
serio_raw->dead);
|
||||||
|
} while (!error);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return read ?: error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
|
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
|
||||||
|
Reference in New Issue
Block a user