Commit 7dd9cba5 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

usb: sysfs: make locking interruptible

232275a0 USB: fix substandard locking for the sysfs files
introduced needed locking into sysfs operations on USB devices
It, however, uses uninterruptible sleep and if the error
handling is on extreme cases of sleep lengths of 10s of seconds
are possible. Unless we are removing the device we should use
interruptible sleep.
Signed-off-by: default avatarOliver Neukum <oneukum@suse.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5363de75
...@@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \ ...@@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \
{ \ { \
struct usb_device *udev; \ struct usb_device *udev; \
struct usb_host_config *actconfig; \ struct usb_host_config *actconfig; \
ssize_t rc = 0; \ ssize_t rc; \
\ \
udev = to_usb_device(dev); \ udev = to_usb_device(dev); \
usb_lock_device(udev); \ rc = usb_lock_device_interruptible(udev); \
if (rc < 0) \
return -EINTR; \
actconfig = udev->actconfig; \ actconfig = udev->actconfig; \
if (actconfig) \ if (actconfig) \
rc = sprintf(buf, format_string, \ rc = sprintf(buf, format_string, \
...@@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev, ...@@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev,
{ {
struct usb_device *udev; struct usb_device *udev;
struct usb_host_config *actconfig; struct usb_host_config *actconfig;
ssize_t rc = 0; ssize_t rc;
udev = to_usb_device(dev); udev = to_usb_device(dev);
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
actconfig = udev->actconfig; actconfig = udev->actconfig;
if (actconfig) if (actconfig)
rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
...@@ -64,10 +68,12 @@ static ssize_t configuration_show(struct device *dev, ...@@ -64,10 +68,12 @@ static ssize_t configuration_show(struct device *dev,
{ {
struct usb_device *udev; struct usb_device *udev;
struct usb_host_config *actconfig; struct usb_host_config *actconfig;
ssize_t rc = 0; ssize_t rc;
udev = to_usb_device(dev); udev = to_usb_device(dev);
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
actconfig = udev->actconfig; actconfig = udev->actconfig;
if (actconfig && actconfig->string) if (actconfig && actconfig->string)
rc = sprintf(buf, "%s\n", actconfig->string); rc = sprintf(buf, "%s\n", actconfig->string);
...@@ -84,11 +90,13 @@ static ssize_t bConfigurationValue_store(struct device *dev, ...@@ -84,11 +90,13 @@ static ssize_t bConfigurationValue_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int config, value; int config, value, rc;
if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
return -EINVAL; return -EINVAL;
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
value = usb_set_configuration(udev, config); value = usb_set_configuration(udev, config);
usb_unlock_device(udev); usb_unlock_device(udev);
return (value < 0) ? value : count; return (value < 0) ? value : count;
...@@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \ ...@@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \
int retval; \ int retval; \
\ \
udev = to_usb_device(dev); \ udev = to_usb_device(dev); \
usb_lock_device(udev); \ retval = usb_lock_device_interruptible(udev); \
if (retval < 0) \
return -EINTR; \
retval = sprintf(buf, "%s\n", udev->name); \ retval = sprintf(buf, "%s\n", udev->name); \
usb_unlock_device(udev); \ usb_unlock_device(udev); \
return retval; \ return retval; \
...@@ -227,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev, ...@@ -227,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int val; int val, rc;
if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1) if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
return -EINVAL; return -EINVAL;
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (val) if (val)
udev->quirks |= USB_QUIRK_RESET; udev->quirks |= USB_QUIRK_RESET;
else else
...@@ -297,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr, ...@@ -297,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
int value; int value, rc;
/* Hubs are always enabled for USB_PERSIST */ /* Hubs are always enabled for USB_PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
...@@ -306,7 +318,9 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr, ...@@ -306,7 +318,9 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%d", &value) != 1) if (sscanf(buf, "%d", &value) != 1)
return -EINVAL; return -EINVAL;
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
udev->persist_enabled = !!value; udev->persist_enabled = !!value;
usb_unlock_device(udev); usb_unlock_device(udev);
return count; return count;
...@@ -423,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr, ...@@ -423,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr,
int len = count; int len = count;
char *cp; char *cp;
int rc = count; int rc = count;
int rv;
warn_level(); warn_level();
cp = memchr(buf, '\n', count); cp = memchr(buf, '\n', count);
if (cp) if (cp)
len = cp - buf; len = cp - buf;
usb_lock_device(udev); rv = usb_lock_device_interruptible(udev);
if (rv < 0)
return -EINTR;
if (len == sizeof on_string - 1 && if (len == sizeof on_string - 1 &&
strncmp(buf, on_string, len) == 0) strncmp(buf, on_string, len) == 0)
...@@ -469,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev, ...@@ -469,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
bool value; bool value;
int ret; int ret;
usb_lock_device(udev); ret = usb_lock_device_interruptible(udev);
if (ret < 0)
return -EINTR;
ret = strtobool(buf, &value); ret = strtobool(buf, &value);
...@@ -539,8 +558,11 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, ...@@ -539,8 +558,11 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
const char *p; const char *p;
int rc;
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (udev->usb3_lpm_u1_enabled) if (udev->usb3_lpm_u1_enabled)
p = "enabled"; p = "enabled";
...@@ -558,8 +580,11 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, ...@@ -558,8 +580,11 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
{ {
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
const char *p; const char *p;
int rc;
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (udev->usb3_lpm_u2_enabled) if (udev->usb3_lpm_u2_enabled)
p = "enabled"; p = "enabled";
...@@ -818,14 +843,16 @@ read_descriptors(struct file *filp, struct kobject *kobj, ...@@ -818,14 +843,16 @@ read_descriptors(struct file *filp, struct kobject *kobj,
struct usb_device *udev = to_usb_device(dev); struct usb_device *udev = to_usb_device(dev);
size_t nleft = count; size_t nleft = count;
size_t srclen, n; size_t srclen, n;
int cfgno; int cfgno, rc;
void *src; void *src;
/* The binary attribute begins with the device descriptor. /* The binary attribute begins with the device descriptor.
* Following that are the raw descriptor entries for all the * Following that are the raw descriptor entries for all the
* configurations (config plus subsidiary descriptors). * configurations (config plus subsidiary descriptors).
*/ */
usb_lock_device(udev); rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
nleft > 0; ++cfgno) { nleft > 0; ++cfgno) {
if (cfgno < 0) { if (cfgno < 0) {
...@@ -972,7 +999,9 @@ static ssize_t supports_autosuspend_show(struct device *dev, ...@@ -972,7 +999,9 @@ static ssize_t supports_autosuspend_show(struct device *dev,
{ {
int s; int s;
device_lock(dev); s = device_lock_interruptible(dev);
if (s < 0)
return -EINTR;
/* Devices will be autosuspended even when an interface isn't claimed */ /* Devices will be autosuspended even when an interface isn't claimed */
s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
device_unlock(dev); device_unlock(dev);
......
...@@ -958,6 +958,11 @@ static inline void device_lock(struct device *dev) ...@@ -958,6 +958,11 @@ static inline void device_lock(struct device *dev)
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
} }
static inline int device_lock_interruptible(struct device *dev)
{
return mutex_lock_interruptible(&dev->mutex);
}
static inline int device_trylock(struct device *dev) static inline int device_trylock(struct device *dev)
{ {
return mutex_trylock(&dev->mutex); return mutex_trylock(&dev->mutex);
......
...@@ -641,9 +641,10 @@ extern struct usb_device *usb_hub_find_child(struct usb_device *hdev, ...@@ -641,9 +641,10 @@ extern struct usb_device *usb_hub_find_child(struct usb_device *hdev,
if (!child) continue; else if (!child) continue; else
/* USB device locking */ /* USB device locking */
#define usb_lock_device(udev) device_lock(&(udev)->dev) #define usb_lock_device(udev) device_lock(&(udev)->dev)
#define usb_unlock_device(udev) device_unlock(&(udev)->dev) #define usb_unlock_device(udev) device_unlock(&(udev)->dev)
#define usb_trylock_device(udev) device_trylock(&(udev)->dev) #define usb_lock_device_interruptible(udev) device_lock_interruptible(&(udev)->dev)
#define usb_trylock_device(udev) device_trylock(&(udev)->dev)
extern int usb_lock_device_for_reset(struct usb_device *udev, extern int usb_lock_device_for_reset(struct usb_device *udev,
const struct usb_interface *iface); const struct usb_interface *iface);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment