summaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
authorDeepa Dinamani <deepa.kernel@gmail.com>2018-01-07 17:44:42 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2018-01-09 16:40:30 -0800
commit152194fe9c3f03232b9c0d0264793a7fa4af82f8 (patch)
tree2c21b0ba04050b8a86562e55aec816f9ea029c4b /drivers/input/evdev.c
parenteca3be9b95ac7cf9442654a54962859d74f8e38a (diff)
downloadlinux-152194fe9c3f03232b9c0d0264793a7fa4af82f8.tar.bz2
Input: extend usable life of event timestamps to 2106 on 32 bit systems
The input events use struct timeval to store event time, unfortunately this structure is not y2038 safe and is being replaced in kernel with y2038 safe structures. Because of ABI concerns we can not change the size or the layout of structure input_event, so we opt to re-interpreting the 'seconds' part of timestamp as an unsigned value, effectively doubling the range of values, to year 2106. Newer glibc that has support for 32 bit applications to use 64 bit time_t supplies __USE_TIME_BITS64 define [1], that we can use to present the userspace with updated input_event layout. The updated layout will cause the compile time breakage, alerting applications and distributions maintainers to the issue. Existing 32 binaries will continue working without any changes until 2038. Ultimately userspace applications should switch to using monotonic or boot time clocks, as realtime clock is not very well suited for input event timestamps as it can go backwards (see a80b83b7b8 "Input: evdev - add CLOCK_BOOTTIME support" by by John Stultz). With monotonic clock the practical range of reported times will always fit into the pair of 32 bit values, as we do not expect any system to stay up for a hundred years without a single reboot. [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign Suggested-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com> Acked-by: Peter Hutterer <peter.hutterer@who-t.net> Patchwork-Id: 10148083 Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r--drivers/input/evdev.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 925571475005..116088fc3621 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -135,10 +135,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
continue;
} else if (head != i) {
/* move entry to fill the gap */
- client->buffer[head].time = ev->time;
- client->buffer[head].type = ev->type;
- client->buffer[head].code = ev->code;
- client->buffer[head].value = ev->value;
+ client->buffer[head] = *ev;
}
num++;
@@ -157,6 +154,7 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
{
struct input_event ev;
ktime_t time;
+ struct timespec64 ts;
time = client->clk_type == EV_CLK_REAL ?
ktime_get_real() :
@@ -164,7 +162,9 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
ktime_get() :
ktime_get_boottime();
- ev.time = ktime_to_timeval(time);
+ ts = ktime_to_timespec64(time);
+ ev.input_event_sec = ts.tv_sec;
+ ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
ev.type = EV_SYN;
ev.code = SYN_DROPPED;
ev.value = 0;
@@ -241,7 +241,10 @@ static void __pass_event(struct evdev_client *client,
*/
client->tail = (client->head - 2) & (client->bufsize - 1);
- client->buffer[client->tail].time = event->time;
+ client->buffer[client->tail].input_event_sec =
+ event->input_event_sec;
+ client->buffer[client->tail].input_event_usec =
+ event->input_event_usec;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;
@@ -262,12 +265,15 @@ static void evdev_pass_values(struct evdev_client *client,
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
+ struct timespec64 ts;
bool wakeup = false;
if (client->revoked)
return;
- event.time = ktime_to_timeval(ev_time[client->clk_type]);
+ ts = ktime_to_timespec64(ev_time[client->clk_type]);
+ event.input_event_sec = ts.tv_sec;
+ event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);