patch "USB: legousbtower: fix deadlock on disconnect" added to usb-linus
Subsystems (3)
This is a note to let you know that I've just added the patch titled
USB: legousbtower: fix deadlock on disconnect
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From 33a7813219f208f4952ece60ee255fd983272dec Mon Sep 17 00:00:00 2001
From: Johan Hovold <[email protected]>
Date: Thu, 19 Sep 2019 10:30:37 +0200
Subject: USB: legousbtower: fix deadlock on disconnect
Fix a potential deadlock if disconnect races with open.
Since commit d4ead16f50f9 ("USB: prevent char device open/deregister race") core holds an rw-semaphore while open is called and when releasing the minor number during deregistration. This can lead to an ABBA deadlock if a driver takes a lock in open which it also holds during deregistration.
This effectively reverts commit 78663ecc344b ("USB: disconnect open race in legousbtower") which needlessly introduced this issue after a generic fix for this race had been added to core by commit d4ead16f50f9 ("USB:
prevent char device open/deregister race").
--- drivers/usb/misc/legousbtower.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-)
drivers/usb/misc/legousbtower.c +2 -17
@@ -179,7 +179,6 @@ static const struct usb_device_id tower_table[] = { };MODULE_DEVICE_TABLE (usb, tower_table); -static DEFINE_MUTEX (open_disc_mutex);#define LEGO_USB_TOWER_MINOR_BASE 160
@@ -332,18 +331,14 @@ static int tower_open (struct inode *inode, struct file *file) goto exit; } -mutex_lock (&open_disc_mutex); dev =usb_get_intfdata (interface); -if (!dev) { -mutex_unlock (&open_disc_mutex); retval = -ENODEV ; goto exit; }/* lock this device */ if (mutex_lock_interruptible (&dev->lock)) { -mutex_unlock (&open_disc_mutex); retval = -ERESTARTSYS ; goto exit; }
@@ -351,12 +346,10 @@ static int tower_open (struct inode *inode, struct file *file)/* allow opening only once */ if (dev->open_count) { -mutex_unlock (&open_disc_mutex); retval = -EBUSY ; goto unlock_exit; } dev->open_count =1 ; -mutex_unlock (&open_disc_mutex);/* reset the tower */ result = usb_control_msg (dev->udev,
@@ -423,10 +416,9 @@ static int tower_release (struct inode *inode, struct file *file)if (dev ==NULL ) { retval = -ENODEV ; - goto exit_nolock; + goto exit; } -mutex_lock (&open_disc_mutex);if (mutex_lock_interruptible (&dev->lock)) { retval = -ERESTARTSYS ; goto exit;
@@ -456,10 +448,7 @@ static int tower_release (struct inode *inode, struct file *file) unlock_exit:mutex_unlock (&dev->lock); - exit: -mutex_unlock (&open_disc_mutex); -exit_nolock:return retval; }
@@ -912,7 +901,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_deviceif (retval) {/* something prevented us from registering this driver */ dev_err (idev,"Not able to get a minor for this device.\n" ); -usb_set_intfdata (interface,NULL ); goto error; } dev->minor = interface->minor;
@@ -944,16 +932,13 @@ static void tower_disconnect (struct usb_interface *interface)int minor; dev =usb_get_intfdata (interface); -mutex_lock (&open_disc_mutex); -usb_set_intfdata (interface,NULL ); minor = dev->minor; -/* give back our minor */ +/* give back our minor and prevent further open() */ usb_deregister_dev (interface, &tower_class);mutex_lock (&dev->lock); -mutex_unlock (&open_disc_mutex);/* if the device is not opened, then we clean up right now */ if (!dev->open_count) {
Signature · 1 line
2.23.0