Skip to content

Commit

Permalink
USB: make single lock for all usb dynamic id lists
Browse files Browse the repository at this point in the history
There are a number of places where we accidentally pass in a constant
structure to later cast it off to a dynamic one, and then attempt to
grab a lock on it, which is not a good idea.  To help resolve this, move
the dynamic id lock out of the dynamic id structure for the driver and
into one single lock for all USB dynamic ids.  As this lock should never
have any real contention (it's only every accessed when a device is
added or removed, which is always serialized) there should not be any
difference except for some memory savings.

Note, this just converts the existing use of the dynamic id lock to the
new static lock, there is one place that is accessing the dynamic id
list without grabbing the lock, that will be fixed up in a follow-on
change.

Cc: Johan Hovold <[email protected]>
Cc: Herve Codina <[email protected]>
Cc: Rob Herring <[email protected]>
Cc: Alan Stern <[email protected]>
Cc: Grant Grundler <[email protected]>
Cc: Oliver Neukum <[email protected]>
Cc: Yajun Deng <[email protected]>
Cc: Douglas Anderson <[email protected]>
Cc: [email protected]
Link: https://lore.kernel.org/r/2024111322-kindly-finalist-d247@gregkh
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
gregkh committed Nov 14, 2024
1 parent 528ea1a commit 0b3144d
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 17 deletions.
3 changes: 3 additions & 0 deletions drivers/usb/common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
struct dentry *usb_debug_root;
EXPORT_SYMBOL_GPL(usb_debug_root);

DEFINE_MUTEX(usb_dynids_lock);
EXPORT_SYMBOL_GPL(usb_dynids_lock);

static int __init usb_common_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL);
Expand Down
15 changes: 5 additions & 10 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
}
}

spin_lock(&dynids->lock);
mutex_lock(&usb_dynids_lock);
list_add_tail(&dynid->node, &dynids->list);
spin_unlock(&dynids->lock);
mutex_unlock(&usb_dynids_lock);

retval = driver_attach(driver);

Expand Down Expand Up @@ -160,7 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
if (fields < 2)
return -EINVAL;

spin_lock(&usb_driver->dynids.lock);
guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
struct usb_device_id *id = &dynid->id;

Expand All @@ -171,7 +171,6 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
break;
}
}
spin_unlock(&usb_driver->dynids.lock);
return count;
}

Expand Down Expand Up @@ -220,27 +219,24 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
{
struct usb_dynid *dynid, *n;

spin_lock(&usb_drv->dynids.lock);
guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
spin_unlock(&usb_drv->dynids.lock);
}

static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
struct usb_driver *drv)
{
struct usb_dynid *dynid;

spin_lock(&drv->dynids.lock);
guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (usb_match_one_id(intf, &dynid->id)) {
spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
spin_unlock(&drv->dynids.lock);
return NULL;
}

Expand Down Expand Up @@ -1076,7 +1072,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
new_driver->driver.owner = owner;
new_driver->driver.mod_name = mod_name;
new_driver->driver.dev_groups = new_driver->dev_groups;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);

retval = driver_register(&new_driver->driver);
Expand Down
4 changes: 1 addition & 3 deletions drivers/usb/serial/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,11 @@ static void free_dynids(struct usb_serial_driver *drv)
{
struct usb_dynid *dynid, *n;

spin_lock(&drv->dynids.lock);
guard(mutex)(&usb_dynids_lock);
list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
spin_unlock(&drv->dynids.lock);
}

const struct bus_type usb_serial_bus_type = {
Expand All @@ -157,7 +156,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;

driver->driver.bus = &usb_serial_bus_type;
spin_lock_init(&driver->dynids.lock);
INIT_LIST_HEAD(&driver->dynids.list);

retval = driver_register(&driver->driver);
Expand Down
4 changes: 1 addition & 3 deletions drivers/usb/serial/usb-serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,12 @@ static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
{
struct usb_dynid *dynid;

spin_lock(&drv->dynids.lock);
guard(mutex)(&usb_dynids_lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (usb_match_one_id(intf, &dynid->id)) {
spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
spin_unlock(&drv->dynids.lock);
return NULL;
}

Expand Down
2 changes: 1 addition & 1 deletion include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1129,8 +1129,8 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size)
/* ----------------------------------------------------------------------- */

/* Stuff for dynamic usb ids */
extern struct mutex usb_dynids_lock;
struct usb_dynids {
spinlock_t lock;
struct list_head list;
};

Expand Down

0 comments on commit 0b3144d

Please sign in to comment.