summaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-06-23 10:09:26 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-06-23 13:05:27 -0700
commite725a4945d6eedd400dd5d0ead293d980a2f76ec (patch)
treec484304f9b4298321d0aa82a6a119004fe290eea /drivers/input/evdev.c
parent6967b4d9de4a7cf3b00cd9a93981d3206d75a1d8 (diff)
downloadlinux-e725a4945d6eedd400dd5d0ead293d980a2f76ec.tar.gz
linux-e725a4945d6eedd400dd5d0ead293d980a2f76ec.tar.bz2
linux-e725a4945d6eedd400dd5d0ead293d980a2f76ec.zip
Input: evdev - never leave the client buffer empty after write
When the client buffer is very small and wraps around a lot, it may well be that a write increases the head such that head == tail. If this happens between the point where a poll is triggered and the actual data is being read, there will be no data to read. This is confusing to applications, which might end up closing the file. This patch solves the problem by making sure the client buffer is never empty after writing to it. Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r--drivers/input/evdev.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 30836c05edd7..cd323254ca6f 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -54,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
- * Interrupts are disabled, just acquire the lock
+ * Interrupts are disabled, just acquire the lock.
+ * Make sure we don't leave with the client buffer
+ * "empty" by having client->head == client->tail.
*/
spin_lock(&client->buffer_lock);
- client->buffer[client->head++] = *event;
- client->head &= client->bufsize - 1;
+ do {
+ client->buffer[client->head++] = *event;
+ client->head &= client->bufsize - 1;
+ } while (client->head == client->tail);
spin_unlock(&client->buffer_lock);
if (event->type == EV_SYN)