Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+49 −20
Original line number Diff line number Diff line
@@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \
{									\
	struct usb_device *udev;					\
	struct usb_host_config *actconfig;				\
	ssize_t rc = 0;							\
	ssize_t rc;							\
									\
	udev = to_usb_device(dev);					\
	usb_lock_device(udev);						\
	rc = usb_lock_device_interruptible(udev);			\
	if (rc < 0)							\
		return -EINTR;						\
	actconfig = udev->actconfig;					\
	if (actconfig)							\
		rc = sprintf(buf, format_string,			\
@@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev,
{
	struct usb_device *udev;
	struct usb_host_config *actconfig;
	ssize_t rc = 0;
	ssize_t rc;

	udev = to_usb_device(dev);
	usb_lock_device(udev);
	rc = usb_lock_device_interruptible(udev);
	if (rc < 0)
		return -EINTR;
	actconfig = udev->actconfig;
	if (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_host_config *actconfig;
	ssize_t rc = 0;
	ssize_t rc;

	udev = to_usb_device(dev);
	usb_lock_device(udev);
	rc = usb_lock_device_interruptible(udev);
	if (rc < 0)
		return -EINTR;
	actconfig = udev->actconfig;
	if (actconfig && 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)
{
	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)
		return -EINVAL;
	usb_lock_device(udev);
	rc = usb_lock_device_interruptible(udev);
	if (rc < 0)
		return -EINTR;
	value = usb_set_configuration(udev, config);
	usb_unlock_device(udev);
	return (value < 0) ? value : count;
@@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \
	int retval;							\
									\
	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);			\
	usb_unlock_device(udev);					\
	return retval;							\
@@ -227,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev,
				      const char *buf, size_t count)
{
	struct usb_device	*udev = to_usb_device(dev);
	int			val;
	int			val, rc;

	if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
		return -EINVAL;
	usb_lock_device(udev);
	rc = usb_lock_device_interruptible(udev);
	if (rc < 0)
		return -EINTR;
	if (val)
		udev->quirks |= USB_QUIRK_RESET;
	else
@@ -297,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
{
	struct usb_device *udev = to_usb_device(dev);
	int value;
	int value, rc;

	/* Hubs are always enabled for USB_PERSIST */
	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)
		return -EINVAL;

	usb_lock_device(udev);
	rc = usb_lock_device_interruptible(udev);
	if (rc < 0)
		return -EINTR;
	udev->persist_enabled = !!value;
	usb_unlock_device(udev);
	return count;
@@ -423,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr,
	int len = count;
	char *cp;
	int rc = count;
	int rv;

	warn_level();
	cp = memchr(buf, '\n', count);
	if (cp)
		len = cp - buf;

	usb_lock_device(udev);
	rv = usb_lock_device_interruptible(udev);
	if (rv < 0)
		return -EINTR;

	if (len == sizeof on_string - 1 &&
			strncmp(buf, on_string, len) == 0)
@@ -469,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
	bool value;
	int ret;

	usb_lock_device(udev);
	ret = usb_lock_device_interruptible(udev);
	if (ret < 0)
		return -EINTR;

	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);
	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)
		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);
	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)
		p = "enabled";
@@ -818,14 +843,16 @@ read_descriptors(struct file *filp, struct kobject *kobj,
	struct usb_device *udev = to_usb_device(dev);
	size_t nleft = count;
	size_t srclen, n;
	int cfgno;
	int cfgno, rc;
	void *src;

	/* The binary attribute begins with the device descriptor.
	 * Following that are the raw descriptor entries for all the
	 * 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 &&
			nleft > 0; ++cfgno) {
		if (cfgno < 0) {
@@ -972,7 +999,9 @@ static ssize_t supports_autosuspend_show(struct device *dev,
{
	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 */
	s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
	device_unlock(dev);
+5 −0
Original line number Diff line number Diff line
@@ -958,6 +958,11 @@ static inline void device_lock(struct device *dev)
	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)
{
	return mutex_trylock(&dev->mutex);
+4 −3
Original line number Diff line number Diff line
@@ -643,6 +643,7 @@ extern struct usb_device *usb_hub_find_child(struct usb_device *hdev,
/* USB device locking */
#define usb_lock_device(udev)			device_lock(&(udev)->dev)
#define usb_unlock_device(udev)			device_unlock(&(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,
				     const struct usb_interface *iface);