diff mbox

[v3,1/4] uinput: Add ioctl for using monotonic/ boot times

Message ID 20171204005545.23325-2-deepa.kernel@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Deepa Dinamani Dec. 4, 2017, 12:55 a.m. UTC
struct timeval which is part of struct input_event to
maintain the event times is not y2038 safe.

Real time timestamps are also not ideal for input_event
as this time can go backwards as noted in the patch
a80b83b7b8 by John Stultz.

Arnd Bergmann suggested deprecating real time and using
monotonic or other timers for all input_event times as a
solution to both the above problems.

Add a new ioctl to let the user dictate the kind of time
to be used for input events. This is similar to the evdev
implementation of the feature. Realtime is still the
default time. This is to maintain backward compatibility.

The structure to maintain input events will be changed
in a different patch.

Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
---
 drivers/input/misc/uinput.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-
 include/uapi/linux/uinput.h |  3 +++
 2 files changed, 59 insertions(+), 1 deletion(-)

Comments

Arnd Bergmann Dec. 4, 2017, 2:21 p.m. UTC | #1
On Mon, Dec 4, 2017 at 1:55 AM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
> struct timeval which is part of struct input_event to
> maintain the event times is not y2038 safe.
>
> Real time timestamps are also not ideal for input_event
> as this time can go backwards as noted in the patch
> a80b83b7b8 by John Stultz.
>
> Arnd Bergmann suggested deprecating real time and using
> monotonic or other timers for all input_event times as a
> solution to both the above problems.
>
> Add a new ioctl to let the user dictate the kind of time
> to be used for input events. This is similar to the evdev
> implementation of the feature. Realtime is still the
> default time. This is to maintain backward compatibility.
>
> The structure to maintain input events will be changed
> in a different patch.

Based on Peter's comment from when you first posted this,
https://patchwork.kernel.org/patch/9381209/, I tried to follow
the code path again, to see if we can come up with a way
to avoid introducing a new ioctl.

There is one idea I had now: The two events we
get (upload and erase) are both triggered from evdev,
which gets called from user space through the EVIOCSFF
and EVIOCRMFF ioctls. This device already sets the
clock domain. Would it make sense to send the event
to the uinput owner using the same clock domain that
was set by the evdev owner, or are these two separate
by definition?

       Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepa Dinamani Dec. 4, 2017, 8:36 p.m. UTC | #2
On Mon, Dec 4, 2017 at 6:21 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Mon, Dec 4, 2017 at 1:55 AM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
>> struct timeval which is part of struct input_event to
>> maintain the event times is not y2038 safe.
>>
>> Real time timestamps are also not ideal for input_event
>> as this time can go backwards as noted in the patch
>> a80b83b7b8 by John Stultz.
>>
>> Arnd Bergmann suggested deprecating real time and using
>> monotonic or other timers for all input_event times as a
>> solution to both the above problems.
>>
>> Add a new ioctl to let the user dictate the kind of time
>> to be used for input events. This is similar to the evdev
>> implementation of the feature. Realtime is still the
>> default time. This is to maintain backward compatibility.
>>
>> The structure to maintain input events will be changed
>> in a different patch.
>
> Based on Peter's comment from when you first posted this,
> https://patchwork.kernel.org/patch/9381209/, I tried to follow
> the code path again, to see if we can come up with a way
> to avoid introducing a new ioctl.
>
> There is one idea I had now: The two events we
> get (upload and erase) are both triggered from evdev,
> which gets called from user space through the EVIOCSFF
> and EVIOCRMFF ioctls. This device already sets the
> clock domain. Would it make sense to send the event
> to the uinput owner using the same clock domain that
> was set by the evdev owner, or are these two separate
> by definition?

uinput and evdev are two separate drivers. One is to write events to a
virtual device and the other is to read from any input device.
I considered both of these separate as the two events.
Let me know if you guys prefer something else.

We could also do away with this patch and just say we extend time till
2106 as we change struct input_event if we are okay with using
realtime only for uinput.

-Deepa
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arnd Bergmann Dec. 4, 2017, 9:18 p.m. UTC | #3
On Mon, Dec 4, 2017 at 9:36 PM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
> On Mon, Dec 4, 2017 at 6:21 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> On Mon, Dec 4, 2017 at 1:55 AM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
>>> struct timeval which is part of struct input_event to
>>> maintain the event times is not y2038 safe.
>>>
>>> Real time timestamps are also not ideal for input_event
>>> as this time can go backwards as noted in the patch
>>> a80b83b7b8 by John Stultz.
>>>
>>> Arnd Bergmann suggested deprecating real time and using
>>> monotonic or other timers for all input_event times as a
>>> solution to both the above problems.
>>>
>>> Add a new ioctl to let the user dictate the kind of time
>>> to be used for input events. This is similar to the evdev
>>> implementation of the feature. Realtime is still the
>>> default time. This is to maintain backward compatibility.
>>>
>>> The structure to maintain input events will be changed
>>> in a different patch.
>>
>> Based on Peter's comment from when you first posted this,
>> https://patchwork.kernel.org/patch/9381209/, I tried to follow
>> the code path again, to see if we can come up with a way
>> to avoid introducing a new ioctl.
>>
>> There is one idea I had now: The two events we
>> get (upload and erase) are both triggered from evdev,
>> which gets called from user space through the EVIOCSFF
>> and EVIOCRMFF ioctls. This device already sets the
>> clock domain. Would it make sense to send the event
>> to the uinput owner using the same clock domain that
>> was set by the evdev owner, or are these two separate
>> by definition?
>
> uinput and evdev are two separate drivers. One is to write events to a
> virtual device and the other is to read from any input device.
> I considered both of these separate as the two events.
> Let me know if you guys prefer something else.

Ok

> We could also do away with this patch and just say we extend time till
> 2106 as we change struct input_event if we are okay with using
> realtime only for uinput.

Another option might be to use monotonic times unconditionally
in uinput. The DRM drivers actually did this conversion successfully:
they changed the timestamps from real-time to monotonic-time and
added a module parameter to revert back to the old behavior. In
the end (after a few years) it turned out that nothing relied on real
time anyway, so I sent a patch to kill off the option.

It seems rather likely that this is in the same category: the user
space reading the events either doesn't access the timestamps
at all, or is only interested in relative times, not absolute ones.

The one program that I found that reads from /dev/uinput
is this one: http://svn.navi.cx/misc/trunk/inputpipe/src/
Here, all input_events get relayed between two machines,
so an input device on one can be used on the other across
a socket. The input_event data that we get from uinput gets
either interpreted (ignoring the timestamp) or pushed into
the evdev interface on the other machine, which then ignores
the timestamp in the kernel and creates a new stamp instead.

       Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Deepa Dinamani Dec. 4, 2017, 9:38 p.m. UTC | #4
On Mon, Dec 4, 2017 at 1:18 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Mon, Dec 4, 2017 at 9:36 PM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
>> On Mon, Dec 4, 2017 at 6:21 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>>> On Mon, Dec 4, 2017 at 1:55 AM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
>>>> struct timeval which is part of struct input_event to
>>>> maintain the event times is not y2038 safe.
>>>>
>>>> Real time timestamps are also not ideal for input_event
>>>> as this time can go backwards as noted in the patch
>>>> a80b83b7b8 by John Stultz.
>>>>
>>>> Arnd Bergmann suggested deprecating real time and using
>>>> monotonic or other timers for all input_event times as a
>>>> solution to both the above problems.
>>>>
>>>> Add a new ioctl to let the user dictate the kind of time
>>>> to be used for input events. This is similar to the evdev
>>>> implementation of the feature. Realtime is still the
>>>> default time. This is to maintain backward compatibility.
>>>>
>>>> The structure to maintain input events will be changed
>>>> in a different patch.
>>>
>>> Based on Peter's comment from when you first posted this,
>>> https://patchwork.kernel.org/patch/9381209/, I tried to follow
>>> the code path again, to see if we can come up with a way
>>> to avoid introducing a new ioctl.
>>>
>>> There is one idea I had now: The two events we
>>> get (upload and erase) are both triggered from evdev,
>>> which gets called from user space through the EVIOCSFF
>>> and EVIOCRMFF ioctls. This device already sets the
>>> clock domain. Would it make sense to send the event
>>> to the uinput owner using the same clock domain that
>>> was set by the evdev owner, or are these two separate
>>> by definition?
>>
>> uinput and evdev are two separate drivers. One is to write events to a
>> virtual device and the other is to read from any input device.
>> I considered both of these separate as the two events.
>> Let me know if you guys prefer something else.
>
> Ok
>
>> We could also do away with this patch and just say we extend time till
>> 2106 as we change struct input_event if we are okay with using
>> realtime only for uinput.
>
> Another option might be to use monotonic times unconditionally
> in uinput. The DRM drivers actually did this conversion successfully:
> they changed the timestamps from real-time to monotonic-time and
> added a module parameter to revert back to the old behavior. In
> the end (after a few years) it turned out that nothing relied on real
> time anyway, so I sent a patch to kill off the option.
>
> It seems rather likely that this is in the same category: the user
> space reading the events either doesn't access the timestamps
> at all, or is only interested in relative times, not absolute ones.
>
> The one program that I found that reads from /dev/uinput
> is this one: http://svn.navi.cx/misc/trunk/inputpipe/src/
> Here, all input_events get relayed between two machines,
> so an input device on one can be used on the other across
> a socket. The input_event data that we get from uinput gets
> either interpreted (ignoring the timestamp) or pushed into
> the evdev interface on the other machine, which then ignores
> the timestamp in the kernel and creates a new stamp instead.

Right. I considered using just monotonic times before.
I decided against it as John did not change the default times to
monotonic times in a80b83b7b8.
But, if nobody really cares about the actual timestamps and only
relative timestamps matter, this might be a better option.

-Deepa
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov Dec. 4, 2017, 10 p.m. UTC | #5
On Mon, Dec 04, 2017 at 01:38:01PM -0800, Deepa Dinamani wrote:
> On Mon, Dec 4, 2017 at 1:18 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Mon, Dec 4, 2017 at 9:36 PM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
> >> On Mon, Dec 4, 2017 at 6:21 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> >>> On Mon, Dec 4, 2017 at 1:55 AM, Deepa Dinamani <deepa.kernel@gmail.com> wrote:
> >>>> struct timeval which is part of struct input_event to
> >>>> maintain the event times is not y2038 safe.
> >>>>
> >>>> Real time timestamps are also not ideal for input_event
> >>>> as this time can go backwards as noted in the patch
> >>>> a80b83b7b8 by John Stultz.
> >>>>
> >>>> Arnd Bergmann suggested deprecating real time and using
> >>>> monotonic or other timers for all input_event times as a
> >>>> solution to both the above problems.
> >>>>
> >>>> Add a new ioctl to let the user dictate the kind of time
> >>>> to be used for input events. This is similar to the evdev
> >>>> implementation of the feature. Realtime is still the
> >>>> default time. This is to maintain backward compatibility.
> >>>>
> >>>> The structure to maintain input events will be changed
> >>>> in a different patch.
> >>>
> >>> Based on Peter's comment from when you first posted this,
> >>> https://patchwork.kernel.org/patch/9381209/, I tried to follow
> >>> the code path again, to see if we can come up with a way
> >>> to avoid introducing a new ioctl.
> >>>
> >>> There is one idea I had now: The two events we
> >>> get (upload and erase) are both triggered from evdev,
> >>> which gets called from user space through the EVIOCSFF
> >>> and EVIOCRMFF ioctls. This device already sets the
> >>> clock domain. Would it make sense to send the event
> >>> to the uinput owner using the same clock domain that
> >>> was set by the evdev owner, or are these two separate
> >>> by definition?
> >>
> >> uinput and evdev are two separate drivers. One is to write events to a
> >> virtual device and the other is to read from any input device.
> >> I considered both of these separate as the two events.
> >> Let me know if you guys prefer something else.
> >
> > Ok
> >
> >> We could also do away with this patch and just say we extend time till
> >> 2106 as we change struct input_event if we are okay with using
> >> realtime only for uinput.
> >
> > Another option might be to use monotonic times unconditionally
> > in uinput. The DRM drivers actually did this conversion successfully:
> > they changed the timestamps from real-time to monotonic-time and
> > added a module parameter to revert back to the old behavior. In
> > the end (after a few years) it turned out that nothing relied on real
> > time anyway, so I sent a patch to kill off the option.
> >
> > It seems rather likely that this is in the same category: the user
> > space reading the events either doesn't access the timestamps
> > at all, or is only interested in relative times, not absolute ones.
> >
> > The one program that I found that reads from /dev/uinput
> > is this one: http://svn.navi.cx/misc/trunk/inputpipe/src/
> > Here, all input_events get relayed between two machines,
> > so an input device on one can be used on the other across
> > a socket. The input_event data that we get from uinput gets
> > either interpreted (ignoring the timestamp) or pushed into
> > the evdev interface on the other machine, which then ignores
> > the timestamp in the kernel and creates a new stamp instead.
> 
> Right. I considered using just monotonic times before.
> I decided against it as John did not change the default times to
> monotonic times in a80b83b7b8.
> But, if nobody really cares about the actual timestamps and only
> relative timestamps matter, this might be a better option.

The timestamps in the kernel->userspace path in uinput are only for
force feedback control messages; userspace is not supposed to analyze
them but simply execute the instructions as they come in. I think we
should switch to the monotonic time and see if someone screams at us.
Then we can either add an option or see if there are other means of
resolving the issue.

Thanks.
diff mbox

Patch

diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 39ddd9a73feb..5a450dc04a94 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -74,6 +74,7 @@  struct uinput_device {
 	unsigned char		tail;
 	struct input_event	buff[UINPUT_BUFFER_SIZE];
 	unsigned int		ff_effects_max;
+	unsigned int		clk_type;
 
 	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
 	wait_queue_head_t	requests_waitq;
@@ -84,11 +85,26 @@  static int uinput_dev_event(struct input_dev *dev,
 			    unsigned int type, unsigned int code, int value)
 {
 	struct uinput_device	*udev = input_get_drvdata(dev);
+	struct timespec64	ts;
 
 	udev->buff[udev->head].type = type;
 	udev->buff[udev->head].code = code;
 	udev->buff[udev->head].value = value;
-	do_gettimeofday(&udev->buff[udev->head].time);
+
+	switch (udev->clk_type) {
+	case CLOCK_REALTIME:
+		ktime_get_real_ts64(&ts);
+		break;
+	case CLOCK_MONOTONIC:
+		ktime_get_ts64(&ts);
+		break;
+	case CLOCK_BOOTTIME:
+		get_monotonic_boottime64(&ts);
+		break;
+	}
+
+	udev->buff[udev->head].time.tv_sec = ts.tv_sec;
+	udev->buff[udev->head].time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
 
 	wake_up_interruptible(&udev->waitq);
@@ -370,6 +386,7 @@  static int uinput_create_device(struct uinput_device *udev)
 	if (error)
 		goto fail2;
 
+	udev->clk_type = CLOCK_REALTIME;
 	udev->state = UIST_CREATED;
 
 	return 0;
@@ -379,6 +396,38 @@  static int uinput_create_device(struct uinput_device *udev)
 	return error;
 }
 
+static int uinput_set_clk_type(struct uinput_device *udev, unsigned int clkid)
+{
+	unsigned int clk_type;
+
+	if (udev->state != UIST_CREATED)
+		return -EINVAL;
+
+	switch (clkid) {
+	/* Realtime clock is only valid until year 2038.*/
+	case CLOCK_REALTIME:
+		clk_type = CLOCK_REALTIME;
+		break;
+	case CLOCK_MONOTONIC:
+		clk_type = CLOCK_MONOTONIC;
+		break;
+	case CLOCK_BOOTTIME:
+		clk_type = CLOCK_BOOTTIME;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (udev->clk_type != clk_type) {
+		udev->clk_type = clk_type;
+
+		/* Flush pending events */
+		uinput_flush_requests(udev);
+	}
+
+	return 0;
+}
+
 static int uinput_open(struct inode *inode, struct file *file)
 {
 	struct uinput_device *newdev;
@@ -850,6 +899,7 @@  static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 	char			*phys;
 	const char		*name;
 	unsigned int		size;
+	int			clock_id;
 
 	retval = mutex_lock_interruptible(&udev->mutex);
 	if (retval)
@@ -881,6 +931,11 @@  static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 		retval = uinput_dev_setup(udev, p);
 		goto out;
 
+	case UI_SET_CLOCKID:
+		if (copy_from_user(&clock_id, p, sizeof(unsigned int)))
+			return -EFAULT;
+		return uinput_set_clk_type(udev, clock_id);
+
 	/* UI_ABS_SETUP is handled in the variable size ioctls */
 
 	case UI_SET_EVBIT:
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index c9e677e3af1d..78b480d1b6c3 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -134,6 +134,9 @@  struct uinput_abs_setup {
  */
 #define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
 
+/* Set clockid to be used for timestamps */
+#define UI_SET_CLOCKID _IOW(UINPUT_IOCTL_BASE, 5, int)
+
 #define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
 #define UI_SET_KEYBIT		_IOW(UINPUT_IOCTL_BASE, 101, int)
 #define UI_SET_RELBIT		_IOW(UINPUT_IOCTL_BASE, 102, int)