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:
Родитель
71f3d070a3
Коммит
486c8aba39
|
@ -165,31 +165,38 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
|
|||
struct serio_raw *serio_raw = client->serio_raw;
|
||||
char uninitialized_var(c);
|
||||
ssize_t read = 0;
|
||||
int retval;
|
||||
int error = 0;
|
||||
|
||||
if (serio_raw->dead)
|
||||
return -ENODEV;
|
||||
do {
|
||||
if (serio_raw->dead)
|
||||
return -ENODEV;
|
||||
|
||||
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
if (serio_raw->head == serio_raw->tail &&
|
||||
(file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(serio_raw->wait,
|
||||
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;
|
||||
if (count == 0)
|
||||
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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче