diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2019-01-08 22:55:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-01-18 13:47:55 +0100 |
commit | 1bf931ab94a963851aa1dfba5d9f03f9f1ad8637 (patch) | |
tree | adb2ec439b9266b37ba687da41094438ab19d348 /drivers/tty/vt/vc_screen.c | |
parent | 8a085494317cab6fef25b34521dae03c83f31eaa (diff) |
vcs: poll(): cope with a deallocated vt
When VT_DISALLOCATE is used on a vt, user space waiting with poll() on
the corresponding /dev/vcs device is not awakened. This is now fixed by
returning POLLHUP|POLLERR to user space.
Also, in the normal screen update case, we don't set POLLERR anymore as
POLLPRI alone is a much more logical response in a non-error situation,
saving some confusion on the user space side. The only known user app
making use of poll() on /dev/vcs* is BRLTTY which is known to cope with
that change already, so the risk of breakage is pretty much nonexistent.
Signed-off-by: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/vt/vc_screen.c')
-rw-r--r-- | drivers/tty/vt/vc_screen.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 3dba60825c08..1bbe2a30cdbe 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -80,7 +80,7 @@ struct vcs_poll_data { struct notifier_block notifier; unsigned int cons_num; - bool seen_last_update; + int event; wait_queue_head_t waitq; struct fasync_struct *fasync; }; @@ -94,7 +94,7 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) container_of(nb, struct vcs_poll_data, notifier); int currcons = poll->cons_num; - if (code != VT_UPDATE) + if (code != VT_UPDATE && code != VT_DEALLOCATE) return NOTIFY_DONE; if (currcons == 0) @@ -104,7 +104,7 @@ vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) if (currcons != vc->vc_num) return NOTIFY_DONE; - poll->seen_last_update = false; + poll->event = code; wake_up_interruptible(&poll->waitq); kill_fasync(&poll->fasync, SIGIO, POLL_IN); return NOTIFY_OK; @@ -261,7 +261,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) poll = file->private_data; if (count && poll) - poll->seen_last_update = true; + poll->event = 0; read = 0; ret = 0; while (count) { @@ -616,12 +616,21 @@ static __poll_t vcs_poll(struct file *file, poll_table *wait) { struct vcs_poll_data *poll = vcs_poll_data_get(file); - __poll_t ret = DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI; + __poll_t ret = DEFAULT_POLLMASK|EPOLLERR; if (poll) { poll_wait(file, &poll->waitq, wait); - if (poll->seen_last_update) + switch (poll->event) { + case VT_UPDATE: + ret = DEFAULT_POLLMASK|EPOLLPRI; + break; + case VT_DEALLOCATE: + ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR; + break; + case 0: ret = DEFAULT_POLLMASK; + break; + } } return ret; } |