On a buffer overflow, the head and tail pointers collide.
This makes the buffer suddenly look empty, rather than
full, which may confuse applications.
This patch moves the tail pointer up one event on a buffer
overflow, which "consumes" the oldest event in the buffer
to make room for the incoming event. Thus, although data
is lost due to the overflow (which is unavoidable), the
data that remains is both recent and still time-ordered.
Signed-off-by: Bill Gatliff <redacted>
---
drivers/input/evdev.c | 18 +++++++++++-------
1 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index e3f7fc6..04a18ff 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -55,15 +55,19 @@ static void evdev_pass_event(struct evdev_client *client,
{
/*
* 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);
- do {
- client->buffer[client->head++] = *event;
- client->head &= client->bufsize - 1;
- } while (client->head == client->tail);
- spin_unlock(&client->buffer_lock);
+ client->buffer[client->head++] = *event;
+ client->head &= client->bufsize - 1;
+
+ /*
+ * If we overflow the buffer, consume the oldest
+ * event to make room for the one that just arrived
+ */
+ if (unlikely(client->head == client->tail)) {
+ client->tail++;
+ client->tail &= client->bufsize - 1;
+ }
if (event->type == EV_SYN)
kill_fasync(&client->fasync, SIGIO, POLL_IN);--
1.7.1