From 4278bccc2d9707c9c4ee1769b464bffe4dfd820a Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 15 Oct 2002 20:54:20 -0700 Subject: driver model: change bus refcounting scheme to match devices'. Based on recent changes to device refcounting/unregistration. struct bus_type gets a ->present field, which is set when the bus is registered. bus_unregister() is added, which only clears ->present and calls put_bus(). get_bus() checks the ->present and returns NULL if clear. This allows all current references to buses to keep valid structures, while preventing any new references to the bus structure. --- drivers/base/bus.c | 36 +++++++++++++++++++++++++++++++----- include/linux/device.h | 10 +++------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 7daffbfd9913..1343c64c5a38 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -136,12 +136,35 @@ void bus_remove_device(struct device * dev) } } +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_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 +179,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 +194,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/include/linux/device.h b/include/linux/device.h index 80a63939f924..03c7d995e96c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -56,6 +56,7 @@ struct bus_type { char * name; rwlock_t lock; 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, -- cgit v1.2.3