History

Input: mousedev - fix race when creating mixed device

We should not be using static variable mousedev_mix in methods that can be called before that singleton gets assigned. While at it let's add open and close methods to mousedev structure so that we do not need to test if we are dealing with multiplexor or normal device and simply call appropriate method directly. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=71551

Dmitry Torokhov committed 12 years ago

Commit e4dbedc1 parent fc7392a1 file · +42 −31Browse files

Unified · Split

drivers/input/mousedev.c+42−31
@@ -67,7 +67,6 @@ struct mousedev { · 66 unmodified lines
6767 struct device dev;
6868 struct cdev cdev;
6969 bool exist;
70− bool is_mixdev;
7170
7271 struct list_head mixdev_node;
7372 bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev { · 3 unmodified lines
7776 int old_x[4], old_y[4];
7877 int frac_dx, frac_dy;
7978 unsigned long touch;
79+
80+ int (*open_device)(struct mousedev *mousedev);
81+ void (*close_device)(struct mousedev *mousedev);
8082 };
8183
8284 enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; · 33 unmodified lines
116118 static struct mousedev *mousedev_mix;
117119 static LIST_HEAD(mousedev_mix_list);
118120
119−static void mixdev_open_devices(void);
120−static void mixdev_close_devices(void);
121−
122121 #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
123122 #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
124123
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev) · 303 unmodified lines
428427 if (retval)
429428 return retval;
430429
431− if (mousedev->is_mixdev)
432− mixdev_open_devices();
433− else if (!mousedev->exist)
430+ if (!mousedev->exist)
434431 retval = -ENODEV;
435432 else if (!mousedev->open++) {
436433 retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev) · 9 unmodified lines
446443 {
447444 mutex_lock(&mousedev->mutex);
448445
449− if (mousedev->is_mixdev)
450− mixdev_close_devices();
451− else if (mousedev->exist && !--mousedev->open)
446+ if (mousedev->exist && !--mousedev->open)
452447 input_close_device(&mousedev->handle);
453448
454449 mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev) · 4 unmodified lines
459454 * stream. Note that this function is called with mousedev_mix->mutex
460455 * held.
461456 */
462−static void mixdev_open_devices(void)
457+static int mixdev_open_devices(struct mousedev *mixdev)
463458 {
464− struct mousedev *mousedev;
459+ int error;
460+
461+ error = mutex_lock_interruptible(&mixdev->mutex);
462+ if (error)
463+ return error;
465464
466− if (mousedev_mix->open++)
467− return;
465+ if (!mixdev->open++) {
466+ struct mousedev *mousedev;
468467
469− list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
470− if (!mousedev->opened_by_mixdev) {
471− if (mousedev_open_device(mousedev))
472− continue;
468+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
469+ if (!mousedev->opened_by_mixdev) {
470+ if (mousedev_open_device(mousedev))
471+ continue;
473472
474− mousedev->opened_by_mixdev = true;
473+ mousedev->opened_by_mixdev = true;
474+ }
475475 }
476476 }
477+
478+ mutex_unlock(&mixdev->mutex);
479+ return 0;
477480 }
478481
479482 /*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void) · 1 unmodified line
481484 * device. Note that this function is called with mousedev_mix->mutex
482485 * held.
483486 */
484−static void mixdev_close_devices(void)
487+static void mixdev_close_devices(struct mousedev *mixdev)
485488 {
486− struct mousedev *mousedev;
489+ mutex_lock(&mixdev->mutex);
487490
488− if (--mousedev_mix->open)
489− return;
491+ if (!--mixdev->open) {
492+ struct mousedev *mousedev;
490493
491− list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
492− if (mousedev->opened_by_mixdev) {
493− mousedev->opened_by_mixdev = false;
494− mousedev_close_device(mousedev);
494+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
495+ if (mousedev->opened_by_mixdev) {
496+ mousedev->opened_by_mixdev = false;
497+ mousedev_close_device(mousedev);
498+ }
495499 }
496500 }
501+
502+ mutex_unlock(&mixdev->mutex);
497503 }
498504
499505
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file) · 22 unmodified lines
522528 mousedev_detach_client(mousedev, client);
523529 kfree(client);
524530
525− mousedev_close_device(mousedev);
531+ mousedev->close_device(mousedev);
526532
527533 return 0;
528534 }
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file) · 21 unmodified lines
550556 client->mousedev = mousedev;
551557 mousedev_attach_client(mousedev, client);
552558
553− error = mousedev_open_device(mousedev);
559+ error = mousedev->open_device(mousedev);
554560 if (error)
555561 goto err_free_client;
556562
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, · 304 unmodified lines
861867
862868 if (mixdev) {
863869 dev_set_name(&mousedev->dev, "mice");
870+
871+ mousedev->open_device = mixdev_open_devices;
872+ mousedev->close_device = mixdev_close_devices;
864873 } else {
865874 int dev_no = minor;
866875 /* Normalize device number if it falls into legacy range */
867876 if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
868877 dev_no -= MOUSEDEV_MINOR_BASE;
869878 dev_set_name(&mousedev->dev, "mouse%d", dev_no);
879+
880+ mousedev->open_device = mousedev_open_device;
881+ mousedev->close_device = mousedev_close_device;
870882 }
871883
872884 mousedev->exist = true;
873− mousedev->is_mixdev = mixdev;
874885 mousedev->handle.dev = input_get_device(dev);
875886 mousedev->handle.name = dev_name(&mousedev->dev);
876887 mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev) · 42 unmodified lines
919930 device_del(&mousedev->dev);
920931 mousedev_cleanup(mousedev);
921932 input_free_minor(MINOR(mousedev->dev.devt));
922− if (!mousedev->is_mixdev)
933+ if (mousedev != mousedev_mix)
923934 input_unregister_handle(&mousedev->handle);
924935 put_device(&mousedev->dev);
925936 }