udev: validate input devices during cold-plug

During libinput initialization a list of existing input devices is
retrieved from udev. This can lead to a situation where libinput can
end up processing un-configured devices because of the race generated
by udev events and libinput startup.
Sequence example:
weston - start
udev - device 1 added
weston - get a list of input devices
weston - process device 1 -- undefined behavior
udev - device 1 added - finalized

The problem was found because of incorrect touchscreen association
when in a dual monitor system the secondary touchscreen was
incorrectly associated with output one since udev didn't finish the
device initialization and WL_OUTPUT was missing.

To avoid this situation we skip un-configured devices during libinput
initialization, relying on udev to send events when devices are
fully configured.

Note: due to the peculiarities of udev_device_get_is_initialized(), the
input device is still processed if the call fails. If there are no udev
rules defined for the device, it will never be reported as initialized,
but this is not a problem, because all input devices handled by libinput
must have some udev properties set, therefore they always have rules.

Signed-off-by: Nandor Han <nandor.han@ge.com>
[Pekka: change log to debug, unref device]
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Nandor Han 2018-04-04 14:51:33 +03:00 committed by Peter Hutterer
parent a660f487fa
commit 23d543b711

View file

@ -150,6 +150,17 @@ udev_input_add_devices(struct udev_input *input, struct udev *udev)
continue;
}
/* Skip unconfigured device. udev will send an event
* when device is fully configured */
if (!udev_device_get_is_initialized(device)) {
log_debug(&input->base,
"%-7s - skip unconfigured input device '%s'\n",
sysname,
udev_device_get_devnode(device));
udev_device_unref(device);
continue;
}
if (device_added(device, input, NULL) < 0) {
udev_device_unref(device);
udev_enumerate_unref(e);