Re: All USB tools hang when one descriptor read fails and needs to timeout

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Feb 07, 2023 at 12:52:16PM -0500, Alan Stern wrote:
> On Tue, Feb 07, 2023 at 09:25:55AM +0100, Troels Liebe Bentsen wrote:
> > Hi again,
> > 
> > Did a bit more testing and found another lock that would be nice to remove,
> > the /dev/bus/usb/$BUS/$DEV file for the hub is also locked:
> > 
> > Bus 003 Device 016: ID 1a40:0201 Terminus Technology Inc. FE 2.1 7-port Hub
> > 
> > strace lsusb -v
> > ...
> > openat(AT_FDCWD, "/dev/bus/usb/003/016", O_RDWR|O_CLOEXEC...
> > 
> > The openat can not be canceled from userspace and even kill -9 won't stop
> > the process until the descriptor read times out.
> 
> Yes, that really should be an interruptible lock.  In fact, all the 
> locks connected with usbfs should be interruptible.
> 
> However, it can't be eliminated entirely.  This is a case where two 
> things end up being mutually exclusive with each other because they both 
> need to be mutually exclusive with a third thing.  In other words, 
> opening a hub's usbfs file and probing a hub's children both have to be 
> mutually exclusive with disconnecting the hub.  The three pathways all 
> use the device lock for this purpose, so they are all mutually exclusive 
> with each other.
> 
> > Also managed to get "lsusb -v" to hang in an unkillable way even after
> > I unplugged the device and hub:
> >
> > ) = 1 ([{fd=5, revents=POLLIN}])
> > ioctl(8, USBDEVFS_DISCARDURB
> 
> Making these lock calls interruptible should fix this problem, right?

Here's a patch.  It should fix most of these problems.

Alan Stern



Index: usb-devel/drivers/usb/core/devio.c
===================================================================
--- usb-devel.orig/drivers/usb/core/devio.c
+++ usb-devel/drivers/usb/core/devio.c
@@ -303,13 +303,15 @@ static ssize_t usbdev_read(struct file *
 {
 	struct usb_dev_state *ps = file->private_data;
 	struct usb_device *dev = ps->dev;
-	ssize_t ret = 0;
+	ssize_t ret;
 	unsigned len;
 	loff_t pos;
 	int i;
 
 	pos = *ppos;
-	usb_lock_device(dev);
+	ret = usb_lock_device_interruptible(dev);
+	if (ret < 0)
+		return ret;
 	if (!connected(ps)) {
 		ret = -ENODEV;
 		goto err;
@@ -1039,7 +1041,9 @@ static int usbdev_open(struct inode *ino
 	if (!dev)
 		goto out_free_ps;
 
-	usb_lock_device(dev);
+	ret = usb_lock_device_interruptible(dev);
+	if (ret < 0)
+		goto out_put_device;
 	if (dev->state == USB_STATE_NOTATTACHED)
 		goto out_unlock_device;
 
@@ -1071,6 +1075,7 @@ static int usbdev_open(struct inode *ino
 
  out_unlock_device:
 	usb_unlock_device(dev);
+ out_put_device:
 	usb_put_dev(dev);
  out_free_ps:
 	kfree(ps);
@@ -2591,14 +2596,17 @@ static long usbdev_do_ioctl(struct file
 	struct usb_dev_state *ps = file->private_data;
 	struct inode *inode = file_inode(file);
 	struct usb_device *dev = ps->dev;
-	int ret = -ENOTTY;
+	int ret;
 
 	if (!(file->f_mode & FMODE_WRITE))
 		return -EPERM;
 
-	usb_lock_device(dev);
+	ret = usb_lock_device_interruptible(dev);
+	if (ret < 0)
+		return ret;
 
 	/* Reap operations are allowed even after disconnection */
+	ret = -ENOTTY;
 	switch (cmd) {
 	case USBDEVFS_REAPURB:
 		snoop(&dev->dev, "%s: REAPURB\n", __func__);




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux