Commit 402f1b9f authored by Patrick Mochel's avatar Patrick Mochel

[driver model] Add device_unregister_wait().

For those times when you need to wait for a device to unregister, before you
continue on, this is device_unregister_wait(). It will block until all the
references to the device go away, including references held by open sysfs
files.

This is probably most useful for modules that add and remove devices when
they are loaded and unloaded. They must be sure that the devices that they
have declared or allocated are completely torn down before the module is 
removed, lest unfreed memory get referenced or called. 
parent a485bc0c
......@@ -76,6 +76,8 @@ static struct sysfs_ops dev_sysfs_ops = {
static void device_release(struct kobject * kobj)
{
struct device * dev = to_dev(kobj);
struct completion * c = dev->complete;
if (dev->release)
dev->release(dev);
else {
......@@ -84,6 +86,8 @@ static void device_release(struct kobject * kobj)
dev->bus_id);
WARN_ON(1);
}
if (c)
complete(c);
}
static struct kobj_type ktype_device = {
......@@ -349,6 +353,26 @@ void device_unregister(struct device * dev)
put_device(dev);
}
/**
* device_unregister_wait - Unregister device and wait for it to be freed.
* @dev: Device to unregister.
*
* For the cases where the caller needs to wait for all references to
* be dropped from the device before continuing (e.g. modules with
* statically allocated devices), this function uses a completion struct
* to wait, along with a matching complete() in device_release() above.
*/
void device_unregister_wait(struct device * dev)
{
struct completion c;
init_completion(&c);
dev->complete = &c;
device_unregister(dev);
wait_for_completion(&c);
}
/**
* device_for_each_child - device child iterator.
* @dev: parent struct device.
......@@ -389,6 +413,7 @@ EXPORT_SYMBOL(device_register);
EXPORT_SYMBOL(device_del);
EXPORT_SYMBOL(device_unregister);
EXPORT_SYMBOL(device_unregister_wait);
EXPORT_SYMBOL(get_device);
EXPORT_SYMBOL(put_device);
......
......@@ -254,6 +254,7 @@ struct device {
struct list_head children;
struct device * parent;
struct completion * complete; /* Notification for freeing device. */
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
......@@ -301,6 +302,7 @@ dev_set_drvdata (struct device *dev, void *data)
*/
extern int device_register(struct device * dev);
extern void device_unregister(struct device * dev);
extern void device_unregister_wait(struct device * dev);
extern void device_initialize(struct device * dev);
extern int device_add(struct device * dev);
extern void device_del(struct device * dev);
......
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