Commit cc7d1ffd authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net//home/mochel/linux-2.5-power

into home.osdl.org:/home/torvalds/v2.5/linux
parents d32824cb 3ee1e2b7
......@@ -459,10 +459,6 @@ int bus_add_driver(struct device_driver * drv)
driver_attach(drv);
up_write(&bus->subsys.rwsem);
if (error) {
kobject_unregister(&drv->kobj);
put_bus(bus);
}
}
return error;
}
......
......@@ -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);
......
......@@ -331,6 +331,7 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
int limit = KOBJ_NAME_LEN;
int need;
va_list args;
char * name;
va_start(args,fmt);
/*
......@@ -338,25 +339,33 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
*/
need = vsnprintf(kobj->name,limit,fmt,args);
if (need < limit)
kobj->k_name = kobj->name;
name = kobj->name;
else {
/*
* Need more space? Allocate it and try again
*/
kobj->k_name = kmalloc(need,GFP_KERNEL);
if (!kobj->k_name) {
name = kmalloc(need,GFP_KERNEL);
if (!name) {
error = -ENOMEM;
goto Done;
}
limit = need;
need = vsnprintf(kobj->k_name,limit,fmt,args);
need = vsnprintf(name,limit,fmt,args);
/* Still? Give up. */
if (need > limit) {
kfree(kobj->k_name);
kfree(name);
error = -EFAULT;
goto Done;
}
}
/* Free the old name, if necessary. */
if (kobj->k_name && kobj->k_name != kobj->name)
kfree(kobj->k_name);
/* Now, set the new name */
kobj->k_name = name;
Done:
va_end(args);
return error;
......@@ -627,6 +636,8 @@ EXPORT_SYMBOL(kobject_unregister);
EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(kset_register);
EXPORT_SYMBOL(kset_unregister);
EXPORT_SYMBOL(kset_find_obj);
EXPORT_SYMBOL(subsystem_init);
......
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