Skip to content

Commit

Permalink
sysfs: flatten and fix sysfs_rename_dir() error handling
Browse files Browse the repository at this point in the history
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: Tejun Heo <htejun@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Tejun Heo authored and Greg Kroah-Hartman committed Jul 11, 2007
1 parent dfeb9fb commit 996b737
Showing 1 changed file with 41 additions and 32 deletions.
73 changes: 41 additions & 32 deletions fs/sysfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -462,40 +463,48 @@ 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 (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) {
error = kobject_set_name(kobj, "%s", new_name);
if (!error) {
struct sysfs_dirent *sd, *parent_sd;

d_add(new_dentry, NULL);
d_move(kobj->dentry, new_dentry);

sd = kobj->dentry->d_fsdata;
parent_sd = new_parent->d_fsdata;

list_del_init(&sd->s_sibling);
list_add(&sd->s_sibling, &parent_sd->s_children);
}
else
d_drop(new_dentry);
} else
error = -EEXIST;
dput(new_dentry);
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
*/
error = -EINVAL;
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)
goto out_drop;

d_add(new_dentry, NULL);
d_move(kobj->dentry, new_dentry);

sd = kobj->dentry->d_fsdata;
parent_sd = new_parent->d_fsdata;

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

error = 0;
goto out_unlock;

out_drop:
d_drop(new_dentry);
out_dput:
dput(new_dentry);
out_unlock:
mutex_unlock(&new_parent->d_inode->i_mutex);
up_write(&sysfs_rename_sem);

return error;
}

Expand Down

0 comments on commit 996b737

Please sign in to comment.