summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamu Onkalo <samu.p.onkalo@nokia.com>2010-02-19 23:17:58 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-02-20 01:23:55 -0800
commitd9c4f846997c6d37e4f56907d93f1be022c17c6b (patch)
treec8565964e0d4566d1b5ef912c12c64b773b00e70
parent3b77fd8ee6a8ae34e349651e9d5f5000d1cc206e (diff)
downloadlwn-d9c4f846997c6d37e4f56907d93f1be022c17c6b.tar.gz
lwn-d9c4f846997c6d37e4f56907d93f1be022c17c6b.zip
Input: polldev can cause crash in case when polling disabled
When polled input device is opened and closed and there are no other users of polled device, the workqueue is created and destroyed in every open / close operation. It is probable that at some point dynamic allocation of internal parts of the workqueue cause changes to the workqueue. When a work is queued to the workqueue the work struct contains pointers to the workqueue data. If the workqueue has been changed and the work has never been queued to the new workqueue, work-struct contains pointers to the non-existing workqueue. This will cause crash at the work cancellation during device close since cancellation of a work assumes that the workqueue exists. To prevent that, work struct is cleaned up at device close. This keeps work struct clean for the next use. Signed-off-by: Samu Onkalo <samu.p.onkalo@nokia.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/input-polldev.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index aa6713b4a988..291d9393d359 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -100,6 +100,12 @@ static void input_close_polled_device(struct input_dev *input)
struct input_polled_dev *dev = input_get_drvdata(input);
cancel_delayed_work_sync(&dev->work);
+ /*
+ * Clean up work struct to remove references to the workqueue.
+ * It may be destroyed by the next call. This causes problems
+ * at next device open-close in case of poll_interval == 0.
+ */
+ INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
input_polldev_stop_workqueue();
if (dev->close)