diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7daffbfd9913f83c7e00ad683b1402e3163782cf..559956c297635aba0218931439ca8dcbe3c58b5b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -47,23 +47,21 @@ int bus_for_each_dev(struct bus_type * bus, void * data, int error = 0; get_bus(bus); - spin_lock(&device_lock); + down_write(&bus->rwsem); 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) { - spin_unlock(&device_lock); error = callback(dev,data); if (prev) put_device(prev); prev = dev; - spin_lock(&device_lock); if (error) break; } } - spin_unlock(&device_lock); if (prev) put_device(prev); + up_write(&bus->rwsem); put_bus(bus); return error; } @@ -77,24 +75,21 @@ int bus_for_each_drv(struct bus_type * bus, void * data, /* pin bus in memory */ get_bus(bus); - - spin_lock(&device_lock); + down_write(&bus->rwsem); list_for_each(node,&bus->drivers) { struct device_driver * drv = get_driver(to_drv(node)); if (drv) { - spin_unlock(&device_lock); error = callback(drv,data); if (prev) put_driver(prev); prev = drv; - spin_lock(&device_lock); if (error) break; } } - spin_unlock(&device_lock); if (prev) put_driver(prev); + up_write(&bus->rwsem); put_bus(bus); return error; } @@ -111,11 +106,11 @@ int bus_for_each_drv(struct bus_type * bus, void * data, int bus_add_device(struct device * dev) { if (dev->bus) { + down_write(&dev->bus->rwsem); pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); get_bus(dev->bus); - spin_lock(&device_lock); list_add_tail(&dev->bus_list,&dev->bus->devices); - spin_unlock(&device_lock); + up_write(&dev->bus->rwsem); device_bus_link(dev); } return 0; @@ -131,17 +126,43 @@ int bus_add_device(struct device * dev) void bus_remove_device(struct device * dev) { if (dev->bus) { + down_write(&dev->bus->rwsem); + list_del_init(&dev->bus_list); device_remove_symlink(&dev->bus->device_dir,dev->bus_id); + up_write(&dev->bus->rwsem); put_bus(dev->bus); } } +struct bus_type * get_bus(struct bus_type * bus) +{ + struct bus_type * ret = bus; + spin_lock(&device_lock); + if (bus && bus->present && atomic_read(&bus->refcount)) + atomic_inc(&bus->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + +void put_bus(struct bus_type * bus) +{ + if (!atomic_dec_and_lock(&bus->refcount,&device_lock)) + return; + list_del_init(&bus->node); + spin_unlock(&device_lock); + BUG_ON(bus->present); + bus_remove_dir(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->drivers); atomic_set(&bus->refcount,2); + bus->present = 1; spin_lock(&device_lock); list_add_tail(&bus->node,&bus_driver_list); @@ -156,13 +177,14 @@ int bus_register(struct bus_type * bus) return 0; } -void put_bus(struct bus_type * bus) +void bus_unregister(struct bus_type * bus) { - if (!atomic_dec_and_lock(&bus->refcount,&device_lock)) - return; - list_del_init(&bus->node); + spin_lock(&device_lock); + bus->present = 0; spin_unlock(&device_lock); - bus_remove_dir(bus); + + pr_debug("bus %s: unregistering\n",bus->name); + put_bus(bus); } EXPORT_SYMBOL(bus_for_each_dev); @@ -170,4 +192,6 @@ EXPORT_SYMBOL(bus_for_each_drv); EXPORT_SYMBOL(bus_add_device); EXPORT_SYMBOL(bus_remove_device); EXPORT_SYMBOL(bus_register); +EXPORT_SYMBOL(bus_unregister); +EXPORT_SYMBOL(get_bus); EXPORT_SYMBOL(put_bus); diff --git a/drivers/base/class.c b/drivers/base/class.c index dfef9793871a07e3f82fbe28cb22d78e100009d0..3c7024cc3efb2069ffa3f65d5c3f42561c7cf6e5 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -81,29 +81,55 @@ void devclass_remove_device(struct device * dev) } } +struct device_class * get_devclass(struct device_class * cls) +{ + struct device_class * ret = cls; + spin_lock(&device_lock); + if (cls && cls->present && atomic_read(&cls->refcount) > 0) + atomic_inc(&cls->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + +void put_devclass(struct device_class * cls) +{ + if (atomic_dec_and_lock(&cls->refcount,&device_lock)) { + list_del_init(&cls->node); + spin_unlock(&device_lock); + devclass_remove_dir(cls); + } +} + + int devclass_register(struct device_class * cls) { INIT_LIST_HEAD(&cls->drivers); INIT_LIST_HEAD(&cls->intf_list); - - pr_debug("registering device class '%s'\n",cls->name); + atomic_set(&cls->refcount,2); + cls->present = 1; + pr_debug("device class '%s': registering\n",cls->name); spin_lock(&device_lock); list_add_tail(&cls->node,&class_list); spin_unlock(&device_lock); devclass_make_dir(cls); + put_devclass(cls); return 0; } void devclass_unregister(struct device_class * cls) { - pr_debug("unregistering device class '%s'\n",cls->name); - devclass_remove_dir(cls); spin_lock(&device_lock); - list_del_init(&class_list); + cls->present = 0; spin_unlock(&device_lock); + pr_debug("device class '%s': unregistering\n",cls->name); + put_devclass(cls); } EXPORT_SYMBOL(devclass_register); EXPORT_SYMBOL(devclass_unregister); +EXPORT_SYMBOL(get_devclass); +EXPORT_SYMBOL(put_devclass); diff --git a/drivers/base/core.c b/drivers/base/core.c index 83c31723d8447211514f1e84cce555f7214e8847..a1a41f4b0a07892ebf4a6a7d31cdf8bc4b56976e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -259,34 +259,21 @@ struct device * get_device(struct device * dev) */ void put_device(struct device * dev) { - struct device * parent; if (!atomic_dec_and_lock(&dev->refcount,&device_lock)) return; - parent = dev->parent; - dev->parent = NULL; + list_del_init(&dev->node); + list_del_init(&dev->g_list); + list_del_init(&dev->driver_list); spin_unlock(&device_lock); BUG_ON(dev->present); - if (dev->release) - dev->release(dev); - - if (parent) - put_device(parent); + device_del(dev); } void device_del(struct device * dev) { - spin_lock(&device_lock); - dev->present = 0; - list_del_init(&dev->node); - list_del_init(&dev->g_list); - list_del_init(&dev->bus_list); - list_del_init(&dev->driver_list); - spin_unlock(&device_lock); - - pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", - dev->bus_id,dev->name); + struct device * parent = dev->parent; /* Notify the platform of the removal, in case they * need to do anything... @@ -302,6 +289,12 @@ void device_del(struct device * dev) /* remove the driverfs directory */ device_remove_dir(dev); + + if (dev->release) + dev->release(dev); + + if (parent) + put_device(parent); } /** @@ -315,22 +308,15 @@ void device_del(struct device * dev) */ void device_unregister(struct device * dev) { - device_del(dev); - put_device(dev); -} - -static int __init device_init(void) -{ - int error; + spin_lock(&device_lock); + dev->present = 0; + spin_unlock(&device_lock); - error = init_driverfs_fs(); - if (error) - panic("DEV: could not initialize driverfs"); - return 0; + pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", + dev->bus_id,dev->name); + put_device(dev); } -core_initcall(device_init); - EXPORT_SYMBOL(device_register); EXPORT_SYMBOL(device_unregister); EXPORT_SYMBOL(get_device); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 221e525736bd30e2b423cf448fc6af278f3f2580..b19b06201dd579c5ac62bcfd81d9963c9b954d0a 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -39,6 +39,43 @@ int driver_for_each_dev(struct device_driver * drv, void * data, return error; } +struct device_driver * get_driver(struct device_driver * drv) +{ + struct device_driver * ret = drv; + spin_lock(&device_lock); + if (drv && drv->present && atomic_read(&drv->refcount) > 0) + atomic_inc(&drv->refcount); + else + ret = NULL; + spin_unlock(&device_lock); + return ret; +} + + +void remove_driver(struct device_driver * drv) +{ + BUG(); +} + +/** + * put_driver - decrement driver's refcount and clean up if necessary + * @drv: driver in question + */ +void put_driver(struct device_driver * drv) +{ + struct bus_type * bus = drv->bus; + if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) + return; + list_del_init(&drv->bus_list); + spin_unlock(&device_lock); + BUG_ON(drv->present); + driver_detach(drv); + driver_remove_dir(drv); + if (drv->release) + drv->release(drv); + put_bus(bus); +} + /** * driver_register - register driver with bus * @drv: driver to register @@ -50,12 +87,13 @@ int driver_register(struct device_driver * drv) if (!drv->bus) return -EINVAL; - pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name); + pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name); get_bus(drv->bus); atomic_set(&drv->refcount,2); rwlock_init(&drv->lock); INIT_LIST_HEAD(&drv->devices); + drv->present = 1; spin_lock(&device_lock); list_add(&drv->bus_list,&drv->bus->drivers); spin_unlock(&device_lock); @@ -65,39 +103,17 @@ int driver_register(struct device_driver * drv) return 0; } -static void __remove_driver(struct device_driver * drv) -{ - pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name); - driver_detach(drv); - driver_remove_dir(drv); - if (drv->release) - drv->release(drv); - put_bus(drv->bus); -} - -void remove_driver(struct device_driver * drv) +void driver_unregister(struct device_driver * drv) { spin_lock(&device_lock); - atomic_set(&drv->refcount,0); - list_del_init(&drv->bus_list); - spin_unlock(&device_lock); - __remove_driver(drv); -} - -/** - * put_driver - decrement driver's refcount and clean up if necessary - * @drv: driver in question - */ -void put_driver(struct device_driver * drv) -{ - if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) - return; - list_del_init(&drv->bus_list); + drv->present = 0; spin_unlock(&device_lock); - __remove_driver(drv); + pr_debug("driver %s:%s: unregistering\n",drv->bus->name,drv->name); + put_driver(drv); } EXPORT_SYMBOL(driver_for_each_dev); EXPORT_SYMBOL(driver_register); +EXPORT_SYMBOL(driver_unregister); +EXPORT_SYMBOL(get_driver); EXPORT_SYMBOL(put_driver); -EXPORT_SYMBOL(remove_driver); diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c index 0f35e27e669ca3b8d2df8cc8464359f06607d197..b4b5aa9f6a5552dd322f1de6974235a47c2e5dce 100644 --- a/fs/driverfs/inode.c +++ b/fs/driverfs/inode.c @@ -509,11 +509,13 @@ static void put_mount(void) DBG("driverfs: mount_count = %d\n",mount_count); } -int __init init_driverfs_fs(void) +static int __init driverfs_init(void) { return register_filesystem(&driverfs_fs_type); } +core_initcall(driverfs_init); + static struct dentry * get_dentry(struct dentry * parent, const char * name) { struct qstr qstr; diff --git a/include/linux/device.h b/include/linux/device.h index 80a63939f9245e617488e973cd128e5e0588288c..c0f8d6c5e4bf120d3f84101cb64cf0184bfd1fcf 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -54,8 +54,9 @@ struct device_class; struct bus_type { char * name; - rwlock_t lock; + struct rw_semaphore rwsem; atomic_t refcount; + u32 present; struct list_head node; struct list_head devices; @@ -73,14 +74,9 @@ struct bus_type { extern int bus_register(struct bus_type * bus); +extern void bus_unregister(struct bus_type * bus); -static inline struct bus_type * get_bus(struct bus_type * bus) -{ - BUG_ON(!atomic_read(&bus->refcount)); - atomic_inc(&bus->refcount); - return bus; -} - +extern struct bus_type * get_bus(struct bus_type * bus); extern void put_bus(struct bus_type * bus); extern int bus_for_each_dev(struct bus_type * bus, void * data, @@ -114,6 +110,7 @@ struct device_driver { rwlock_t lock; atomic_t refcount; + u32 present; struct list_head bus_list; struct list_head class_list; @@ -131,16 +128,10 @@ struct device_driver { }; - extern int driver_register(struct device_driver * drv); +extern void driver_unregister(struct device_driver * drv); -static inline struct device_driver * get_driver(struct device_driver * drv) -{ - BUG_ON(!atomic_read(&drv->refcount)); - atomic_inc(&drv->refcount); - return drv; -} - +extern struct device_driver * get_driver(struct device_driver * drv); extern void put_driver(struct device_driver * drv); extern void remove_driver(struct device_driver * drv); @@ -172,6 +163,9 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute * */ struct device_class { char * name; + atomic_t refcount; + u32 present; + u32 devnum; struct list_head node; @@ -189,6 +183,9 @@ struct device_class { extern int devclass_register(struct device_class *); extern void devclass_unregister(struct device_class *); +extern struct device_class * get_devclass(struct device_class *); +extern void put_devclass(struct device_class *); + struct devclass_attribute { struct attribute attr; diff --git a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h index d859f8c2e041b43f38020fdf971c8c9b619abe8f..b4270e947a1e8999eb7cd482d7656edfb7290d4e 100644 --- a/include/linux/driverfs_fs.h +++ b/include/linux/driverfs_fs.h @@ -65,6 +65,4 @@ driverfs_create_symlink(struct driver_dir_entry * parent, extern void driverfs_remove_file(struct driver_dir_entry *, const char * name); -extern int init_driverfs_fs(void); - #endif /* _DDFS_H_ */