[PATCH xf86-input-libinput] If the parent libinput_device is unavailable, create a new one

Hans de Goede hdegoede at redhat.com
Tue Nov 15 09:35:31 UTC 2016


Hi,

On 15-11-16 05:37, Peter Hutterer wrote:
> The parent device ref's the libinput device during pre_init and unref's it
> during DEVICE_INIT, so the copy is lost. During DEVICE_ON, the libinput device
> is re-added and ref'd, this one stays around now. But the takeaway is: unless
> the device is enabled, no libinput device reference is available.
>
> If a device is a mixed pointer + keyboard device, a subdevice is created
> during a WorkProc. The subdevice relied on the parent's libinput_device being
> available and didn't even check for it. This WorkProc usually runs after
> the parent's DEVICE_ON, so in most cases all is well.
>
> But when running without logind and the server is vt-switched away, the parent
> device only runs PreInit and DEVICE_INIT but never DEVICE_ON, causing the
> subdevice to burn, crash, and generally fail horribly when it dereferences the
> parent's libinput device.
>
> Fix this because we have global warming already and don't need to burn more
> things and also because it's considered bad user experience to have the
> server crash. The simple fix is to check the parent device first and if it is
> unavailable, create a new one because it will end up disabled as well anyway,
> so the ref goes away as well. The use-case where the parent somehow gets
> disabled but the subdevice doesn't is a bit too niche to worry about.
>
> This doesn't happen with logind because in that case we don't get a usable fd
> while VT-switched away, so we can't even run PreInit and never get this far
> (see the paused fd handling in the xfree86 code for that). It can be
> reproduced by setting AutoEnableDevices off, but why would you do that,
> seriously.
>
> https://bugs.freedesktop.org/show_bug.cgi?id=97117
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

Hmm, so what happens if the parent device later does get DEVICE_ON, after
the subdevice has created its own libinputdevice ?

Regards,

Hans



> ---
>  src/xf86libinput.c | 42 +++++++++++++++++++++++-------------------
>  1 file changed, 23 insertions(+), 19 deletions(-)
>
> diff --git a/src/xf86libinput.c b/src/xf86libinput.c
> index 6792d1c..747e84b 100644
> --- a/src/xf86libinput.c
> +++ b/src/xf86libinput.c
> @@ -2850,7 +2850,7 @@ xf86libinput_pre_init(InputDriverPtr drv,
>  	struct xf86libinput *driver_data = NULL;
>  	struct xf86libinput_device *shared_device = NULL;
>  	struct libinput *libinput = NULL;
> -	struct libinput_device *device;
> +	struct libinput_device *device = NULL;
>  	char *path = NULL;
>  	bool is_subdevice;
>
> @@ -2885,7 +2885,28 @@ xf86libinput_pre_init(InputDriverPtr drv,
>  	}
>
>  	is_subdevice = xf86libinput_is_subdevice(pInfo);
> -	if (!is_subdevice) {
> +	if (is_subdevice) {
> +		InputInfoPtr parent;
> +		struct xf86libinput *parent_driver_data;
> +
> +		parent = xf86libinput_get_parent(pInfo);
> +		if (!parent) {
> +			xf86IDrvMsg(pInfo, X_ERROR, "Failed to find parent device\n");
> +			goto fail;
> +		}
> +
> +		parent_driver_data = parent->private;
> +		if (!parent_driver_data) /* parent already removed again */
> +			goto fail;
> +
> +		xf86IDrvMsg(pInfo, X_INFO, "is a virtual subdevice\n");
> +		shared_device = xf86libinput_shared_ref(parent_driver_data->shared_device);
> +		device = shared_device->device;
> +		if (!device)
> +			xf86IDrvMsg(pInfo, X_ERROR, "Parent device not available\n");
> +	}
> +
> +	if (!device) {
>  		device = libinput_path_add_device(libinput, path);
>  		if (!device) {
>  			xf86IDrvMsg(pInfo, X_ERROR, "Failed to create a device for %s\n", path);
> @@ -2903,23 +2924,6 @@ xf86libinput_pre_init(InputDriverPtr drv,
>  			libinput_device_unref(device);
>  			goto fail;
>  		}
> -	} else {
> -		InputInfoPtr parent;
> -		struct xf86libinput *parent_driver_data;
> -
> -		parent = xf86libinput_get_parent(pInfo);
> -		if (!parent) {
> -			xf86IDrvMsg(pInfo, X_ERROR, "Failed to find parent device\n");
> -			goto fail;
> -		}
> -
> -		parent_driver_data = parent->private;
> -		if (!parent_driver_data) /* parent already removed again */
> -			goto fail;
> -
> -		xf86IDrvMsg(pInfo, X_INFO, "is a virtual subdevice\n");
> -		shared_device = xf86libinput_shared_ref(parent_driver_data->shared_device);
> -		device = shared_device->device;
>  	}
>
>  	pInfo->private = driver_data;
>


More information about the xorg-devel mailing list