usb: sysfs: make locking interruptible

232275a 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: Oliver Neukum <oneukum@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Oliver Neukum 2016-01-21 15:18:47 +01:00 committed by Greg Kroah-Hartman
parent 5363de7530
commit 7dd9cba5bb
3 changed files with 58 additions and 23 deletions

View file

@ -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,
{ {
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,
{ {
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,
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, \
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,
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,
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,
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,
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,
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,
{ {
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,
{ {
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,
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,
{ {
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);

View file

@ -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);

View file

@ -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);