diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 73 |
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) | |||
452 | int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent, | 452 | int 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 | ||