Commit ba809e8a authored by Patrick Mochel's avatar Patrick Mochel

driver model: replace rwlock in struct bus_type with a rwsem.

Synchronize all walks of the device and driver lists of a bus with an rwsem wrapped
around the entire iterator, instead of using device_lock and dropping it after we 
grabbed each node. 

Note this also prevents deadlock when walking the list of drivers and calling 
get_driver(), since get_driver() tries to take device_lock while we already have it
held.
parent 1067efac
...@@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data, ...@@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data,
int error = 0; int error = 0;
get_bus(bus); get_bus(bus);
spin_lock(&device_lock); down_write(&bus->rwsem);
list_for_each(node,&bus->devices) { list_for_each(node,&bus->devices) {
struct device * dev = get_device_locked(to_dev(node)); struct device * dev = get_device(to_dev(node));
if (dev) { if (dev) {
spin_unlock(&device_lock);
error = callback(dev,data); error = callback(dev,data);
if (prev) if (prev)
put_device(prev); put_device(prev);
prev = dev; prev = dev;
spin_lock(&device_lock);
if (error) if (error)
break; break;
} }
} }
spin_unlock(&device_lock);
if (prev) if (prev)
put_device(prev); put_device(prev);
up_write(&bus->rwsem);
put_bus(bus); put_bus(bus);
return error; return error;
} }
...@@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data, ...@@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
/* pin bus in memory */ /* pin bus in memory */
get_bus(bus); get_bus(bus);
down_write(&bus->rwsem);
spin_lock(&device_lock);
list_for_each(node,&bus->drivers) { list_for_each(node,&bus->drivers) {
struct device_driver * drv = get_driver(to_drv(node)); struct device_driver * drv = get_driver(to_drv(node));
if (drv) { if (drv) {
spin_unlock(&device_lock);
error = callback(drv,data); error = callback(drv,data);
if (prev) if (prev)
put_driver(prev); put_driver(prev);
prev = drv; prev = drv;
spin_lock(&device_lock);
if (error) if (error)
break; break;
} }
} }
spin_unlock(&device_lock);
if (prev) if (prev)
put_driver(prev); put_driver(prev);
up_write(&bus->rwsem);
put_bus(bus); put_bus(bus);
return error; return error;
} }
...@@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data, ...@@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data,
int bus_add_device(struct device * dev) int bus_add_device(struct device * dev)
{ {
if (dev->bus) { if (dev->bus) {
down_write(&dev->bus->rwsem);
pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
get_bus(dev->bus); get_bus(dev->bus);
spin_lock(&device_lock);
list_add_tail(&dev->bus_list,&dev->bus->devices); list_add_tail(&dev->bus_list,&dev->bus->devices);
spin_unlock(&device_lock); up_write(&dev->bus->rwsem);
device_bus_link(dev); device_bus_link(dev);
} }
return 0; return 0;
...@@ -131,7 +126,10 @@ int bus_add_device(struct device * dev) ...@@ -131,7 +126,10 @@ int bus_add_device(struct device * dev)
void bus_remove_device(struct device * dev) void bus_remove_device(struct device * dev)
{ {
if (dev->bus) { if (dev->bus) {
down_write(&dev->bus->rwsem);
list_del_init(&dev->bus_list);
device_remove_symlink(&dev->bus->device_dir,dev->bus_id); device_remove_symlink(&dev->bus->device_dir,dev->bus_id);
up_write(&dev->bus->rwsem);
put_bus(dev->bus); put_bus(dev->bus);
} }
} }
...@@ -160,7 +158,7 @@ void put_bus(struct bus_type * bus) ...@@ -160,7 +158,7 @@ void put_bus(struct bus_type * bus)
int bus_register(struct bus_type * bus) int bus_register(struct bus_type * bus)
{ {
rwlock_init(&bus->lock); init_rwsem(&bus->rwsem);
INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers); INIT_LIST_HEAD(&bus->drivers);
atomic_set(&bus->refcount,2); atomic_set(&bus->refcount,2);
......
...@@ -263,7 +263,6 @@ void put_device(struct device * dev) ...@@ -263,7 +263,6 @@ void put_device(struct device * dev)
return; return;
list_del_init(&dev->node); list_del_init(&dev->node);
list_del_init(&dev->g_list); list_del_init(&dev->g_list);
list_del_init(&dev->bus_list);
list_del_init(&dev->driver_list); list_del_init(&dev->driver_list);
spin_unlock(&device_lock); spin_unlock(&device_lock);
......
...@@ -54,7 +54,7 @@ struct device_class; ...@@ -54,7 +54,7 @@ struct device_class;
struct bus_type { struct bus_type {
char * name; char * name;
rwlock_t lock; struct rw_semaphore rwsem;
atomic_t refcount; atomic_t refcount;
u32 present; u32 present;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment