diff options
author | Oliver Neukum <oliver@neukum.org> | 2007-10-23 08:23:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-25 15:18:44 -0400 |
commit | 54d2bc068fd21bcb096660938bce7c7265613a24 (patch) | |
tree | 6808af091410fea3f2b7e7d06a9cdad322f51ce2 /drivers/usb | |
parent | 439a903a9663c0caa8094f3907ca60069d6c36e7 (diff) |
USB: fix locking in idmouse
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/misc/idmouse.c | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index e6fd024024f5..4bcf7fb4e5da 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c | |||
@@ -66,6 +66,7 @@ static struct usb_device_id idmouse_table[] = { | |||
66 | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) | 66 | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) |
67 | 67 | ||
68 | MODULE_DEVICE_TABLE(usb, idmouse_table); | 68 | MODULE_DEVICE_TABLE(usb, idmouse_table); |
69 | static DEFINE_MUTEX(open_disc_mutex); | ||
69 | 70 | ||
70 | /* structure to hold all of our device specific stuff */ | 71 | /* structure to hold all of our device specific stuff */ |
71 | struct usb_idmouse { | 72 | struct usb_idmouse { |
@@ -80,7 +81,7 @@ struct usb_idmouse { | |||
80 | 81 | ||
81 | int open; /* if the port is open or not */ | 82 | int open; /* if the port is open or not */ |
82 | int present; /* if the device is not disconnected */ | 83 | int present; /* if the device is not disconnected */ |
83 | struct semaphore sem; /* locks this structure */ | 84 | struct mutex lock; /* locks this structure */ |
84 | 85 | ||
85 | }; | 86 | }; |
86 | 87 | ||
@@ -213,13 +214,17 @@ static int idmouse_open(struct inode *inode, struct file *file) | |||
213 | if (!interface) | 214 | if (!interface) |
214 | return -ENODEV; | 215 | return -ENODEV; |
215 | 216 | ||
217 | mutex_lock(&open_disc_mutex); | ||
216 | /* get the device information block from the interface */ | 218 | /* get the device information block from the interface */ |
217 | dev = usb_get_intfdata(interface); | 219 | dev = usb_get_intfdata(interface); |
218 | if (!dev) | 220 | if (!dev) { |
221 | mutex_unlock(&open_disc_mutex); | ||
219 | return -ENODEV; | 222 | return -ENODEV; |
223 | } | ||
220 | 224 | ||
221 | /* lock this device */ | 225 | /* lock this device */ |
222 | down(&dev->sem); | 226 | mutex_lock(&dev->lock); |
227 | mutex_unlock(&open_disc_mutex); | ||
223 | 228 | ||
224 | /* check if already open */ | 229 | /* check if already open */ |
225 | if (dev->open) { | 230 | if (dev->open) { |
@@ -245,7 +250,7 @@ static int idmouse_open(struct inode *inode, struct file *file) | |||
245 | error: | 250 | error: |
246 | 251 | ||
247 | /* unlock this device */ | 252 | /* unlock this device */ |
248 | up(&dev->sem); | 253 | mutex_unlock(&dev->lock); |
249 | return result; | 254 | return result; |
250 | } | 255 | } |
251 | 256 | ||
@@ -258,12 +263,14 @@ static int idmouse_release(struct inode *inode, struct file *file) | |||
258 | if (dev == NULL) | 263 | if (dev == NULL) |
259 | return -ENODEV; | 264 | return -ENODEV; |
260 | 265 | ||
266 | mutex_lock(&open_disc_mutex); | ||
261 | /* lock our device */ | 267 | /* lock our device */ |
262 | down(&dev->sem); | 268 | mutex_lock(&dev->lock); |
263 | 269 | ||
264 | /* are we really open? */ | 270 | /* are we really open? */ |
265 | if (dev->open <= 0) { | 271 | if (dev->open <= 0) { |
266 | up(&dev->sem); | 272 | mutex_unlock(&dev->lock); |
273 | mutex_unlock(&open_disc_mutex); | ||
267 | return -ENODEV; | 274 | return -ENODEV; |
268 | } | 275 | } |
269 | 276 | ||
@@ -271,10 +278,12 @@ static int idmouse_release(struct inode *inode, struct file *file) | |||
271 | 278 | ||
272 | if (!dev->present) { | 279 | if (!dev->present) { |
273 | /* the device was unplugged before the file was released */ | 280 | /* the device was unplugged before the file was released */ |
274 | up(&dev->sem); | 281 | mutex_unlock(&dev->lock); |
282 | mutex_unlock(&open_disc_mutex); | ||
275 | idmouse_delete(dev); | 283 | idmouse_delete(dev); |
276 | } else { | 284 | } else { |
277 | up(&dev->sem); | 285 | mutex_unlock(&dev->lock); |
286 | mutex_unlock(&open_disc_mutex); | ||
278 | } | 287 | } |
279 | return 0; | 288 | return 0; |
280 | } | 289 | } |
@@ -286,18 +295,18 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count | |||
286 | int result; | 295 | int result; |
287 | 296 | ||
288 | /* lock this object */ | 297 | /* lock this object */ |
289 | down(&dev->sem); | 298 | mutex_lock(&dev->lock); |
290 | 299 | ||
291 | /* verify that the device wasn't unplugged */ | 300 | /* verify that the device wasn't unplugged */ |
292 | if (!dev->present) { | 301 | if (!dev->present) { |
293 | up(&dev->sem); | 302 | mutex_unlock(&dev->lock); |
294 | return -ENODEV; | 303 | return -ENODEV; |
295 | } | 304 | } |
296 | 305 | ||
297 | result = simple_read_from_buffer(buffer, count, ppos, | 306 | result = simple_read_from_buffer(buffer, count, ppos, |
298 | dev->bulk_in_buffer, IMGSIZE); | 307 | dev->bulk_in_buffer, IMGSIZE); |
299 | /* unlock the device */ | 308 | /* unlock the device */ |
300 | up(&dev->sem); | 309 | mutex_unlock(&dev->lock); |
301 | return result; | 310 | return result; |
302 | } | 311 | } |
303 | 312 | ||
@@ -320,7 +329,7 @@ static int idmouse_probe(struct usb_interface *interface, | |||
320 | if (dev == NULL) | 329 | if (dev == NULL) |
321 | return -ENOMEM; | 330 | return -ENOMEM; |
322 | 331 | ||
323 | init_MUTEX(&dev->sem); | 332 | mutex_init(&dev->lock); |
324 | dev->udev = udev; | 333 | dev->udev = udev; |
325 | dev->interface = interface; | 334 | dev->interface = interface; |
326 | 335 | ||
@@ -372,24 +381,26 @@ static void idmouse_disconnect(struct usb_interface *interface) | |||
372 | 381 | ||
373 | /* get device structure */ | 382 | /* get device structure */ |
374 | dev = usb_get_intfdata(interface); | 383 | dev = usb_get_intfdata(interface); |
375 | usb_set_intfdata(interface, NULL); | ||
376 | 384 | ||
377 | /* give back our minor */ | 385 | /* give back our minor */ |
378 | usb_deregister_dev(interface, &idmouse_class); | 386 | usb_deregister_dev(interface, &idmouse_class); |
379 | 387 | ||
380 | /* lock it */ | 388 | mutex_lock(&open_disc_mutex); |
381 | down(&dev->sem); | 389 | usb_set_intfdata(interface, NULL); |
390 | /* lock the device */ | ||
391 | mutex_lock(&dev->lock); | ||
392 | mutex_unlock(&open_disc_mutex); | ||
382 | 393 | ||
383 | /* prevent device read, write and ioctl */ | 394 | /* prevent device read, write and ioctl */ |
384 | dev->present = 0; | 395 | dev->present = 0; |
385 | 396 | ||
386 | /* if the device is opened, idmouse_release will clean this up */ | 397 | /* if the device is opened, idmouse_release will clean this up */ |
387 | if (!dev->open) { | 398 | if (!dev->open) { |
388 | up(&dev->sem); | 399 | mutex_unlock(&dev->lock); |
389 | idmouse_delete(dev); | 400 | idmouse_delete(dev); |
390 | } else { | 401 | } else { |
391 | /* unlock */ | 402 | /* unlock */ |
392 | up(&dev->sem); | 403 | mutex_unlock(&dev->lock); |
393 | } | 404 | } |
394 | 405 | ||
395 | info("%s disconnected", DRIVER_DESC); | 406 | info("%s disconnected", DRIVER_DESC); |