diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2010-01-08 12:56:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-02 17:54:08 -0500 |
commit | 62e299e61a6ffe8131fa85a984c3058b68586f5d (patch) | |
tree | d10709c5b5e6d280e1329c7ed4f30f990246893e /drivers/usb/core/devio.c | |
parent | 0f3dda9f7ff2db8dbf4d6fbab4d4438251446002 (diff) |
USB: change locking for device-level autosuspend
This patch (as1323) changes the locking requirements for
usb_autosuspend_device(), usb_autoresume_device(), and
usb_try_autosuspend_device(). This isn't a very important change;
mainly it's meant to make the locking more uniform.
The most tricky part of the patch involves changes to usbdev_open().
To avoid an ABBA locking problem, it was necessary to reduce the
region protected by usbfs_mutex. Since that mutex now protects only
against simultaneous open and remove, this posed no difficulty -- its
scope was larger than necessary.
And it turns out that usbfs_mutex is no longer needed in
usbdev_release() at all. The list of usbfs "ps" structures is now
protected by the device lock instead of by usbfs_mutex.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 431d17287a86..825e0abfed0a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -654,19 +654,21 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
654 | int ret; | 654 | int ret; |
655 | 655 | ||
656 | lock_kernel(); | 656 | lock_kernel(); |
657 | /* Protect against simultaneous removal or release */ | ||
658 | mutex_lock(&usbfs_mutex); | ||
659 | 657 | ||
660 | ret = -ENOMEM; | 658 | ret = -ENOMEM; |
661 | ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); | 659 | ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); |
662 | if (!ps) | 660 | if (!ps) |
663 | goto out; | 661 | goto out_free_ps; |
664 | 662 | ||
665 | ret = -ENODEV; | 663 | ret = -ENODEV; |
666 | 664 | ||
665 | /* Protect against simultaneous removal or release */ | ||
666 | mutex_lock(&usbfs_mutex); | ||
667 | |||
667 | /* usbdev device-node */ | 668 | /* usbdev device-node */ |
668 | if (imajor(inode) == USB_DEVICE_MAJOR) | 669 | if (imajor(inode) == USB_DEVICE_MAJOR) |
669 | dev = usbdev_lookup_by_devt(inode->i_rdev); | 670 | dev = usbdev_lookup_by_devt(inode->i_rdev); |
671 | |||
670 | #ifdef CONFIG_USB_DEVICEFS | 672 | #ifdef CONFIG_USB_DEVICEFS |
671 | /* procfs file */ | 673 | /* procfs file */ |
672 | if (!dev) { | 674 | if (!dev) { |
@@ -678,13 +680,19 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
678 | dev = NULL; | 680 | dev = NULL; |
679 | } | 681 | } |
680 | #endif | 682 | #endif |
681 | if (!dev || dev->state == USB_STATE_NOTATTACHED) | 683 | mutex_unlock(&usbfs_mutex); |
682 | goto out; | 684 | |
685 | if (!dev) | ||
686 | goto out_free_ps; | ||
687 | |||
688 | usb_lock_device(dev); | ||
689 | if (dev->state == USB_STATE_NOTATTACHED) | ||
690 | goto out_unlock_device; | ||
691 | |||
683 | ret = usb_autoresume_device(dev); | 692 | ret = usb_autoresume_device(dev); |
684 | if (ret) | 693 | if (ret) |
685 | goto out; | 694 | goto out_unlock_device; |
686 | 695 | ||
687 | ret = 0; | ||
688 | ps->dev = dev; | 696 | ps->dev = dev; |
689 | ps->file = file; | 697 | ps->file = file; |
690 | spin_lock_init(&ps->lock); | 698 | spin_lock_init(&ps->lock); |
@@ -702,14 +710,17 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
702 | smp_wmb(); | 710 | smp_wmb(); |
703 | list_add_tail(&ps->list, &dev->filelist); | 711 | list_add_tail(&ps->list, &dev->filelist); |
704 | file->private_data = ps; | 712 | file->private_data = ps; |
713 | usb_unlock_device(dev); | ||
705 | snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current), | 714 | snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current), |
706 | current->comm); | 715 | current->comm); |
707 | out: | 716 | unlock_kernel(); |
708 | if (ret) { | 717 | return ret; |
709 | kfree(ps); | 718 | |
710 | usb_put_dev(dev); | 719 | out_unlock_device: |
711 | } | 720 | usb_unlock_device(dev); |
712 | mutex_unlock(&usbfs_mutex); | 721 | usb_put_dev(dev); |
722 | out_free_ps: | ||
723 | kfree(ps); | ||
713 | unlock_kernel(); | 724 | unlock_kernel(); |
714 | return ret; | 725 | return ret; |
715 | } | 726 | } |
@@ -724,10 +735,7 @@ static int usbdev_release(struct inode *inode, struct file *file) | |||
724 | usb_lock_device(dev); | 735 | usb_lock_device(dev); |
725 | usb_hub_release_all_ports(dev, ps); | 736 | usb_hub_release_all_ports(dev, ps); |
726 | 737 | ||
727 | /* Protect against simultaneous open */ | ||
728 | mutex_lock(&usbfs_mutex); | ||
729 | list_del_init(&ps->list); | 738 | list_del_init(&ps->list); |
730 | mutex_unlock(&usbfs_mutex); | ||
731 | 739 | ||
732 | for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); | 740 | for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); |
733 | ifnum++) { | 741 | ifnum++) { |