driver core: Introduce device_move(): move a device to a new parent.

Provide a function device_move() to move a device to a new parent device. Add
auxilliary functions kobject_move() and sysfs_move_dir().
kobject_move() generates a new uevent of type KOBJ_MOVE, containing the
previous path (DEVPATH_OLD) in addition to the usual values. For this, a new
interface kobject_uevent_env() is created that allows to add further
environmental data to the uevent at the kobject layer.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Acked-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Cornelia Huck
2006-11-20 17:07:51 +01:00
committed by Greg Kroah-Hartman
parent af9e076536
commit 8a82472f86
7 changed files with 228 additions and 4 deletions
+92
View File
@@ -955,3 +955,95 @@ int device_rename(struct device *dev, char *new_name)
return error;
}
static int device_move_class_links(struct device *dev,
struct device *old_parent,
struct device *new_parent)
{
#ifdef CONFIG_SYSFS_DEPRECATED
int error;
char *class_name;
class_name = make_class_name(dev->class->name, &dev->kobj);
if (!class_name) {
error = PTR_ERR(class_name);
class_name = NULL;
goto out;
}
if (old_parent) {
sysfs_remove_link(&dev->kobj, "device");
sysfs_remove_link(&old_parent->kobj, class_name);
}
error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
if (error)
goto out;
error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
if (error)
sysfs_remove_link(&dev->kobj, "device");
out:
kfree(class_name);
return error;
#else
return 0;
#endif
}
/**
* device_move - moves a device to a new parent
* @dev: the pointer to the struct device to be moved
* @new_parent: the new parent of the device
*/
int device_move(struct device *dev, struct device *new_parent)
{
int error;
struct device *old_parent;
dev = get_device(dev);
if (!dev)
return -EINVAL;
if (!device_is_registered(dev)) {
error = -EINVAL;
goto out;
}
new_parent = get_device(new_parent);
if (!new_parent) {
error = -EINVAL;
goto out;
}
pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
new_parent->bus_id);
error = kobject_move(&dev->kobj, &new_parent->kobj);
if (error) {
put_device(new_parent);
goto out;
}
old_parent = dev->parent;
dev->parent = new_parent;
if (old_parent)
klist_del(&dev->knode_parent);
klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
if (error) {
/* We ignore errors on cleanup since we're hosed anyway... */
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
klist_del(&dev->knode_parent);
if (old_parent)
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
}
put_device(new_parent);
goto out;
}
out_put:
put_device(old_parent);
out:
put_device(dev);
return error;
}
EXPORT_SYMBOL_GPL(device_move);