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

Commit 996b7376 authored by Tejun Heo's avatar Tejun Heo Committed by Greg Kroah-Hartman
Browse files

sysfs: flatten and fix sysfs_rename_dir() error handling



Error handling in sysfs_rename_dir() was broken.

* When lookup_one_len() fails, 0 is returned.

* If parent inode check fails, returns with inode mutex and rename
  rwsem held.

This patch fixes the above bugs and flattens error handling such that
it's more readable and easier to modify.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dfeb9fb0
Loading
Loading
Loading
Loading
+41 −32
Original line number Diff line number Diff line
@@ -452,8 +452,9 @@ void sysfs_remove_dir(struct kobject * kobj)
int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
		     const char *new_name)
{
	int error = 0;
	int error;
	struct dentry * new_dentry;
	struct sysfs_dirent *sd, *parent_sd;

	if (!new_parent)
		return -EFAULT;
@@ -462,21 +463,28 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
	mutex_lock(&new_parent->d_inode->i_mutex);

	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
	if (!IS_ERR(new_dentry)) {
		/* By allowing two different directories with the
		 * same d_parent we allow this routine to move
		 * between different shadows of the same directory
	if (IS_ERR(new_dentry)) {
		error = PTR_ERR(new_dentry);
		goto out_unlock;
	}

	/* By allowing two different directories with the same
	 * d_parent we allow this routine to move between different
	 * shadows of the same directory
	 */
		if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
			return -EINVAL;
		else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
			error = -EINVAL;
		else if (new_dentry == kobj->dentry)
	error = -EINVAL;
		else if (!new_dentry->d_inode) {
	if (kobj->dentry->d_parent->d_inode != new_parent->d_inode ||
	    new_dentry->d_parent->d_inode != new_parent->d_inode ||
	    new_dentry == kobj->dentry)
		goto out_dput;

	error = -EEXIST;
	if (new_dentry->d_inode)
		goto out_dput;

	error = kobject_set_name(kobj, "%s", new_name);
			if (!error) {
				struct sysfs_dirent *sd, *parent_sd;
	if (error)
		goto out_drop;

	d_add(new_dentry, NULL);
	d_move(kobj->dentry, new_dentry);
@@ -486,16 +494,17 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,

	list_del_init(&sd->s_sibling);
	list_add(&sd->s_sibling, &parent_sd->s_children);
			}
			else

	error = 0;
	goto out_unlock;

 out_drop:
	d_drop(new_dentry);
		} else
			error = -EEXIST;
 out_dput:
	dput(new_dentry);
	}
 out_unlock:
	mutex_unlock(&new_parent->d_inode->i_mutex);
	up_write(&sysfs_rename_sem);

	return error;
}