aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2013-09-24 15:43:39 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-25 20:27:01 -0400
commit232275a089dfd2e77377a85f11d0a4e3ca60e612 (patch)
tree14d96e68ff15d0751996e123ff6c9e7e8ff232b5 /drivers/usb/core
parent9a37a50349c8d6a7adcee21cefae407fb2f8c623 (diff)
USB: fix substandard locking for the sysfs files
This patch straightens out some locking issues in the USB sysfs interface: Deauthorization will destroy existing configurations. Attributes that read from udev->actconfig need to lock the device to prevent races. Likewise for the rawdescriptor values. Attributes that access an interface's current alternate setting should use ACCESS_ONCE() to obtain the cur_altsetting pointer, to protect against concurrent altsetting changes. The supports_autosuspend() attribute routine accesses values from an interface's driver, so it should lock the interface (rather than the usb_device) to protect against concurrent unbinds. Once this is done, the routine can be simplified considerably. Scalar values that are stored directly in the usb_device structure are always available. They do not require any locking. The same is true of the cached interface string descriptor, because it is not deallocated until the usb_host_interface structure is destroyed. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/sysfs.c53
1 files changed, 26 insertions, 27 deletions
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 6d2c8edb1ffe..59cb5f99467a 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -23,14 +23,16 @@ static ssize_t field##_show(struct device *dev, \
23{ \ 23{ \
24 struct usb_device *udev; \ 24 struct usb_device *udev; \
25 struct usb_host_config *actconfig; \ 25 struct usb_host_config *actconfig; \
26 ssize_t rc = 0; \
26 \ 27 \
27 udev = to_usb_device(dev); \ 28 udev = to_usb_device(dev); \
29 usb_lock_device(udev); \
28 actconfig = udev->actconfig; \ 30 actconfig = udev->actconfig; \
29 if (actconfig) \ 31 if (actconfig) \
30 return sprintf(buf, format_string, \ 32 rc = sprintf(buf, format_string, \
31 actconfig->desc.field); \ 33 actconfig->desc.field); \
32 else \ 34 usb_unlock_device(udev); \
33 return 0; \ 35 return rc; \
34} \ 36} \
35 37
36#define usb_actconfig_attr(field, format_string) \ 38#define usb_actconfig_attr(field, format_string) \
@@ -45,12 +47,15 @@ static ssize_t bMaxPower_show(struct device *dev,
45{ 47{
46 struct usb_device *udev; 48 struct usb_device *udev;
47 struct usb_host_config *actconfig; 49 struct usb_host_config *actconfig;
50 ssize_t rc = 0;
48 51
49 udev = to_usb_device(dev); 52 udev = to_usb_device(dev);
53 usb_lock_device(udev);
50 actconfig = udev->actconfig; 54 actconfig = udev->actconfig;
51 if (!actconfig) 55 if (actconfig)
52 return 0; 56 rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
53 return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); 57 usb_unlock_device(udev);
58 return rc;
54} 59}
55static DEVICE_ATTR_RO(bMaxPower); 60static DEVICE_ATTR_RO(bMaxPower);
56 61
@@ -59,12 +64,15 @@ static ssize_t configuration_show(struct device *dev,
59{ 64{
60 struct usb_device *udev; 65 struct usb_device *udev;
61 struct usb_host_config *actconfig; 66 struct usb_host_config *actconfig;
67 ssize_t rc = 0;
62 68
63 udev = to_usb_device(dev); 69 udev = to_usb_device(dev);
70 usb_lock_device(udev);
64 actconfig = udev->actconfig; 71 actconfig = udev->actconfig;
65 if ((!actconfig) || (!actconfig->string)) 72 if (actconfig && actconfig->string)
66 return 0; 73 rc = sprintf(buf, "%s\n", actconfig->string);
67 return sprintf(buf, "%s\n", actconfig->string); 74 usb_unlock_device(udev);
75 return rc;
68} 76}
69static DEVICE_ATTR_RO(configuration); 77static DEVICE_ATTR_RO(configuration);
70 78
@@ -764,6 +772,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
764 * Following that are the raw descriptor entries for all the 772 * Following that are the raw descriptor entries for all the
765 * configurations (config plus subsidiary descriptors). 773 * configurations (config plus subsidiary descriptors).
766 */ 774 */
775 usb_lock_device(udev);
767 for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && 776 for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
768 nleft > 0; ++cfgno) { 777 nleft > 0; ++cfgno) {
769 if (cfgno < 0) { 778 if (cfgno < 0) {
@@ -784,6 +793,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
784 off -= srclen; 793 off -= srclen;
785 } 794 }
786 } 795 }
796 usb_unlock_device(udev);
787 return count - nleft; 797 return count - nleft;
788} 798}
789 799
@@ -870,9 +880,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
870 char *string; 880 char *string;
871 881
872 intf = to_usb_interface(dev); 882 intf = to_usb_interface(dev);
873 string = intf->cur_altsetting->string; 883 string = ACCESS_ONCE(intf->cur_altsetting->string);
874 barrier(); /* The altsetting might change! */
875
876 if (!string) 884 if (!string)
877 return 0; 885 return 0;
878 return sprintf(buf, "%s\n", string); 886 return sprintf(buf, "%s\n", string);
@@ -888,7 +896,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
888 896
889 intf = to_usb_interface(dev); 897 intf = to_usb_interface(dev);
890 udev = interface_to_usbdev(intf); 898 udev = interface_to_usbdev(intf);
891 alt = intf->cur_altsetting; 899 alt = ACCESS_ONCE(intf->cur_altsetting);
892 900
893 return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" 901 return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
894 "ic%02Xisc%02Xip%02Xin%02X\n", 902 "ic%02Xisc%02Xip%02Xin%02X\n",
@@ -909,23 +917,14 @@ static ssize_t supports_autosuspend_show(struct device *dev,
909 struct device_attribute *attr, 917 struct device_attribute *attr,
910 char *buf) 918 char *buf)
911{ 919{
912 struct usb_interface *intf; 920 int s;
913 struct usb_device *udev;
914 int ret;
915 921
916 intf = to_usb_interface(dev); 922 device_lock(dev);
917 udev = interface_to_usbdev(intf);
918
919 usb_lock_device(udev);
920 /* Devices will be autosuspended even when an interface isn't claimed */ 923 /* Devices will be autosuspended even when an interface isn't claimed */
921 if (!intf->dev.driver || 924 s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
922 to_usb_driver(intf->dev.driver)->supports_autosuspend) 925 device_unlock(dev);
923 ret = sprintf(buf, "%u\n", 1);
924 else
925 ret = sprintf(buf, "%u\n", 0);
926 usb_unlock_device(udev);
927 926
928 return ret; 927 return sprintf(buf, "%u\n", s);
929} 928}
930static DEVICE_ATTR_RO(supports_autosuspend); 929static DEVICE_ATTR_RO(supports_autosuspend);
931 930