Re: On the 19th Dec I reported an OOPS when attaching a BeagleBone

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

 



On Wed, 4 Jan 2012, Huajun Li wrote:

> Hi Alan,
>    Is any chance for user to trigger the window if the driver has been
> unregistered?  thanks.

Yes, that possibility does exist.

> How about adding more codes into usb_store_new_id() to find out
> whether the driver is registered while receiving such requests? and
> this could give useful info to user space if the requests fail.

I don't think that's the best approach.  Furthermore, your proposed fix
still contains a race because is_drv_ready() calls put_driver() before
returning.

In order to fix this properly, we have to make sure that 
usb_store_new_id() is mutually exclusive with driver registration and 
unregistration.  The patch below will accomplish that.

However it does leave one problem unsolved.  The udev rule still can 
run too quickly.  Now instead of getting an oops, the rule simply won't 
work.  I don't know how to fix that.

David, can you test this patch in place of the earlier one?

Alan Stern



Index: usb-3.2/drivers/usb/core/driver.c
===================================================================
--- usb-3.2.orig/drivers/usb/core/driver.c
+++ usb-3.2/drivers/usb/core/driver.c
@@ -31,6 +31,10 @@
 
 #include "usb.h"
 
+/* Mutual exclusion for drvwrap->is_registered */
+DEFINE_MUTEX(usb_driver_reg_mutex);
+EXPORT_SYMBOL_GPL(usb_driver_reg_mutex);
+
 
 #ifdef CONFIG_HOTPLUG
 
@@ -815,6 +819,10 @@ int usb_register_device_driver(struct us
 			usbcore_name, retval, new_udriver->name);
 	}
 
+	mutex_lock(&usb_driver_reg_mutex);
+	new_udriver->drvwrap.is_registered = 1;
+	mutex_unlock(&usb_driver_reg_mutex);
+
 	return retval;
 }
 EXPORT_SYMBOL_GPL(usb_register_device_driver);
@@ -831,6 +839,10 @@ void usb_deregister_device_driver(struct
 	pr_info("%s: deregistering device driver %s\n",
 			usbcore_name, udriver->name);
 
+	mutex_lock(&usb_driver_reg_mutex);
+	udriver->drvwrap.is_registered = 0;
+	mutex_unlock(&usb_driver_reg_mutex);
+
 	driver_unregister(&udriver->drvwrap.driver);
 	usbfs_update_special();
 }
@@ -873,6 +885,10 @@ int usb_register_driver(struct usb_drive
 	if (retval)
 		goto out;
 
+	mutex_lock(&usb_driver_reg_mutex);
+	new_driver->drvwrap.is_registered = 1;
+	mutex_unlock(&usb_driver_reg_mutex);
+
 	usbfs_update_special();
 
 	retval = usb_create_newid_file(new_driver);
@@ -917,6 +933,10 @@ void usb_deregister(struct usb_driver *d
 	pr_info("%s: deregistering interface driver %s\n",
 			usbcore_name, driver->name);
 
+	mutex_lock(&usb_driver_reg_mutex);
+	driver->drvwrap.is_registered = 0;
+	mutex_unlock(&usb_driver_reg_mutex);
+
 	usb_remove_removeid_file(driver);
 	usb_remove_newid_file(driver);
 	usb_free_dynids(driver);
Index: usb-3.2/drivers/usb/serial/bus.c
===================================================================
--- usb-3.2.orig/drivers/usb/serial/bus.c
+++ usb-3.2/drivers/usb/serial/bus.c
@@ -119,13 +119,20 @@ static int usb_serial_device_remove(stru
 static ssize_t store_new_id(struct device_driver *driver,
 			    const char *buf, size_t count)
 {
-	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
-	ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
-
-	if (retval >= 0 && usb_drv->usb_driver != NULL)
-		retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
-					  &usb_drv->usb_driver->drvwrap.driver,
+	struct usb_serial_driver *ser_drv = to_usb_serial_driver(driver);
+	struct usb_driver *usb_drv = ser_drv->usb_driver;
+	ssize_t retval = usb_store_new_id(&ser_drv->dynids, driver, buf, count);
+
+	if (retval >= 0 && usb_drv != NULL) {
+		mutex_lock(&usb_driver_reg_mutex);
+		if (usb_drv->drvwrap.is_registered)
+			retval = usb_store_new_id(&usb_drv->dynids,
+					  &usb_drv->drvwrap.driver,
 					  buf, count);
+		else
+			retval = -EAGAIN;
+		mutex_unlock(&usb_driver_reg_mutex);
+	}
 	return retval;
 }
 
@@ -178,7 +185,7 @@ int usb_serial_bus_register(struct usb_s
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
-	free_dynids(driver);
 	driver_unregister(&driver->driver);
+	free_dynids(driver);
 }
 
Index: usb-3.2/include/linux/usb.h
===================================================================
--- usb-3.2.orig/include/linux/usb.h
+++ usb-3.2/include/linux/usb.h
@@ -792,14 +792,18 @@ extern ssize_t usb_store_new_id(struct u
 				struct device_driver *driver,
 				const char *buf, size_t count);
 
+extern struct mutex usb_driver_reg_mutex;
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
  * @for_devices: Non-zero for device drivers, 0 for interface drivers.
+ * @is_registered: The driver is registered (protected by usb_driver_reg_mutex)
  */
 struct usbdrv_wrap {
 	struct device_driver driver;
-	int for_devices;
+	unsigned int for_devices:1;
+	unsigned int is_registered:1;
 };
 
 /**

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux