From d470409a6d855b6c9fbb2a6724958d492149e362 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 7 Aug 2002 20:47:07 -0700 Subject: Change DEVICE_ATTR, BUS_ATTR, and DRIVER_ATTR macros to not take a '_str' parameter, and just __stringify the name instead. Update all the users of the macros. --- include/linux/device.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index 9706d94ff7b6..c6f13cf24dba 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -93,9 +93,9 @@ struct bus_attribute { ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); }; -#define BUS_ATTR(_name,_str,_mode,_show,_store) \ +#define BUS_ATTR(_name,_mode,_show,_store) \ struct bus_attribute bus_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; @@ -150,9 +150,9 @@ struct driver_attribute { ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); }; -#define DRIVER_ATTR(_name,_str,_mode,_show,_store) \ +#define DRIVER_ATTR(_name,_mode,_show,_store) \ struct driver_attribute driver_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; @@ -222,13 +222,14 @@ struct device_attribute { ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); }; -#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ +#define DEVICE_ATTR(_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; + extern int device_create_file(struct device *device, struct device_attribute * entry); extern void device_remove_file(struct device * dev, struct device_attribute * attr); -- cgit v1.2.3 From d8b2993cbe5e4a58038e65a2d99b7b396281ba9f Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 12 Aug 2002 00:50:03 -0700 Subject: Update device model locking This updates the device model locking to use device_lock when accessing all lists (the global list, the bus' lists and the drivers' lists). Before the latter two would use their own rwlocks. This also updates get_device() to return a pointer to the struct device if it can successfully increment the reference count. Between these two changes, this should prevent anything gaining an invalid reference to a device that is in the process of being removed: If a device is being removed, it's reference count is 0, but it hasn't necessarily hasn't been removed from its bus's list. If the bus list iterator attempts to access the device, it will take the lock, but will continue on to the next device because the refcount is 0 (and drop the lock). Well, theoretically; the bus iterators still need to be changed, but that's coming next.. --- drivers/base/base.h | 2 ++ drivers/base/bus.c | 26 +++++++++++++------------- drivers/base/core.c | 38 +++++++++++++++++++++++++++++--------- drivers/base/driver.c | 25 +++++++++++-------------- drivers/base/power.c | 6 +++--- include/linux/device.h | 7 +------ 6 files changed, 59 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/base.h b/drivers/base/base.h index c2a1f9b1e9af..2ba238eba033 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -9,6 +9,8 @@ extern struct device device_root; extern spinlock_t device_lock; +extern struct device * get_device_locked(struct device *); + extern int bus_add_device(struct device * dev); extern void bus_remove_device(struct device * dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index e85af605a07f..c10532e28fb8 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -42,12 +42,12 @@ int bus_for_each_dev(struct bus_type * bus, void * data, int error = 0; get_bus(bus); - read_lock(&bus->lock); + spin_lock(&device_lock); node = bus->devices.next; while (node != &bus->devices) { next = list_entry(node,struct device,bus_list); - get_device(next); - read_unlock(&bus->lock); + get_device_locked(next); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -56,10 +56,10 @@ int bus_for_each_dev(struct bus_type * bus, void * data, put_device(dev); break; } - read_lock(&bus->lock); + spin_lock(&device_lock); node = dev->bus_list.next; } - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); put_bus(bus); @@ -77,12 +77,12 @@ int bus_for_each_drv(struct bus_type * bus, void * data, /* pin bus in memory */ get_bus(bus); - read_lock(&bus->lock); + spin_lock(&device_lock); node = bus->drivers.next; while (node != &bus->drivers) { next = list_entry(node,struct device_driver,bus_list); get_driver(next); - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (drv) put_driver(drv); @@ -91,10 +91,10 @@ int bus_for_each_drv(struct bus_type * bus, void * data, put_driver(drv); break; } - read_lock(&bus->lock); + spin_lock(&device_lock); node = drv->bus_list.next; } - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (drv) put_driver(drv); put_bus(bus); @@ -115,9 +115,9 @@ int bus_add_device(struct device * dev) if (dev->bus) { pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); get_bus(dev->bus); - write_lock(&dev->bus->lock); + spin_lock(&device_lock); list_add_tail(&dev->bus_list,&dev->bus->devices); - write_unlock(&dev->bus->lock); + spin_unlock(&device_lock); device_bus_link(dev); } return 0; @@ -134,9 +134,9 @@ void bus_remove_device(struct device * dev) { if (dev->bus) { device_remove_symlink(&dev->bus->device_dir,dev->bus_id); - write_lock(&dev->bus->lock); + spin_lock(&device_lock); list_del_init(&dev->bus_list); - write_unlock(&dev->bus->lock); + spin_unlock(&device_lock); put_bus(dev->bus); } } diff --git a/drivers/base/core.c b/drivers/base/core.c index 9d04145d5ac2..c3b275b0b2e9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -53,9 +53,9 @@ static int found_match(struct device * dev, struct device_driver * drv) pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id,drv->name); - write_lock(&drv->lock); + spin_lock(&device_lock); list_add_tail(&dev->driver_list,&drv->devices); - write_unlock(&drv->lock); + spin_unlock(&device_lock); goto Done; @@ -154,13 +154,13 @@ void driver_detach(struct device_driver * drv) struct list_head * node; int error = 0; - write_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; while (node != &drv->devices) { next = list_entry(node,struct device,driver_list); - get_device(next); + get_device_locked(next); list_del_init(&next->driver_list); - write_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -169,10 +169,10 @@ void driver_detach(struct device_driver * drv) put_device(dev); break; } - write_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; } - write_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); } @@ -202,12 +202,12 @@ int device_register(struct device *dev) spin_lock_init(&dev->lock); atomic_set(&dev->refcount,2); - spin_lock(&device_lock); if (dev != &device_root) { if (!dev->parent) dev->parent = &device_root; get_device(dev->parent); + spin_lock(&device_lock); if (list_empty(&dev->parent->children)) prev_dev = dev->parent; else @@ -215,8 +215,8 @@ int device_register(struct device *dev) list_add(&dev->g_list, &prev_dev->g_list); list_add_tail(&dev->node,&dev->parent->children); + spin_unlock(&device_lock); } - spin_unlock(&device_lock); pr_debug("DEV: registering device: ID = '%s', name = %s\n", dev->bus_id, dev->name); @@ -240,6 +240,25 @@ int device_register(struct device *dev) return error; } +struct device * get_device_locked(struct device * dev) +{ + struct device * ret = dev; + if (dev && atomic_read(&dev->refcount)) + atomic_inc(&dev->refcount); + else + ret = NULL; + return ret; +} + +struct device * get_device(struct device * dev) +{ + struct device * ret; + spin_lock(&device_lock); + ret = get_device_locked(dev); + spin_unlock(&device_lock); + return ret; +} + /** * put_device - decrement reference count, and clean up when it hits 0 * @dev: device in question @@ -296,4 +315,5 @@ static int __init device_init(void) core_initcall(device_init); EXPORT_SYMBOL(device_register); +EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(put_device); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 2b4aa02a0683..138e5a3ff80d 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,12 +19,12 @@ int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback) int error = 0; get_driver(drv); - read_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; while (node != &drv->devices) { next = list_entry(node,struct device,driver_list); - get_device(next); - read_unlock(&drv->lock); + get_device_locked(next); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -33,10 +33,10 @@ int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback) put_device(dev); break; } - read_lock(&drv->lock); + spin_lock(&device_lock); node = dev->driver_list.next; } - read_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); put_driver(drv); @@ -60,9 +60,9 @@ int driver_register(struct device_driver * drv) atomic_set(&drv->refcount,2); rwlock_init(&drv->lock); INIT_LIST_HEAD(&drv->devices); - write_lock(&drv->bus->lock); + spin_lock(&device_lock); list_add(&drv->bus_list,&drv->bus->drivers); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); driver_make_dir(drv); driver_attach(drv); put_driver(drv); @@ -81,10 +81,10 @@ static void __remove_driver(struct device_driver * drv) void remove_driver(struct device_driver * drv) { - write_lock(&drv->bus->lock); + spin_lock(&device_lock); atomic_set(&drv->refcount,0); list_del_init(&drv->bus_list); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); __remove_driver(drv); } @@ -94,13 +94,10 @@ void remove_driver(struct device_driver * drv) */ void put_driver(struct device_driver * drv) { - write_lock(&drv->bus->lock); - if (!atomic_dec_and_test(&drv->refcount)) { - write_unlock(&drv->bus->lock); + if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) return; - } list_del_init(&drv->bus_list); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); __remove_driver(drv); } diff --git a/drivers/base/power.c b/drivers/base/power.c index f916cb838b30..9faa611a065a 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -36,7 +36,7 @@ int device_suspend(u32 state, u32 level) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.next); while(dev != &device_root && !error) { - get_device(dev); + get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); @@ -71,7 +71,7 @@ void device_resume(u32 level) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.prev); while(dev != &device_root) { - get_device(dev); + get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); @@ -108,7 +108,7 @@ void device_shutdown(void) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.next); while(dev != &device_root) { - get_device(dev); + dev = get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); diff --git a/include/linux/device.h b/include/linux/device.h index c6f13cf24dba..c33eae266026 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -261,12 +261,7 @@ static inline void unlock_device(struct device * dev) * get_device - atomically increment the reference count for the device. * */ -static inline void get_device(struct device * dev) -{ - BUG_ON(!atomic_read(&dev->refcount)); - atomic_inc(&dev->refcount); -} - +extern struct device * get_device(struct device * dev); extern void put_device(struct device * dev); /* drivers/base/sys.c */ -- cgit v1.2.3