aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 14:45:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:03 -0400
commit996b73764e9bb9d5e751fd15b130ba38637d66a8 (patch)
treeb8fe0310d1d37da2c2434d1398c12b5ae82b929f /fs
parentdfeb9fb0343363aadc3ee00a9347d120bc2a26b1 (diff)
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: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/dir.c73
1 files changed, 41 insertions, 32 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index b4c482461403..90bed5df254f 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -452,8 +452,9 @@ void sysfs_remove_dir(struct kobject * kobj)
452int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent, 452int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
453 const char *new_name) 453 const char *new_name)
454{ 454{
455 int error = 0; 455 int error;
456 struct dentry * new_dentry; 456 struct dentry * new_dentry;
457 struct sysfs_dirent *sd, *parent_sd;
457 458
458 if (!new_parent) 459 if (!new_parent)
459 return -EFAULT; 460 return -EFAULT;
@@ -462,40 +463,48 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
462 mutex_lock(&new_parent->d_inode->i_mutex); 463 mutex_lock(&new_parent->d_inode->i_mutex);
463 464
464 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); 465 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
465 if (!IS_ERR(new_dentry)) { 466 if (IS_ERR(new_dentry)) {
466 /* By allowing two different directories with the 467 error = PTR_ERR(new_dentry);
467 * same d_parent we allow this routine to move 468 goto out_unlock;
468 * between different shadows of the same directory
469 */
470 if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
471 return -EINVAL;
472 else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
473 error = -EINVAL;
474 else if (new_dentry == kobj->dentry)
475 error = -EINVAL;
476 else if (!new_dentry->d_inode) {
477 error = kobject_set_name(kobj, "%s", new_name);
478 if (!error) {
479 struct sysfs_dirent *sd, *parent_sd;
480
481 d_add(new_dentry, NULL);
482 d_move(kobj->dentry, new_dentry);
483
484 sd = kobj->dentry->d_fsdata;
485 parent_sd = new_parent->d_fsdata;
486
487 list_del_init(&sd->s_sibling);
488 list_add(&sd->s_sibling, &parent_sd->s_children);
489 }
490 else
491 d_drop(new_dentry);
492 } else
493 error = -EEXIST;
494 dput(new_dentry);
495 } 469 }
470
471 /* By allowing two different directories with the same
472 * d_parent we allow this routine to move between different
473 * shadows of the same directory
474 */
475 error = -EINVAL;
476 if (kobj->dentry->d_parent->d_inode != new_parent->d_inode ||
477 new_dentry->d_parent->d_inode != new_parent->d_inode ||
478 new_dentry == kobj->dentry)
479 goto out_dput;
480
481 error = -EEXIST;
482 if (new_dentry->d_inode)
483 goto out_dput;
484
485 error = kobject_set_name(kobj, "%s", new_name);
486 if (error)
487 goto out_drop;
488
489 d_add(new_dentry, NULL);
490 d_move(kobj->dentry, new_dentry);
491
492 sd = kobj->dentry->d_fsdata;
493 parent_sd = new_parent->d_fsdata;
494
495 list_del_init(&sd->s_sibling);
496 list_add(&sd->s_sibling, &parent_sd->s_children);
497
498 error = 0;
499 goto out_unlock;
500
501 out_drop:
502 d_drop(new_dentry);
503 out_dput:
504 dput(new_dentry);
505 out_unlock:
496 mutex_unlock(&new_parent->d_inode->i_mutex); 506 mutex_unlock(&new_parent->d_inode->i_mutex);
497 up_write(&sysfs_rename_sem); 507 up_write(&sysfs_rename_sem);
498
499 return error; 508 return error;
500} 509}
501 510