Pete caused me to lock at buggy drivers in this respect. The idmouse has
a race between open and disconnect. This patch
- solves the open/disconnect race
- switches locking to mutexes
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
MODULE_DEVICE_TABLE(usb, idmouse_table);
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
MODULE_DEVICE_TABLE(usb, idmouse_table);
+static DEFINE_MUTEX(open_disc_mutex);
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
int open; /* if the port is open or not */
int present; /* if the device is not disconnected */
int open; /* if the port is open or not */
int present; /* if the device is not disconnected */
- struct semaphore sem; /* locks this structure */
+ struct mutex lock; /* locks this structure */
if (!interface)
return -ENODEV;
if (!interface)
return -ENODEV;
+ mutex_lock(&open_disc_mutex);
/* get the device information block from the interface */
dev = usb_get_intfdata(interface);
/* get the device information block from the interface */
dev = usb_get_intfdata(interface);
+ if (!dev) {
+ mutex_unlock(&open_disc_mutex);
+ mutex_lock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
/* check if already open */
if (dev->open) {
/* check if already open */
if (dev->open) {
error:
/* unlock this device */
error:
/* unlock this device */
+ mutex_unlock(&dev->lock);
if (dev == NULL)
return -ENODEV;
if (dev == NULL)
return -ENODEV;
+ mutex_lock(&open_disc_mutex);
+ mutex_lock(&dev->lock);
/* are we really open? */
if (dev->open <= 0) {
/* are we really open? */
if (dev->open <= 0) {
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
if (!dev->present) {
/* the device was unplugged before the file was released */
if (!dev->present) {
/* the device was unplugged before the file was released */
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
idmouse_delete(dev);
} else {
idmouse_delete(dev);
} else {
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
int result;
/* lock this object */
int result;
/* lock this object */
+ mutex_lock(&dev->lock);
/* verify that the device wasn't unplugged */
if (!dev->present) {
/* verify that the device wasn't unplugged */
if (!dev->present) {
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
result = simple_read_from_buffer(buffer, count, ppos,
dev->bulk_in_buffer, IMGSIZE);
/* unlock the device */
return -ENODEV;
}
result = simple_read_from_buffer(buffer, count, ppos,
dev->bulk_in_buffer, IMGSIZE);
/* unlock the device */
+ mutex_unlock(&dev->lock);
if (dev == NULL)
return -ENOMEM;
if (dev == NULL)
return -ENOMEM;
+ mutex_init(&dev->lock);
dev->udev = udev;
dev->interface = interface;
dev->udev = udev;
dev->interface = interface;
/* get device structure */
dev = usb_get_intfdata(interface);
/* get device structure */
dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &idmouse_class);
/* give back our minor */
usb_deregister_dev(interface, &idmouse_class);
- /* lock it */
- down(&dev->sem);
+ mutex_lock(&open_disc_mutex);
+ usb_set_intfdata(interface, NULL);
+ /* lock the device */
+ mutex_lock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
/* prevent device read, write and ioctl */
dev->present = 0;
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open) {
/* prevent device read, write and ioctl */
dev->present = 0;
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open) {
+ mutex_unlock(&dev->lock);
idmouse_delete(dev);
} else {
/* unlock */
idmouse_delete(dev);
} else {
/* unlock */
+ mutex_unlock(&dev->lock);
}
info("%s disconnected", DRIVER_DESC);
}
info("%s disconnected", DRIVER_DESC);