summaryrefslogtreecommitdiffstats
path: root/drivers/input/misc
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2017-09-01 20:13:43 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-09-21 19:31:22 -0400
commite8b95728f724797f958912fd9b765a695595d3a6 (patch)
tree0d3f91f4dc14bf8eb728def1697283cce9177aab /drivers/input/misc
parentbbc8608755da42e7494c00dce24a636007972def (diff)
Input: uinput - avoid FF flush when destroying device
Normally, when input device supporting force feedback effects is being destroyed, we try to "flush" currently playing effects, so that the physical device does not continue vibrating (or executing other effects). Unfortunately this does not work well for uinput as flushing of the effects deadlocks with the destroy action: - if device is being destroyed because the file descriptor is being closed, then there is noone to even service FF requests; - if device is being destroyed because userspace sent UI_DEV_DESTROY, while theoretically it could be possible to service FF requests, userspace is unlikely to do so (they'd need to make sure FF handling happens on a separate thread) even if kernel solves the issue with FF ioctls deadlocking with UI_DEV_DESTROY ioctl on udev->mutex. To avoid lockups like the one below, let's install a custom input device flush handler, and avoid trying to flush force feedback effects when we destroying the device, and instead rely on uinput to shut off the device properly. NMI watchdog: Watchdog detected hard LOCKUP on cpu 3 ... <<EOE>> [<ffffffff817a0307>] _raw_spin_lock_irqsave+0x37/0x40 [<ffffffff810e633d>] complete+0x1d/0x50 [<ffffffffa00ba08c>] uinput_request_done+0x3c/0x40 [uinput] [<ffffffffa00ba587>] uinput_request_submit.part.7+0x47/0xb0 [uinput] [<ffffffffa00bb62b>] uinput_dev_erase_effect+0x5b/0x76 [uinput] [<ffffffff815d91ad>] erase_effect+0xad/0xf0 [<ffffffff815d929d>] flush_effects+0x4d/0x90 [<ffffffff815d4cc0>] input_flush_device+0x40/0x60 [<ffffffff815daf1c>] evdev_cleanup+0xac/0xc0 [<ffffffff815daf5b>] evdev_disconnect+0x2b/0x60 [<ffffffff815d74ac>] __input_unregister_device+0xac/0x150 [<ffffffff815d75f7>] input_unregister_device+0x47/0x70 [<ffffffffa00bac45>] uinput_destroy_device+0xb5/0xc0 [uinput] [<ffffffffa00bb2de>] uinput_ioctl_handler.isra.9+0x65e/0x740 [uinput] [<ffffffff811231ab>] ? do_futex+0x12b/0xad0 [<ffffffffa00bb3f8>] uinput_ioctl+0x18/0x20 [uinput] [<ffffffff81241248>] do_vfs_ioctl+0x298/0x480 [<ffffffff81337553>] ? security_file_ioctl+0x43/0x60 [<ffffffff812414a9>] SyS_ioctl+0x79/0x90 [<ffffffff817a04ee>] entry_SYSCALL_64_fastpath+0x12/0x71 Reported-by: Rodrigo Rivas Costa <rodrigorivascosta@gmail.com> Reported-by: Clément VUCHENER <clement.vuchener@gmail.com> Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=193741 Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/uinput.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 022be0e22eba..2cff40be8860 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -230,6 +230,18 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
230 return uinput_request_submit(udev, &request); 230 return uinput_request_submit(udev, &request);
231} 231}
232 232
233static int uinput_dev_flush(struct input_dev *dev, struct file *file)
234{
235 /*
236 * If we are called with file == NULL that means we are tearing
237 * down the device, and therefore we can not handle FF erase
238 * requests: either we are handling UI_DEV_DESTROY (and holding
239 * the udev->mutex), or the file descriptor is closed and there is
240 * nobody on the other side anymore.
241 */
242 return file ? input_ff_flush(dev, file) : 0;
243}
244
233static void uinput_destroy_device(struct uinput_device *udev) 245static void uinput_destroy_device(struct uinput_device *udev)
234{ 246{
235 const char *name, *phys; 247 const char *name, *phys;
@@ -297,6 +309,12 @@ static int uinput_create_device(struct uinput_device *udev)
297 dev->ff->playback = uinput_dev_playback; 309 dev->ff->playback = uinput_dev_playback;
298 dev->ff->set_gain = uinput_dev_set_gain; 310 dev->ff->set_gain = uinput_dev_set_gain;
299 dev->ff->set_autocenter = uinput_dev_set_autocenter; 311 dev->ff->set_autocenter = uinput_dev_set_autocenter;
312 /*
313 * The standard input_ff_flush() implementation does
314 * not quite work for uinput as we can't reasonably
315 * handle FF requests during device teardown.
316 */
317 dev->flush = uinput_dev_flush;
300 } 318 }
301 319
302 error = input_register_device(udev->dev); 320 error = input_register_device(udev->dev);