Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c744aeae authored by Cornelia Huck's avatar Cornelia Huck Committed by Greg Kroah-Hartman
Browse files

driver core: Allow device_move(dev, NULL).



If we allow NULL as the new parent in device_move(), we need to make sure
that the device is placed into the same place as it would if it was
newly registered:

- Consider the device virtual tree. In order to be able to reuse code,
  setup_parent() has been tweaked a bit.
- kobject_move() can fall back to the kset's kobject.
- sysfs_move_dir() uses the sysfs root dir as fallback.

Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Cc: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 717e48c2
Loading
Loading
Loading
Loading
+47 −29
Original line number Diff line number Diff line
@@ -390,22 +390,23 @@ void device_initialize(struct device *dev)
}

#ifdef CONFIG_SYSFS_DEPRECATED
static int setup_parent(struct device *dev, struct device *parent)
static struct kobject * get_device_parent(struct device *dev,
					  struct device *parent)
{
	/* Set the parent to the class, not the parent device */
	/* this keeps sysfs from having a symlink to make old udevs happy */
	if (dev->class)
		dev->kobj.parent = &dev->class->subsys.kset.kobj;
		return &dev->class->subsys.kset.kobj;
	else if (parent)
		dev->kobj.parent = &parent->kobj;
		return &parent->kobj;

	return 0;
	return NULL;
}
#else
static int virtual_device_parent(struct device *dev)
static struct kobject * virtual_device_parent(struct device *dev)
{
	if (!dev->class)
		return -ENODEV;
		return ERR_PTR(-ENODEV);

	if (!dev->class->virtual_dir) {
		static struct kobject *virtual_dir = NULL;
@@ -415,25 +416,31 @@ static int virtual_device_parent(struct device *dev)
		dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
	}

	dev->kobj.parent = dev->class->virtual_dir;
	return 0;
	return dev->class->virtual_dir;
}

static int setup_parent(struct device *dev, struct device *parent)
static struct kobject * get_device_parent(struct device *dev,
					  struct device *parent)
{
	int error;

	/* if this is a class device, and has no parent, create one */
	if ((dev->class) && (parent == NULL)) {
		error = virtual_device_parent(dev);
		if (error)
			return error;
		return virtual_device_parent(dev);
	} else if (parent)
		dev->kobj.parent = &parent->kobj;
		return &parent->kobj;
	return NULL;
}

#endif
static int setup_parent(struct device *dev, struct device *parent)
{
	struct kobject *kobj;
	kobj = get_device_parent(dev, parent);
	if (IS_ERR(kobj))
		return PTR_ERR(kobj);
	if (kobj)
		dev->kobj.parent = kobj;
	return 0;
}
#endif

/**
 *	device_add - add device to device hierarchy.
@@ -976,12 +983,18 @@ static int device_move_class_links(struct device *dev,
		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 (new_parent) {
		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);
		error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
					  class_name);
		if (error)
			sysfs_remove_link(&dev->kobj, "device");
	}
	else
		error = 0;
out:
	kfree(class_name);
	return error;
@@ -993,25 +1006,28 @@ static int device_move_class_links(struct device *dev,
/**
 * 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
 * @new_parent: the new parent of the device (can by NULL)
 */
int device_move(struct device *dev, struct device *new_parent)
{
	int error;
	struct device *old_parent;
	struct kobject *new_parent_kobj;

	dev = get_device(dev);
	if (!dev)
		return -EINVAL;

	new_parent = get_device(new_parent);
	if (!new_parent) {
		error = -EINVAL;
	new_parent_kobj = get_device_parent (dev, new_parent);
	if (IS_ERR(new_parent_kobj)) {
		error = PTR_ERR(new_parent_kobj);
		put_device(new_parent);
		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);
		 new_parent ? new_parent->bus_id : "<NULL>");
	error = kobject_move(&dev->kobj, new_parent_kobj);
	if (error) {
		put_device(new_parent);
		goto out;
@@ -1020,6 +1036,7 @@ int device_move(struct device *dev, struct device *new_parent)
	dev->parent = new_parent;
	if (old_parent)
		klist_remove(&dev->knode_parent);
	if (new_parent)
		klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
	if (!dev->class)
		goto out_put;
@@ -1028,6 +1045,7 @@ int device_move(struct device *dev, struct device *new_parent)
		/* 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)) {
			if (new_parent)
				klist_remove(&dev->knode_parent);
			if (old_parent)
				klist_add_tail(&dev->knode_parent,
+2 −4
Original line number Diff line number Diff line
@@ -378,12 +378,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
	struct sysfs_dirent *new_parent_sd, *sd;
	int error;

	if (!new_parent)
		return -EINVAL;

	old_parent_dentry = kobj->parent ?
		kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
	new_parent_dentry = new_parent->dentry;
	new_parent_dentry = new_parent ?
		new_parent->dentry : sysfs_mount->mnt_sb->s_root;

again:
	mutex_lock(&old_parent_dentry->d_inode->i_mutex);
+3 −3
Original line number Diff line number Diff line
@@ -314,7 +314,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
/**
 *	kobject_move - move object to another parent
 *	@kobj:	object in question.
 *	@new_parent: object's new parent
 *	@new_parent: object's new parent (can be NULL)
 */

int kobject_move(struct kobject *kobj, struct kobject *new_parent)
@@ -330,8 +330,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
		return -EINVAL;
	new_parent = kobject_get(new_parent);
	if (!new_parent) {
		error = -EINVAL;
		goto out;
		if (kobj->kset)
			new_parent = kobject_get(&kobj->kset->kobj);
	}
	/* old object path */
	devpath = kobject_get_path(kobj, GFP_KERNEL);