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) ...@@ -459,10 +459,6 @@ int bus_add_driver(struct device_driver * drv)
driver_attach(drv); driver_attach(drv);
up_write(&bus->subsys.rwsem); up_write(&bus->subsys.rwsem);
if (error) {
kobject_unregister(&drv->kobj);
put_bus(bus);
}
} }
return error; return error;
} }
......
...@@ -76,6 +76,8 @@ static struct sysfs_ops dev_sysfs_ops = { ...@@ -76,6 +76,8 @@ static struct sysfs_ops dev_sysfs_ops = {
static void device_release(struct kobject * kobj) static void device_release(struct kobject * kobj)
{ {
struct device * dev = to_dev(kobj); struct device * dev = to_dev(kobj);
struct completion * c = dev->complete;
if (dev->release) if (dev->release)
dev->release(dev); dev->release(dev);
else { else {
...@@ -84,6 +86,8 @@ static void device_release(struct kobject * kobj) ...@@ -84,6 +86,8 @@ static void device_release(struct kobject * kobj)
dev->bus_id); dev->bus_id);
WARN_ON(1); WARN_ON(1);
} }
if (c)
complete(c);
} }
static struct kobj_type ktype_device = { static struct kobj_type ktype_device = {
...@@ -349,6 +353,26 @@ void device_unregister(struct device * dev) ...@@ -349,6 +353,26 @@ void device_unregister(struct device * dev)
put_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. * device_for_each_child - device child iterator.
* @dev: parent struct device. * @dev: parent struct device.
...@@ -389,6 +413,7 @@ EXPORT_SYMBOL(device_register); ...@@ -389,6 +413,7 @@ EXPORT_SYMBOL(device_register);
EXPORT_SYMBOL(device_del); EXPORT_SYMBOL(device_del);
EXPORT_SYMBOL(device_unregister); EXPORT_SYMBOL(device_unregister);
EXPORT_SYMBOL(device_unregister_wait);
EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(get_device);
EXPORT_SYMBOL(put_device); EXPORT_SYMBOL(put_device);
......
...@@ -254,6 +254,7 @@ struct device { ...@@ -254,6 +254,7 @@ struct device {
struct list_head children; struct list_head children;
struct device * parent; struct device * parent;
struct completion * complete; /* Notification for freeing device. */
struct kobject kobj; struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */ char bus_id[BUS_ID_SIZE]; /* position on parent bus */
...@@ -301,6 +302,7 @@ dev_set_drvdata (struct device *dev, void *data) ...@@ -301,6 +302,7 @@ dev_set_drvdata (struct device *dev, void *data)
*/ */
extern int device_register(struct device * dev); extern int device_register(struct device * dev);
extern void device_unregister(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 void device_initialize(struct device * dev);
extern int device_add(struct device * dev); extern int device_add(struct device * dev);
extern void device_del(struct device * dev); extern void device_del(struct device * dev);
......
...@@ -331,6 +331,7 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...) ...@@ -331,6 +331,7 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
int limit = KOBJ_NAME_LEN; int limit = KOBJ_NAME_LEN;
int need; int need;
va_list args; va_list args;
char * name;
va_start(args,fmt); va_start(args,fmt);
/* /*
...@@ -338,25 +339,33 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...) ...@@ -338,25 +339,33 @@ int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
*/ */
need = vsnprintf(kobj->name,limit,fmt,args); need = vsnprintf(kobj->name,limit,fmt,args);
if (need < limit) if (need < limit)
kobj->k_name = kobj->name; name = kobj->name;
else { else {
/* /*
* Need more space? Allocate it and try again * Need more space? Allocate it and try again
*/ */
kobj->k_name = kmalloc(need,GFP_KERNEL); name = kmalloc(need,GFP_KERNEL);
if (!kobj->k_name) { if (!name) {
error = -ENOMEM; error = -ENOMEM;
goto Done; goto Done;
} }
limit = need; limit = need;
need = vsnprintf(kobj->k_name,limit,fmt,args); need = vsnprintf(name,limit,fmt,args);
/* Still? Give up. */ /* Still? Give up. */
if (need > limit) { if (need > limit) {
kfree(kobj->k_name); kfree(name);
error = -EFAULT; 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: Done:
va_end(args); va_end(args);
return error; return error;
...@@ -627,6 +636,8 @@ EXPORT_SYMBOL(kobject_unregister); ...@@ -627,6 +636,8 @@ EXPORT_SYMBOL(kobject_unregister);
EXPORT_SYMBOL(kobject_get); EXPORT_SYMBOL(kobject_get);
EXPORT_SYMBOL(kobject_put); EXPORT_SYMBOL(kobject_put);
EXPORT_SYMBOL(kset_register);
EXPORT_SYMBOL(kset_unregister);
EXPORT_SYMBOL(kset_find_obj); EXPORT_SYMBOL(kset_find_obj);
EXPORT_SYMBOL(subsystem_init); 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