Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: prevent char device open/deregister race

This patch (as908) adds central protection in usbcore for the
prototypical race between opening and unregistering a char device.
The spinlock used to protect the minor-numbers array is replaced with
an rwsem, which can remain locked across a call to a driver's open()
method. This guarantees that open() and deregister() will be mutually
exclusive.

The private locks currently used in several individual drivers for
this purpose are no longer necessary, and the patch removes them. The
following USB drivers are affected: usblcd, idmouse, auerswald,
legousbtower, sisusbvga/sisusb, ldusb, adutux, iowarrior, and
usb-skeleton.

As a side effect of this change, usb_deregister_dev() must not be
called while holding a lock that is acquired by open(). Unfortunately
a number of drivers do this, but luckily the solution is simple: call
usb_deregister_dev() before acquiring the lock.

In addition to these changes (and their consequent code
simplifications), the patch fixes a use-after-free bug in adutux and a
race between open() and release() in iowarrior.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
d4ead16f 55e5fdfa

+75 -228
+13 -16
drivers/usb/core/file.c
··· 16 16 */ 17 17 18 18 #include <linux/module.h> 19 - #include <linux/spinlock.h> 20 19 #include <linux/errno.h> 20 + #include <linux/rwsem.h> 21 21 #include <linux/usb.h> 22 22 23 23 #include "usb.h" 24 24 25 25 #define MAX_USB_MINORS 256 26 26 static const struct file_operations *usb_minors[MAX_USB_MINORS]; 27 - static DEFINE_SPINLOCK(minor_lock); 27 + static DECLARE_RWSEM(minor_rwsem); 28 28 29 29 static int usb_open(struct inode * inode, struct file * file) 30 30 { ··· 33 33 int err = -ENODEV; 34 34 const struct file_operations *old_fops, *new_fops = NULL; 35 35 36 - spin_lock (&minor_lock); 36 + down_read(&minor_rwsem); 37 37 c = usb_minors[minor]; 38 38 39 - if (!c || !(new_fops = fops_get(c))) { 40 - spin_unlock(&minor_lock); 41 - return err; 42 - } 43 - spin_unlock(&minor_lock); 39 + if (!c || !(new_fops = fops_get(c))) 40 + goto done; 44 41 45 42 old_fops = file->f_op; 46 43 file->f_op = new_fops; ··· 49 52 file->f_op = fops_get(old_fops); 50 53 } 51 54 fops_put(old_fops); 55 + done: 56 + up_read(&minor_rwsem); 52 57 return err; 53 58 } 54 59 ··· 165 166 if (class_driver->fops == NULL) 166 167 goto exit; 167 168 168 - spin_lock (&minor_lock); 169 + down_write(&minor_rwsem); 169 170 for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { 170 171 if (usb_minors[minor]) 171 172 continue; ··· 175 176 retval = 0; 176 177 break; 177 178 } 178 - spin_unlock (&minor_lock); 179 + up_write(&minor_rwsem); 179 180 180 181 if (retval) 181 182 goto exit; ··· 196 197 intf->usb_dev = device_create(usb_class->class, &intf->dev, 197 198 MKDEV(USB_MAJOR, minor), "%s", temp); 198 199 if (IS_ERR(intf->usb_dev)) { 199 - spin_lock (&minor_lock); 200 + down_write(&minor_rwsem); 200 201 usb_minors[intf->minor] = NULL; 201 - spin_unlock (&minor_lock); 202 + up_write(&minor_rwsem); 202 203 retval = PTR_ERR(intf->usb_dev); 203 204 } 204 205 exit: ··· 235 236 236 237 dbg ("removing %d minor", intf->minor); 237 238 238 - spin_lock (&minor_lock); 239 + down_write(&minor_rwsem); 239 240 usb_minors[intf->minor] = NULL; 240 - spin_unlock (&minor_lock); 241 + up_write(&minor_rwsem); 241 242 242 243 snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); 243 244 device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); ··· 246 247 destroy_usb_class(); 247 248 } 248 249 EXPORT_SYMBOL(usb_deregister_dev); 249 - 250 -
+11 -20
drivers/usb/misc/adutux.c
··· 108 108 struct urb* interrupt_out_urb; 109 109 }; 110 110 111 - /* prevent races between open() and disconnect */ 112 - static DEFINE_MUTEX(disconnect_mutex); 113 111 static struct usb_driver adu_driver; 114 112 115 113 static void adu_debug_data(int level, const char *function, int size, ··· 254 256 255 257 subminor = iminor(inode); 256 258 257 - mutex_lock(&disconnect_mutex); 258 - 259 259 interface = usb_find_interface(&adu_driver, subminor); 260 260 if (!interface) { 261 261 err("%s - error, can't find device for minor %d", ··· 302 306 up(&dev->sem); 303 307 304 308 exit_no_device: 305 - mutex_unlock(&disconnect_mutex); 306 309 dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval); 307 310 308 311 return retval; ··· 313 318 314 319 dbg(2," %s : enter", __FUNCTION__); 315 320 316 - if (dev->udev == NULL) { 317 - /* the device was unplugged before the file was released */ 318 - adu_delete(dev); 319 - goto exit; 320 - } 321 - 322 321 /* decrement our usage count for the device */ 323 322 --dev->open_count; 324 323 dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); ··· 321 332 dev->open_count = 0; 322 333 } 323 334 324 - exit: 325 335 dbg(2," %s : leave", __FUNCTION__); 326 336 return retval; 327 337 } ··· 355 367 goto exit; 356 368 } 357 369 358 - /* do the work */ 359 - retval = adu_release_internal(dev); 370 + if (dev->udev == NULL) { 371 + /* the device was unplugged before the file was released */ 372 + up(&dev->sem); 373 + adu_delete(dev); 374 + dev = NULL; 375 + } else { 376 + /* do the work */ 377 + retval = adu_release_internal(dev); 378 + } 360 379 361 380 exit: 362 381 if (dev) ··· 826 831 827 832 dbg(2," %s : enter", __FUNCTION__); 828 833 829 - mutex_lock(&disconnect_mutex); /* not interruptible */ 830 - 831 834 dev = usb_get_intfdata(interface); 832 835 usb_set_intfdata(interface, NULL); 833 - 834 - down(&dev->sem); /* not interruptible */ 835 836 836 837 minor = dev->minor; 837 838 838 839 /* give back our minor */ 839 840 usb_deregister_dev(interface, &adu_class); 840 841 dev->minor = 0; 842 + 843 + down(&dev->sem); /* not interruptible */ 841 844 842 845 /* if the device is not opened, then we clean up right now */ 843 846 dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); ··· 846 853 dev->udev = NULL; 847 854 up(&dev->sem); 848 855 } 849 - 850 - mutex_unlock(&disconnect_mutex); 851 856 852 857 dev_info(&interface->dev, "ADU device adutux%d now disconnected", 853 858 (minor - ADU_MINOR_BASE));
+3 -3
drivers/usb/misc/auerswald.c
··· 2034 2034 if (!cp) 2035 2035 return; 2036 2036 2037 - down (&cp->mutex); 2038 - info ("device /dev/%s now disconnecting", cp->name); 2039 - 2040 2037 /* give back our USB minor number */ 2041 2038 usb_deregister_dev(intf, &auerswald_class); 2039 + 2040 + down (&cp->mutex); 2041 + info ("device /dev/%s now disconnecting", cp->name); 2042 2042 2043 2043 /* Stop the interrupt endpoint */ 2044 2044 auerswald_int_release (cp);
+15 -39
drivers/usb/misc/idmouse.c
··· 119 119 .id_table = idmouse_table, 120 120 }; 121 121 122 - /* prevent races between open() and disconnect() */ 123 - static DEFINE_MUTEX(disconnect_mutex); 124 - 125 122 static int idmouse_create_image(struct usb_idmouse *dev) 126 123 { 127 124 int bytes_read; ··· 208 211 struct usb_interface *interface; 209 212 int result; 210 213 211 - /* prevent disconnects */ 212 - mutex_lock(&disconnect_mutex); 213 - 214 214 /* get the interface from minor number and driver information */ 215 215 interface = usb_find_interface (&idmouse_driver, iminor (inode)); 216 - if (!interface) { 217 - mutex_unlock(&disconnect_mutex); 216 + if (!interface) 218 217 return -ENODEV; 219 - } 218 + 220 219 /* get the device information block from the interface */ 221 220 dev = usb_get_intfdata(interface); 222 - if (!dev) { 223 - mutex_unlock(&disconnect_mutex); 221 + if (!dev) 224 222 return -ENODEV; 225 - } 226 223 227 224 /* lock this device */ 228 225 down(&dev->sem); ··· 246 255 247 256 /* unlock this device */ 248 257 up(&dev->sem); 249 - 250 - /* unlock the disconnect semaphore */ 251 - mutex_unlock(&disconnect_mutex); 252 258 return result; 253 259 } 254 260 ··· 253 265 { 254 266 struct usb_idmouse *dev; 255 267 256 - /* prevent a race condition with open() */ 257 - mutex_lock(&disconnect_mutex); 258 - 259 268 dev = file->private_data; 260 269 261 - if (dev == NULL) { 262 - mutex_unlock(&disconnect_mutex); 270 + if (dev == NULL) 263 271 return -ENODEV; 264 - } 265 272 266 273 /* lock our device */ 267 274 down(&dev->sem); ··· 264 281 /* are we really open? */ 265 282 if (dev->open <= 0) { 266 283 up(&dev->sem); 267 - mutex_unlock(&disconnect_mutex); 268 284 return -ENODEV; 269 285 } 270 286 ··· 273 291 /* the device was unplugged before the file was released */ 274 292 up(&dev->sem); 275 293 idmouse_delete(dev); 276 - mutex_unlock(&disconnect_mutex); 277 - return 0; 294 + } else { 295 + up(&dev->sem); 278 296 } 279 - 280 - up(&dev->sem); 281 - mutex_unlock(&disconnect_mutex); 282 297 return 0; 283 298 } 284 299 ··· 370 391 { 371 392 struct usb_idmouse *dev; 372 393 373 - /* prevent races with open() */ 374 - mutex_lock(&disconnect_mutex); 375 - 376 394 /* get device structure */ 377 395 dev = usb_get_intfdata(interface); 378 396 usb_set_intfdata(interface, NULL); 379 397 380 - /* lock it */ 381 - down(&dev->sem); 382 - 383 398 /* give back our minor */ 384 399 usb_deregister_dev(interface, &idmouse_class); 400 + 401 + /* lock it */ 402 + down(&dev->sem); 385 403 386 404 /* prevent device read, write and ioctl */ 387 405 dev->present = 0; 388 406 389 - /* unlock */ 390 - up(&dev->sem); 391 - 392 407 /* if the device is opened, idmouse_release will clean this up */ 393 - if (!dev->open) 408 + if (!dev->open) { 409 + up(&dev->sem); 394 410 idmouse_delete(dev); 395 - 396 - mutex_unlock(&disconnect_mutex); 411 + } else { 412 + /* unlock */ 413 + up(&dev->sem); 414 + } 397 415 398 416 info("%s disconnected", DRIVER_DESC); 399 417 }
+8 -18
drivers/usb/misc/iowarrior.c
··· 100 100 /*--------------*/ 101 101 /* globals */ 102 102 /*--------------*/ 103 - /* prevent races between open() and disconnect() */ 104 - static DECLARE_MUTEX(disconnect_sem); 105 103 106 104 /* 107 105 * USB spec identifies 5 second timeouts. ··· 598 600 599 601 subminor = iminor(inode); 600 602 601 - /* prevent disconnects */ 602 - down(&disconnect_sem); 603 - 604 603 interface = usb_find_interface(&iowarrior_driver, subminor); 605 604 if (!interface) { 606 605 err("%s - error, can't find device for minor %d", __FUNCTION__, 607 606 subminor); 608 - retval = -ENODEV; 609 - goto out; 607 + return -ENODEV; 610 608 } 611 609 612 610 dev = usb_get_intfdata(interface); 613 - if (!dev) { 614 - retval = -ENODEV; 615 - goto out; 616 - } 611 + if (!dev) 612 + return -ENODEV; 613 + 614 + mutex_lock(&dev->mutex); 617 615 618 616 /* Only one process can open each device, no sharing. */ 619 617 if (dev->opened) { ··· 630 636 retval = 0; 631 637 632 638 out: 633 - up(&disconnect_sem); 639 + mutex_unlock(&dev->mutex); 634 640 return retval; 635 641 } 636 642 ··· 862 868 struct iowarrior *dev; 863 869 int minor; 864 870 865 - /* prevent races with open() */ 866 - down(&disconnect_sem); 867 - 868 871 dev = usb_get_intfdata(interface); 869 872 usb_set_intfdata(interface, NULL); 870 - 871 - mutex_lock(&dev->mutex); 872 873 873 874 minor = dev->minor; 874 875 875 876 /* give back our minor */ 876 877 usb_deregister_dev(interface, &iowarrior_class); 878 + 879 + mutex_lock(&dev->mutex); 877 880 878 881 /* prevent device read, write and ioctl */ 879 882 dev->present = 0; ··· 889 898 /* no process is using the device, cleanup now */ 890 899 iowarrior_delete(dev); 891 900 } 892 - up(&disconnect_sem); 893 901 894 902 dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", 895 903 minor - IOWARRIOR_MINOR_BASE);
+8 -25
drivers/usb/misc/ldusb.c
··· 176 176 int interrupt_out_busy; 177 177 }; 178 178 179 - /* prevent races between open() and disconnect() */ 180 - static DEFINE_MUTEX(disconnect_mutex); 181 - 182 179 static struct usb_driver ld_usb_driver; 183 180 184 181 /** ··· 295 298 { 296 299 struct ld_usb *dev; 297 300 int subminor; 298 - int retval = 0; 301 + int retval; 299 302 struct usb_interface *interface; 300 303 301 304 nonseekable_open(inode, file); 302 305 subminor = iminor(inode); 303 - 304 - mutex_lock(&disconnect_mutex); 305 306 306 307 interface = usb_find_interface(&ld_usb_driver, subminor); 307 308 308 309 if (!interface) { 309 310 err("%s - error, can't find device for minor %d\n", 310 311 __FUNCTION__, subminor); 311 - retval = -ENODEV; 312 - goto unlock_disconnect_exit; 312 + return -ENODEV; 313 313 } 314 314 315 315 dev = usb_get_intfdata(interface); 316 316 317 - if (!dev) { 318 - retval = -ENODEV; 319 - goto unlock_disconnect_exit; 320 - } 317 + if (!dev) 318 + return -ENODEV; 321 319 322 320 /* lock this device */ 323 - if (down_interruptible(&dev->sem)) { 324 - retval = -ERESTARTSYS; 325 - goto unlock_disconnect_exit; 326 - } 321 + if (down_interruptible(&dev->sem)) 322 + return -ERESTARTSYS; 327 323 328 324 /* allow opening only once */ 329 325 if (dev->open_count) { ··· 355 365 356 366 unlock_exit: 357 367 up(&dev->sem); 358 - 359 - unlock_disconnect_exit: 360 - mutex_unlock(&disconnect_mutex); 361 368 362 369 return retval; 363 370 } ··· 753 766 struct ld_usb *dev; 754 767 int minor; 755 768 756 - mutex_lock(&disconnect_mutex); 757 - 758 769 dev = usb_get_intfdata(intf); 759 770 usb_set_intfdata(intf, NULL); 760 - 761 - down(&dev->sem); 762 771 763 772 minor = intf->minor; 764 773 765 774 /* give back our minor */ 766 775 usb_deregister_dev(intf, &ld_usb_class); 776 + 777 + down(&dev->sem); 767 778 768 779 /* if the device is not opened, then we clean up right now */ 769 780 if (!dev->open_count) { ··· 771 786 dev->intf = NULL; 772 787 up(&dev->sem); 773 788 } 774 - 775 - mutex_unlock(&disconnect_mutex); 776 789 777 790 dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", 778 791 (minor - USB_LD_MINOR_BASE));
+6 -18
drivers/usb/misc/legousbtower.c
··· 254 254 static void tower_disconnect (struct usb_interface *interface); 255 255 256 256 257 - /* prevent races between open() and disconnect */ 258 - static DEFINE_MUTEX (disconnect_mutex); 259 - 260 257 /* file operations needed when we register this driver */ 261 258 static const struct file_operations tower_fops = { 262 259 .owner = THIS_MODULE, ··· 341 344 nonseekable_open(inode, file); 342 345 subminor = iminor(inode); 343 346 344 - mutex_lock (&disconnect_mutex); 345 - 346 347 interface = usb_find_interface (&tower_driver, subminor); 347 348 348 349 if (!interface) { 349 350 err ("%s - error, can't find device for minor %d", 350 351 __FUNCTION__, subminor); 351 352 retval = -ENODEV; 352 - goto unlock_disconnect_exit; 353 + goto exit; 353 354 } 354 355 355 356 dev = usb_get_intfdata(interface); 356 357 357 358 if (!dev) { 358 359 retval = -ENODEV; 359 - goto unlock_disconnect_exit; 360 + goto exit; 360 361 } 361 362 362 363 /* lock this device */ 363 364 if (down_interruptible (&dev->sem)) { 364 365 retval = -ERESTARTSYS; 365 - goto unlock_disconnect_exit; 366 + goto exit; 366 367 } 367 368 368 369 /* allow opening only once */ ··· 416 421 unlock_exit: 417 422 up (&dev->sem); 418 423 419 - unlock_disconnect_exit: 420 - mutex_unlock (&disconnect_mutex); 421 - 424 + exit: 422 425 dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval); 423 426 424 427 return retval; ··· 986 993 987 994 dbg(2, "%s: enter", __FUNCTION__); 988 995 989 - mutex_lock (&disconnect_mutex); 990 - 991 996 dev = usb_get_intfdata (interface); 992 997 usb_set_intfdata (interface, NULL); 993 - 994 - 995 - down (&dev->sem); 996 998 997 999 minor = dev->minor; 998 1000 999 1001 /* give back our minor */ 1000 1002 usb_deregister_dev (interface, &tower_class); 1003 + 1004 + down (&dev->sem); 1001 1005 1002 1006 /* if the device is not opened, then we clean up right now */ 1003 1007 if (!dev->open_count) { ··· 1004 1014 dev->udev = NULL; 1005 1015 up (&dev->sem); 1006 1016 } 1007 - 1008 - mutex_unlock (&disconnect_mutex); 1009 1017 1010 1018 info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE)); 1011 1019
+5 -33
drivers/usb/misc/sisusbvga/sisusb.c
··· 72 72 73 73 static struct usb_driver sisusb_driver; 74 74 75 - DEFINE_MUTEX(disconnect_mutex); 76 - 77 75 static void 78 76 sisusb_free_buffers(struct sisusb_usb_data *sisusb) 79 77 { ··· 2509 2511 struct usb_interface *interface; 2510 2512 int subminor = iminor(inode); 2511 2513 2512 - mutex_lock(&disconnect_mutex); 2513 - 2514 2514 if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { 2515 2515 printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", 2516 2516 subminor); 2517 - mutex_unlock(&disconnect_mutex); 2518 2517 return -ENODEV; 2519 2518 } 2520 2519 2521 - if (!(sisusb = usb_get_intfdata(interface))) { 2522 - mutex_unlock(&disconnect_mutex); 2520 + if (!(sisusb = usb_get_intfdata(interface))) 2523 2521 return -ENODEV; 2524 - } 2525 2522 2526 2523 mutex_lock(&sisusb->lock); 2527 2524 2528 2525 if (!sisusb->present || !sisusb->ready) { 2529 2526 mutex_unlock(&sisusb->lock); 2530 - mutex_unlock(&disconnect_mutex); 2531 2527 return -ENODEV; 2532 2528 } 2533 2529 2534 2530 if (sisusb->isopen) { 2535 2531 mutex_unlock(&sisusb->lock); 2536 - mutex_unlock(&disconnect_mutex); 2537 2532 return -EBUSY; 2538 2533 } 2539 2534 ··· 2534 2543 if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { 2535 2544 if (sisusb_init_gfxdevice(sisusb, 0)) { 2536 2545 mutex_unlock(&sisusb->lock); 2537 - mutex_unlock(&disconnect_mutex); 2538 2546 printk(KERN_ERR 2539 2547 "sisusbvga[%d]: Failed to initialize " 2540 2548 "device\n", ··· 2542 2552 } 2543 2553 } else { 2544 2554 mutex_unlock(&sisusb->lock); 2545 - mutex_unlock(&disconnect_mutex); 2546 2555 printk(KERN_ERR 2547 2556 "sisusbvga[%d]: Device not attached to " 2548 2557 "USB 2.0 hub\n", ··· 2558 2569 file->private_data = sisusb; 2559 2570 2560 2571 mutex_unlock(&sisusb->lock); 2561 - 2562 - mutex_unlock(&disconnect_mutex); 2563 2572 2564 2573 return 0; 2565 2574 } ··· 2588 2601 struct sisusb_usb_data *sisusb; 2589 2602 int myminor; 2590 2603 2591 - mutex_lock(&disconnect_mutex); 2592 - 2593 - if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) { 2594 - mutex_unlock(&disconnect_mutex); 2604 + if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) 2595 2605 return -ENODEV; 2596 - } 2597 2606 2598 2607 mutex_lock(&sisusb->lock); 2599 2608 ··· 2608 2625 2609 2626 /* decrement the usage count on our device */ 2610 2627 kref_put(&sisusb->kref, sisusb_delete); 2611 - 2612 - mutex_unlock(&disconnect_mutex); 2613 2628 2614 2629 return 0; 2615 2630 } ··· 3364 3383 sisusb_console_exit(sisusb); 3365 3384 #endif 3366 3385 3367 - /* The above code doesn't need the disconnect 3368 - * semaphore to be down; its meaning is to 3369 - * protect all other routines from the disconnect 3370 - * case, not the other way round. 3371 - */ 3372 - mutex_lock(&disconnect_mutex); 3386 + minor = sisusb->minor; 3387 + 3388 + usb_deregister_dev(intf, &usb_sisusb_class); 3373 3389 3374 3390 mutex_lock(&sisusb->lock); 3375 3391 ··· 3374 3396 if (!sisusb_wait_all_out_complete(sisusb)) 3375 3397 sisusb_kill_all_busy(sisusb); 3376 3398 3377 - minor = sisusb->minor; 3378 - 3379 3399 usb_set_intfdata(intf, NULL); 3380 - 3381 - usb_deregister_dev(intf, &usb_sisusb_class); 3382 3400 3383 3401 #ifdef SISUSB_OLD_CONFIG_COMPAT 3384 3402 if (sisusb->ioctl32registered) { ··· 3399 3425 3400 3426 /* decrement our usage count */ 3401 3427 kref_put(&sisusb->kref, sisusb_delete); 3402 - 3403 - mutex_unlock(&disconnect_mutex); 3404 3428 3405 3429 printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); 3406 3430 }
+2 -23
drivers/usb/misc/sisusbvga/sisusb_con.c
··· 214 214 * are set up/restored. 215 215 */ 216 216 217 - mutex_lock(&disconnect_mutex); 218 - 219 - if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { 220 - mutex_unlock(&disconnect_mutex); 217 + if (!(sisusb = sisusb_get_sisusb(c->vc_num))) 221 218 return; 222 - } 223 219 224 220 mutex_lock(&sisusb->lock); 225 221 226 222 if (!sisusb_sisusb_valid(sisusb)) { 227 223 mutex_unlock(&sisusb->lock); 228 - mutex_unlock(&disconnect_mutex); 229 224 return; 230 225 } 231 226 ··· 259 264 260 265 mutex_unlock(&sisusb->lock); 261 266 262 - mutex_unlock(&disconnect_mutex); 263 - 264 267 if (init) { 265 268 c->vc_cols = cols; 266 269 c->vc_rows = rows; ··· 277 284 * and others, ie not under our control. 278 285 */ 279 286 280 - mutex_lock(&disconnect_mutex); 281 - 282 - if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { 283 - mutex_unlock(&disconnect_mutex); 287 + if (!(sisusb = sisusb_get_sisusb(c->vc_num))) 284 288 return; 285 - } 286 289 287 290 mutex_lock(&sisusb->lock); 288 291 ··· 303 314 304 315 /* decrement the usage count on our sisusb */ 305 316 kref_put(&sisusb->kref, sisusb_delete); 306 - 307 - mutex_unlock(&disconnect_mutex); 308 317 } 309 318 310 319 /* interface routine */ ··· 1477 1490 { 1478 1491 int i, ret, minor = sisusb->minor; 1479 1492 1480 - mutex_lock(&disconnect_mutex); 1481 - 1482 1493 mutex_lock(&sisusb->lock); 1483 1494 1484 1495 /* Erm.. that should not happen */ 1485 1496 if (sisusb->haveconsole || !sisusb->SiS_Pr) { 1486 1497 mutex_unlock(&sisusb->lock); 1487 - mutex_unlock(&disconnect_mutex); 1488 1498 return 1; 1489 1499 } 1490 1500 ··· 1492 1508 first > MAX_NR_CONSOLES || 1493 1509 last > MAX_NR_CONSOLES) { 1494 1510 mutex_unlock(&sisusb->lock); 1495 - mutex_unlock(&disconnect_mutex); 1496 1511 return 1; 1497 1512 } 1498 1513 1499 1514 /* If gfxcore not initialized or no consoles given, quit graciously */ 1500 1515 if (!sisusb->gfxinit || first < 1 || last < 1) { 1501 1516 mutex_unlock(&sisusb->lock); 1502 - mutex_unlock(&disconnect_mutex); 1503 1517 return 0; 1504 1518 } 1505 1519 ··· 1508 1526 /* Set up text mode (and upload default font) */ 1509 1527 if (sisusb_reset_text_mode(sisusb, 1)) { 1510 1528 mutex_unlock(&sisusb->lock); 1511 - mutex_unlock(&disconnect_mutex); 1512 1529 printk(KERN_ERR 1513 1530 "sisusbvga[%d]: Failed to set up text mode\n", 1514 1531 minor); ··· 1531 1550 /* Allocate screen buffer */ 1532 1551 if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { 1533 1552 mutex_unlock(&sisusb->lock); 1534 - mutex_unlock(&disconnect_mutex); 1535 1553 printk(KERN_ERR 1536 1554 "sisusbvga[%d]: Failed to allocate screen buffer\n", 1537 1555 minor); ··· 1538 1558 } 1539 1559 1540 1560 mutex_unlock(&sisusb->lock); 1541 - mutex_unlock(&disconnect_mutex); 1542 1561 1543 1562 /* Now grab the desired console(s) */ 1544 1563 ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
-2
drivers/usb/misc/sisusbvga/sisusb_init.h
··· 808 808 { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ 809 809 }; 810 810 811 - extern struct mutex disconnect_mutex; 812 - 813 811 int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); 814 812 int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); 815 813
+4 -17
drivers/usb/misc/usblcd.c
··· 51 51 #define USB_LCD_CONCURRENT_WRITES 5 52 52 53 53 static struct usb_driver lcd_driver; 54 - static DEFINE_MUTEX(usb_lcd_open_mutex); 55 54 56 55 57 56 static void lcd_delete(struct kref *kref) ··· 68 69 struct usb_lcd *dev; 69 70 struct usb_interface *interface; 70 71 int subminor; 71 - int retval = 0; 72 72 73 73 subminor = iminor(inode); 74 74 75 - mutex_lock(&usb_lcd_open_mutex); 76 75 interface = usb_find_interface(&lcd_driver, subminor); 77 76 if (!interface) { 78 77 err ("USBLCD: %s - error, can't find device for minor %d", 79 78 __FUNCTION__, subminor); 80 - retval = -ENODEV; 81 - goto exit; 79 + return -ENODEV; 82 80 } 83 81 84 82 dev = usb_get_intfdata(interface); 85 - if (!dev) { 86 - retval = -ENODEV; 87 - goto exit; 88 - } 83 + if (!dev) 84 + return -ENODEV; 89 85 90 86 /* increment our usage count for the device */ 91 87 kref_get(&dev->kref); ··· 88 94 /* save our object in the file's private structure */ 89 95 file->private_data = dev; 90 96 91 - exit: 92 - mutex_unlock(&usb_lcd_open_mutex); 93 - return retval; 97 + return 0; 94 98 } 95 99 96 100 static int lcd_release(struct inode *inode, struct file *file) ··· 355 363 struct usb_lcd *dev; 356 364 int minor = interface->minor; 357 365 358 - /* prevent skel_open() from racing skel_disconnect() */ 359 - mutex_lock(&usb_lcd_open_mutex); 360 - 361 366 dev = usb_get_intfdata(interface); 362 367 usb_set_intfdata(interface, NULL); 363 368 364 369 /* give back our minor */ 365 370 usb_deregister_dev(interface, &lcd_class); 366 371 367 - mutex_unlock(&usb_lcd_open_mutex); 368 - 369 372 /* decrement our usage count */ 370 373 kref_put(&dev->kref, lcd_delete); 371 374
-14
drivers/usb/usb-skeleton.c
··· 34 34 }; 35 35 MODULE_DEVICE_TABLE(usb, skel_table); 36 36 37 - /* to prevent a race between open and disconnect */ 38 - static DEFINE_MUTEX(skel_open_lock); 39 - 40 37 41 38 /* Get a minor range for your devices from the usb maintainer */ 42 39 #define USB_SKEL_MINOR_BASE 192 ··· 80 83 81 84 subminor = iminor(inode); 82 85 83 - mutex_lock(&skel_open_lock); 84 86 interface = usb_find_interface(&skel_driver, subminor); 85 87 if (!interface) { 86 - mutex_unlock(&skel_open_lock); 87 88 err ("%s - error, can't find device for minor %d", 88 89 __FUNCTION__, subminor); 89 90 retval = -ENODEV; ··· 90 95 91 96 dev = usb_get_intfdata(interface); 92 97 if (!dev) { 93 - mutex_unlock(&skel_open_lock); 94 98 retval = -ENODEV; 95 99 goto exit; 96 100 } 97 101 98 102 /* increment our usage count for the device */ 99 103 kref_get(&dev->kref); 100 - /* now we can drop the lock */ 101 - mutex_unlock(&skel_open_lock); 102 104 103 105 /* prevent the device from being autosuspended */ 104 106 retval = usb_autopm_get_interface(interface); ··· 360 368 struct usb_skel *dev; 361 369 int minor = interface->minor; 362 370 363 - /* prevent skel_open() from racing skel_disconnect() */ 364 - mutex_lock(&skel_open_lock); 365 - 366 371 dev = usb_get_intfdata(interface); 367 372 usb_set_intfdata(interface, NULL); 368 373 369 374 /* give back our minor */ 370 375 usb_deregister_dev(interface, &skel_class); 371 - mutex_unlock(&skel_open_lock); 372 376 373 377 /* prevent more I/O from starting */ 374 378 mutex_lock(&dev->io_mutex); 375 379 dev->interface = NULL; 376 380 mutex_unlock(&dev->io_mutex); 377 - 378 - 379 381 380 382 /* decrement our usage count */ 381 383 kref_put(&dev->kref, skel_delete);