USB: race fixes for usb-serial, step 2
- take BKL before looking up a driver to associate with a device to make sure the module is not unloaded after looking up but before association & bumping module count Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
34ef50e5b1
commit
4b10f0f3a0
|
@ -685,14 +685,17 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
int num_ports = 0;
|
int num_ports = 0;
|
||||||
int max_endpoints;
|
int max_endpoints;
|
||||||
|
|
||||||
|
lock_kernel(); /* guard against unloading a serial driver module */
|
||||||
type = search_serial_device(interface);
|
type = search_serial_device(interface);
|
||||||
if (!type) {
|
if (!type) {
|
||||||
|
unlock_kernel();
|
||||||
dbg("none matched");
|
dbg("none matched");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
serial = create_serial (dev, interface, type);
|
serial = create_serial (dev, interface, type);
|
||||||
if (!serial) {
|
if (!serial) {
|
||||||
|
unlock_kernel();
|
||||||
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
|
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -702,6 +705,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
const struct usb_device_id *id;
|
const struct usb_device_id *id;
|
||||||
|
|
||||||
if (!try_module_get(type->driver.owner)) {
|
if (!try_module_get(type->driver.owner)) {
|
||||||
|
unlock_kernel();
|
||||||
dev_err(&interface->dev, "module get failed, exiting\n");
|
dev_err(&interface->dev, "module get failed, exiting\n");
|
||||||
kfree (serial);
|
kfree (serial);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -712,6 +716,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
module_put(type->driver.owner);
|
module_put(type->driver.owner);
|
||||||
|
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
unlock_kernel();
|
||||||
dbg ("sub driver rejected device");
|
dbg ("sub driver rejected device");
|
||||||
kfree (serial);
|
kfree (serial);
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -781,6 +786,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
* properly during a later invocation of usb_serial_probe
|
* properly during a later invocation of usb_serial_probe
|
||||||
*/
|
*/
|
||||||
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
||||||
|
unlock_kernel();
|
||||||
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
||||||
kfree (serial);
|
kfree (serial);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -796,6 +802,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
if (type == &usb_serial_generic_device) {
|
if (type == &usb_serial_generic_device) {
|
||||||
num_ports = num_bulk_out;
|
num_ports = num_bulk_out;
|
||||||
if (num_ports == 0) {
|
if (num_ports == 0) {
|
||||||
|
unlock_kernel();
|
||||||
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
|
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
|
||||||
kfree (serial);
|
kfree (serial);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -806,6 +813,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
/* if this device type has a calc_num_ports function, call it */
|
/* if this device type has a calc_num_ports function, call it */
|
||||||
if (type->calc_num_ports) {
|
if (type->calc_num_ports) {
|
||||||
if (!try_module_get(type->driver.owner)) {
|
if (!try_module_get(type->driver.owner)) {
|
||||||
|
unlock_kernel();
|
||||||
dev_err(&interface->dev, "module get failed, exiting\n");
|
dev_err(&interface->dev, "module get failed, exiting\n");
|
||||||
kfree (serial);
|
kfree (serial);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -831,6 +839,8 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
max_endpoints = max(max_endpoints, num_interrupt_out);
|
max_endpoints = max(max_endpoints, num_interrupt_out);
|
||||||
max_endpoints = max(max_endpoints, (int)serial->num_ports);
|
max_endpoints = max(max_endpoints, (int)serial->num_ports);
|
||||||
serial->num_port_pointers = max_endpoints;
|
serial->num_port_pointers = max_endpoints;
|
||||||
|
unlock_kernel();
|
||||||
|
|
||||||
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
|
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
|
||||||
for (i = 0; i < max_endpoints; ++i) {
|
for (i = 0; i < max_endpoints; ++i) {
|
||||||
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
|
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
|
||||||
|
@ -1187,7 +1197,7 @@ static void fixup_generic(struct usb_serial_driver *device)
|
||||||
set_to_generic_if_null(device, shutdown);
|
set_to_generic_if_null(device, shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_serial_register(struct usb_serial_driver *driver)
|
int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -1211,7 +1221,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void usb_serial_deregister(struct usb_serial_driver *device)
|
void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
|
||||||
{
|
{
|
||||||
info("USB Serial deregistering driver %s", device->description);
|
info("USB Serial deregistering driver %s", device->description);
|
||||||
list_del(&device->driver_list);
|
list_del(&device->driver_list);
|
||||||
|
|
Loading…
Reference in a new issue