diff options
Diffstat (limited to 'fs/sysfs/dir.c')
| -rw-r--r-- | fs/sysfs/dir.c | 388 |
1 files changed, 123 insertions, 265 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e0201837d244..f05f2303a8b8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
| 26 | 26 | ||
| 27 | DEFINE_MUTEX(sysfs_mutex); | 27 | DEFINE_MUTEX(sysfs_mutex); |
| 28 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
| 29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 28 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
| 30 | 29 | ||
| 31 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 30 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
| @@ -85,46 +84,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | /** | 86 | /** |
| 88 | * sysfs_get_dentry - get dentry for the given sysfs_dirent | ||
| 89 | * @sd: sysfs_dirent of interest | ||
| 90 | * | ||
| 91 | * Get dentry for @sd. Dentry is looked up if currently not | ||
| 92 | * present. This function descends from the root looking up | ||
| 93 | * dentry for each step. | ||
| 94 | * | ||
| 95 | * LOCKING: | ||
| 96 | * mutex_lock(sysfs_rename_mutex) | ||
| 97 | * | ||
| 98 | * RETURNS: | ||
| 99 | * Pointer to found dentry on success, ERR_PTR() value on error. | ||
| 100 | */ | ||
| 101 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | ||
| 102 | { | ||
| 103 | struct dentry *dentry = dget(sysfs_sb->s_root); | ||
| 104 | |||
| 105 | while (dentry->d_fsdata != sd) { | ||
| 106 | struct sysfs_dirent *cur; | ||
| 107 | struct dentry *parent; | ||
| 108 | |||
| 109 | /* find the first ancestor which hasn't been looked up */ | ||
| 110 | cur = sd; | ||
| 111 | while (cur->s_parent != dentry->d_fsdata) | ||
| 112 | cur = cur->s_parent; | ||
| 113 | |||
| 114 | /* look it up */ | ||
| 115 | parent = dentry; | ||
| 116 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 117 | dentry = lookup_one_noperm(cur->s_name, parent); | ||
| 118 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 119 | dput(parent); | ||
| 120 | |||
| 121 | if (IS_ERR(dentry)) | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | return dentry; | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * sysfs_get_active - get an active reference to sysfs_dirent | 87 | * sysfs_get_active - get an active reference to sysfs_dirent |
| 129 | * @sd: sysfs_dirent to get an active reference to | 88 | * @sd: sysfs_dirent to get an active reference to |
| 130 | * | 89 | * |
| @@ -298,7 +257,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
| 298 | goto repeat; | 257 | goto repeat; |
| 299 | } | 258 | } |
| 300 | 259 | ||
| 301 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | 260 | static int sysfs_dentry_delete(struct dentry *dentry) |
| 261 | { | ||
| 262 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 263 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); | ||
| 264 | } | ||
| 265 | |||
| 266 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
| 267 | { | ||
| 268 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 269 | int is_dir; | ||
| 270 | |||
| 271 | mutex_lock(&sysfs_mutex); | ||
| 272 | |||
| 273 | /* The sysfs dirent has been deleted */ | ||
| 274 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
| 275 | goto out_bad; | ||
| 276 | |||
| 277 | /* The sysfs dirent has been moved? */ | ||
| 278 | if (dentry->d_parent->d_fsdata != sd->s_parent) | ||
| 279 | goto out_bad; | ||
| 280 | |||
| 281 | /* The sysfs dirent has been renamed */ | ||
| 282 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) | ||
| 283 | goto out_bad; | ||
| 284 | |||
| 285 | mutex_unlock(&sysfs_mutex); | ||
| 286 | out_valid: | ||
| 287 | return 1; | ||
| 288 | out_bad: | ||
| 289 | /* Remove the dentry from the dcache hashes. | ||
| 290 | * If this is a deleted dentry we use d_drop instead of d_delete | ||
| 291 | * so sysfs doesn't need to cope with negative dentries. | ||
| 292 | * | ||
| 293 | * If this is a dentry that has simply been renamed we | ||
| 294 | * use d_drop to remove it from the dcache lookup on its | ||
| 295 | * old parent. If this dentry persists later when a lookup | ||
| 296 | * is performed at its new name the dentry will be readded | ||
| 297 | * to the dcache hashes. | ||
| 298 | */ | ||
| 299 | is_dir = (sysfs_type(sd) == SYSFS_DIR); | ||
| 300 | mutex_unlock(&sysfs_mutex); | ||
| 301 | if (is_dir) { | ||
| 302 | /* If we have submounts we must allow the vfs caches | ||
| 303 | * to lie about the state of the filesystem to prevent | ||
| 304 | * leaks and other nasty things. | ||
| 305 | */ | ||
| 306 | if (have_submounts(dentry)) | ||
| 307 | goto out_valid; | ||
| 308 | shrink_dcache_parent(dentry); | ||
| 309 | } | ||
| 310 | d_drop(dentry); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode) | ||
| 302 | { | 315 | { |
| 303 | struct sysfs_dirent * sd = dentry->d_fsdata; | 316 | struct sysfs_dirent * sd = dentry->d_fsdata; |
| 304 | 317 | ||
| @@ -307,7 +320,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
| 307 | } | 320 | } |
| 308 | 321 | ||
| 309 | static const struct dentry_operations sysfs_dentry_ops = { | 322 | static const struct dentry_operations sysfs_dentry_ops = { |
| 310 | .d_iput = sysfs_d_iput, | 323 | .d_revalidate = sysfs_dentry_revalidate, |
| 324 | .d_delete = sysfs_dentry_delete, | ||
| 325 | .d_iput = sysfs_dentry_iput, | ||
| 311 | }; | 326 | }; |
| 312 | 327 | ||
| 313 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | 328 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) |
| @@ -344,12 +359,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
| 344 | return NULL; | 359 | return NULL; |
| 345 | } | 360 | } |
| 346 | 361 | ||
| 347 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | ||
| 348 | { | ||
| 349 | struct sysfs_dirent *sd = arg; | ||
| 350 | return inode->i_ino == sd->s_ino; | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | 362 | /** |
| 354 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 363 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
| 355 | * @acxt: pointer to sysfs_addrm_cxt to be used | 364 | * @acxt: pointer to sysfs_addrm_cxt to be used |
| @@ -357,47 +366,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg) | |||
| 357 | * | 366 | * |
| 358 | * This function is called when the caller is about to add or | 367 | * This function is called when the caller is about to add or |
| 359 | * remove sysfs_dirent under @parent_sd. This function acquires | 368 | * remove sysfs_dirent under @parent_sd. This function acquires |
| 360 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | 369 | * sysfs_mutex. @acxt is used to keep and pass context to |
| 361 | * i_mutex of it. @acxt is used to keep and pass context to | ||
| 362 | * other addrm functions. | 370 | * other addrm functions. |
| 363 | * | 371 | * |
| 364 | * LOCKING: | 372 | * LOCKING: |
| 365 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 373 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
| 366 | * return. i_mutex of parent inode is locked on return if | 374 | * return. |
| 367 | * available. | ||
| 368 | */ | 375 | */ |
| 369 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 376 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
| 370 | struct sysfs_dirent *parent_sd) | 377 | struct sysfs_dirent *parent_sd) |
| 371 | { | 378 | { |
| 372 | struct inode *inode; | ||
| 373 | |||
| 374 | memset(acxt, 0, sizeof(*acxt)); | 379 | memset(acxt, 0, sizeof(*acxt)); |
| 375 | acxt->parent_sd = parent_sd; | 380 | acxt->parent_sd = parent_sd; |
| 376 | 381 | ||
| 377 | /* Lookup parent inode. inode initialization is protected by | ||
| 378 | * sysfs_mutex, so inode existence can be determined by | ||
| 379 | * looking up inode while holding sysfs_mutex. | ||
| 380 | */ | ||
| 381 | mutex_lock(&sysfs_mutex); | 382 | mutex_lock(&sysfs_mutex); |
| 382 | |||
| 383 | inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
| 384 | parent_sd); | ||
| 385 | if (inode) { | ||
| 386 | WARN_ON(inode->i_state & I_NEW); | ||
| 387 | |||
| 388 | /* parent inode available */ | ||
| 389 | acxt->parent_inode = inode; | ||
| 390 | |||
| 391 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
| 392 | * First, trylock i_mutex. If fails, unlock | ||
| 393 | * sysfs_mutex and lock them in order. | ||
| 394 | */ | ||
| 395 | if (!mutex_trylock(&inode->i_mutex)) { | ||
| 396 | mutex_unlock(&sysfs_mutex); | ||
| 397 | mutex_lock(&inode->i_mutex); | ||
| 398 | mutex_lock(&sysfs_mutex); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | } | 383 | } |
| 402 | 384 | ||
| 403 | /** | 385 | /** |
| @@ -422,18 +404,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 422 | */ | 404 | */ |
| 423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 405 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
| 424 | { | 406 | { |
| 407 | struct sysfs_inode_attrs *ps_iattr; | ||
| 408 | |||
| 425 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) | 409 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) |
| 426 | return -EEXIST; | 410 | return -EEXIST; |
| 427 | 411 | ||
| 428 | sd->s_parent = sysfs_get(acxt->parent_sd); | 412 | sd->s_parent = sysfs_get(acxt->parent_sd); |
| 429 | 413 | ||
| 430 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
| 431 | inc_nlink(acxt->parent_inode); | ||
| 432 | |||
| 433 | acxt->cnt++; | ||
| 434 | |||
| 435 | sysfs_link_sibling(sd); | 414 | sysfs_link_sibling(sd); |
| 436 | 415 | ||
| 416 | /* Update timestamps on the parent */ | ||
| 417 | ps_iattr = acxt->parent_sd->s_iattr; | ||
| 418 | if (ps_iattr) { | ||
| 419 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
| 420 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
| 421 | } | ||
| 422 | |||
| 437 | return 0; | 423 | return 0; |
| 438 | } | 424 | } |
| 439 | 425 | ||
| @@ -512,70 +498,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 512 | */ | 498 | */ |
| 513 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 499 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
| 514 | { | 500 | { |
| 501 | struct sysfs_inode_attrs *ps_iattr; | ||
| 502 | |||
| 515 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 503 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
| 516 | 504 | ||
| 517 | sysfs_unlink_sibling(sd); | 505 | sysfs_unlink_sibling(sd); |
| 518 | 506 | ||
| 507 | /* Update timestamps on the parent */ | ||
| 508 | ps_iattr = acxt->parent_sd->s_iattr; | ||
| 509 | if (ps_iattr) { | ||
| 510 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
| 511 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
| 512 | } | ||
| 513 | |||
| 519 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 514 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
| 520 | sd->s_sibling = acxt->removed; | 515 | sd->s_sibling = acxt->removed; |
| 521 | acxt->removed = sd; | 516 | acxt->removed = sd; |
| 522 | |||
| 523 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
| 524 | drop_nlink(acxt->parent_inode); | ||
| 525 | |||
| 526 | acxt->cnt++; | ||
| 527 | } | ||
| 528 | |||
| 529 | /** | ||
| 530 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
| 531 | * @sd: target sysfs_dirent | ||
| 532 | * | ||
| 533 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
| 534 | * parent on entry to this function such that it can't be looked | ||
| 535 | * up anymore. | ||
| 536 | */ | ||
| 537 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
| 538 | { | ||
| 539 | struct inode *inode; | ||
| 540 | struct dentry *dentry; | ||
| 541 | |||
| 542 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
| 543 | if (!inode) | ||
| 544 | return; | ||
| 545 | |||
| 546 | /* Drop any existing dentries associated with sd. | ||
| 547 | * | ||
| 548 | * For the dentry to be properly freed we need to grab a | ||
| 549 | * reference to the dentry under the dcache lock, unhash it, | ||
| 550 | * and then put it. The playing with the dentry count allows | ||
| 551 | * dput to immediately free the dentry if it is not in use. | ||
| 552 | */ | ||
| 553 | repeat: | ||
| 554 | spin_lock(&dcache_lock); | ||
| 555 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | ||
| 556 | if (d_unhashed(dentry)) | ||
| 557 | continue; | ||
| 558 | dget_locked(dentry); | ||
| 559 | spin_lock(&dentry->d_lock); | ||
| 560 | __d_drop(dentry); | ||
| 561 | spin_unlock(&dentry->d_lock); | ||
| 562 | spin_unlock(&dcache_lock); | ||
| 563 | dput(dentry); | ||
| 564 | goto repeat; | ||
| 565 | } | ||
| 566 | spin_unlock(&dcache_lock); | ||
| 567 | |||
| 568 | /* adjust nlink and update timestamp */ | ||
| 569 | mutex_lock(&inode->i_mutex); | ||
| 570 | |||
| 571 | inode->i_ctime = CURRENT_TIME; | ||
| 572 | drop_nlink(inode); | ||
| 573 | if (sysfs_type(sd) == SYSFS_DIR) | ||
| 574 | drop_nlink(inode); | ||
| 575 | |||
| 576 | mutex_unlock(&inode->i_mutex); | ||
| 577 | |||
| 578 | iput(inode); | ||
| 579 | } | 517 | } |
| 580 | 518 | ||
| 581 | /** | 519 | /** |
| @@ -584,25 +522,15 @@ repeat: | |||
| 584 | * | 522 | * |
| 585 | * Finish up sysfs_dirent add/remove. Resources acquired by | 523 | * Finish up sysfs_dirent add/remove. Resources acquired by |
| 586 | * sysfs_addrm_start() are released and removed sysfs_dirents are | 524 | * sysfs_addrm_start() are released and removed sysfs_dirents are |
| 587 | * cleaned up. Timestamps on the parent inode are updated. | 525 | * cleaned up. |
| 588 | * | 526 | * |
| 589 | * LOCKING: | 527 | * LOCKING: |
| 590 | * All mutexes acquired by sysfs_addrm_start() are released. | 528 | * sysfs_mutex is released. |
| 591 | */ | 529 | */ |
| 592 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 530 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
| 593 | { | 531 | { |
| 594 | /* release resources acquired by sysfs_addrm_start() */ | 532 | /* release resources acquired by sysfs_addrm_start() */ |
| 595 | mutex_unlock(&sysfs_mutex); | 533 | mutex_unlock(&sysfs_mutex); |
| 596 | if (acxt->parent_inode) { | ||
| 597 | struct inode *inode = acxt->parent_inode; | ||
| 598 | |||
| 599 | /* if added/removed, update timestamps on the parent */ | ||
| 600 | if (acxt->cnt) | ||
| 601 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
| 602 | |||
| 603 | mutex_unlock(&inode->i_mutex); | ||
| 604 | iput(inode); | ||
| 605 | } | ||
| 606 | 534 | ||
| 607 | /* kill removed sysfs_dirents */ | 535 | /* kill removed sysfs_dirents */ |
| 608 | while (acxt->removed) { | 536 | while (acxt->removed) { |
| @@ -611,7 +539,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 611 | acxt->removed = sd->s_sibling; | 539 | acxt->removed = sd->s_sibling; |
| 612 | sd->s_sibling = NULL; | 540 | sd->s_sibling = NULL; |
| 613 | 541 | ||
| 614 | sysfs_drop_dentry(sd); | ||
| 615 | sysfs_deactivate(sd); | 542 | sysfs_deactivate(sd); |
| 616 | unmap_bin_file(sd); | 543 | unmap_bin_file(sd); |
| 617 | sysfs_put(sd); | 544 | sysfs_put(sd); |
| @@ -751,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 751 | } | 678 | } |
| 752 | 679 | ||
| 753 | /* instantiate and hash dentry */ | 680 | /* instantiate and hash dentry */ |
| 754 | dentry->d_op = &sysfs_dentry_ops; | 681 | ret = d_find_alias(inode); |
| 755 | dentry->d_fsdata = sysfs_get(sd); | 682 | if (!ret) { |
| 756 | d_instantiate(dentry, inode); | 683 | dentry->d_op = &sysfs_dentry_ops; |
| 757 | d_rehash(dentry); | 684 | dentry->d_fsdata = sysfs_get(sd); |
| 685 | d_add(dentry, inode); | ||
| 686 | } else { | ||
| 687 | d_move(ret, dentry); | ||
| 688 | iput(inode); | ||
| 689 | } | ||
| 758 | 690 | ||
| 759 | out_unlock: | 691 | out_unlock: |
| 760 | mutex_unlock(&sysfs_mutex); | 692 | mutex_unlock(&sysfs_mutex); |
| @@ -763,7 +695,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 763 | 695 | ||
| 764 | const struct inode_operations sysfs_dir_inode_operations = { | 696 | const struct inode_operations sysfs_dir_inode_operations = { |
| 765 | .lookup = sysfs_lookup, | 697 | .lookup = sysfs_lookup, |
| 698 | .permission = sysfs_permission, | ||
| 766 | .setattr = sysfs_setattr, | 699 | .setattr = sysfs_setattr, |
| 700 | .getattr = sysfs_getattr, | ||
| 767 | .setxattr = sysfs_setxattr, | 701 | .setxattr = sysfs_setxattr, |
| 768 | }; | 702 | }; |
| 769 | 703 | ||
| @@ -826,141 +760,65 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
| 826 | __sysfs_remove_dir(sd); | 760 | __sysfs_remove_dir(sd); |
| 827 | } | 761 | } |
| 828 | 762 | ||
| 829 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | 763 | int sysfs_rename(struct sysfs_dirent *sd, |
| 764 | struct sysfs_dirent *new_parent_sd, const char *new_name) | ||
| 830 | { | 765 | { |
| 831 | struct sysfs_dirent *sd = kobj->sd; | ||
| 832 | struct dentry *parent = NULL; | ||
| 833 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
| 834 | const char *dup_name = NULL; | 766 | const char *dup_name = NULL; |
| 835 | int error; | 767 | int error; |
| 836 | 768 | ||
| 837 | mutex_lock(&sysfs_rename_mutex); | 769 | mutex_lock(&sysfs_mutex); |
| 838 | 770 | ||
| 839 | error = 0; | 771 | error = 0; |
| 840 | if (strcmp(sd->s_name, new_name) == 0) | 772 | if ((sd->s_parent == new_parent_sd) && |
| 773 | (strcmp(sd->s_name, new_name) == 0)) | ||
| 841 | goto out; /* nothing to rename */ | 774 | goto out; /* nothing to rename */ |
| 842 | 775 | ||
| 843 | /* get the original dentry */ | ||
| 844 | old_dentry = sysfs_get_dentry(sd); | ||
| 845 | if (IS_ERR(old_dentry)) { | ||
| 846 | error = PTR_ERR(old_dentry); | ||
| 847 | old_dentry = NULL; | ||
| 848 | goto out; | ||
| 849 | } | ||
| 850 | |||
| 851 | parent = old_dentry->d_parent; | ||
| 852 | |||
| 853 | /* lock parent and get dentry for new name */ | ||
| 854 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 855 | mutex_lock(&sysfs_mutex); | ||
| 856 | |||
| 857 | error = -EEXIST; | 776 | error = -EEXIST; |
| 858 | if (sysfs_find_dirent(sd->s_parent, new_name)) | 777 | if (sysfs_find_dirent(new_parent_sd, new_name)) |
| 859 | goto out_unlock; | 778 | goto out; |
| 860 | |||
| 861 | error = -ENOMEM; | ||
| 862 | new_dentry = d_alloc_name(parent, new_name); | ||
| 863 | if (!new_dentry) | ||
| 864 | goto out_unlock; | ||
| 865 | 779 | ||
| 866 | /* rename sysfs_dirent */ | 780 | /* rename sysfs_dirent */ |
| 867 | error = -ENOMEM; | 781 | if (strcmp(sd->s_name, new_name) != 0) { |
| 868 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 782 | error = -ENOMEM; |
| 869 | if (!new_name) | 783 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
| 870 | goto out_unlock; | 784 | if (!new_name) |
| 871 | 785 | goto out; | |
| 872 | dup_name = sd->s_name; | 786 | |
| 873 | sd->s_name = new_name; | 787 | dup_name = sd->s_name; |
| 788 | sd->s_name = new_name; | ||
| 789 | } | ||
| 874 | 790 | ||
| 875 | /* rename */ | 791 | /* Remove from old parent's list and insert into new parent's list. */ |
| 876 | d_add(new_dentry, NULL); | 792 | if (sd->s_parent != new_parent_sd) { |
| 877 | d_move(old_dentry, new_dentry); | 793 | sysfs_unlink_sibling(sd); |
| 794 | sysfs_get(new_parent_sd); | ||
| 795 | sysfs_put(sd->s_parent); | ||
| 796 | sd->s_parent = new_parent_sd; | ||
| 797 | sysfs_link_sibling(sd); | ||
| 798 | } | ||
| 878 | 799 | ||
| 879 | error = 0; | 800 | error = 0; |
| 880 | out_unlock: | 801 | out: |
| 881 | mutex_unlock(&sysfs_mutex); | 802 | mutex_unlock(&sysfs_mutex); |
| 882 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 883 | kfree(dup_name); | 803 | kfree(dup_name); |
| 884 | dput(old_dentry); | ||
| 885 | dput(new_dentry); | ||
| 886 | out: | ||
| 887 | mutex_unlock(&sysfs_rename_mutex); | ||
| 888 | return error; | 804 | return error; |
| 889 | } | 805 | } |
| 890 | 806 | ||
| 807 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | ||
| 808 | { | ||
| 809 | return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); | ||
| 810 | } | ||
| 811 | |||
| 891 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 812 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
| 892 | { | 813 | { |
| 893 | struct sysfs_dirent *sd = kobj->sd; | 814 | struct sysfs_dirent *sd = kobj->sd; |
| 894 | struct sysfs_dirent *new_parent_sd; | 815 | struct sysfs_dirent *new_parent_sd; |
| 895 | struct dentry *old_parent, *new_parent = NULL; | ||
| 896 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
| 897 | int error; | ||
| 898 | 816 | ||
| 899 | mutex_lock(&sysfs_rename_mutex); | ||
| 900 | BUG_ON(!sd->s_parent); | 817 | BUG_ON(!sd->s_parent); |
| 901 | new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? | 818 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
| 902 | new_parent_kobj->sd : &sysfs_root; | 819 | new_parent_kobj->sd : &sysfs_root; |
| 903 | 820 | ||
| 904 | error = 0; | 821 | return sysfs_rename(sd, new_parent_sd, sd->s_name); |
| 905 | if (sd->s_parent == new_parent_sd) | ||
| 906 | goto out; /* nothing to move */ | ||
| 907 | |||
| 908 | /* get dentries */ | ||
| 909 | old_dentry = sysfs_get_dentry(sd); | ||
| 910 | if (IS_ERR(old_dentry)) { | ||
| 911 | error = PTR_ERR(old_dentry); | ||
| 912 | old_dentry = NULL; | ||
| 913 | goto out; | ||
| 914 | } | ||
| 915 | old_parent = old_dentry->d_parent; | ||
| 916 | |||
| 917 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
| 918 | if (IS_ERR(new_parent)) { | ||
| 919 | error = PTR_ERR(new_parent); | ||
| 920 | new_parent = NULL; | ||
| 921 | goto out; | ||
| 922 | } | ||
| 923 | |||
| 924 | again: | ||
| 925 | mutex_lock(&old_parent->d_inode->i_mutex); | ||
| 926 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | ||
| 927 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
| 928 | goto again; | ||
| 929 | } | ||
| 930 | mutex_lock(&sysfs_mutex); | ||
| 931 | |||
| 932 | error = -EEXIST; | ||
| 933 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) | ||
| 934 | goto out_unlock; | ||
| 935 | |||
| 936 | error = -ENOMEM; | ||
| 937 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
| 938 | if (!new_dentry) | ||
| 939 | goto out_unlock; | ||
| 940 | |||
| 941 | error = 0; | ||
| 942 | d_add(new_dentry, NULL); | ||
| 943 | d_move(old_dentry, new_dentry); | ||
| 944 | |||
| 945 | /* Remove from old parent's list and insert into new parent's list. */ | ||
| 946 | sysfs_unlink_sibling(sd); | ||
| 947 | sysfs_get(new_parent_sd); | ||
| 948 | drop_nlink(old_parent->d_inode); | ||
| 949 | sysfs_put(sd->s_parent); | ||
| 950 | sd->s_parent = new_parent_sd; | ||
| 951 | inc_nlink(new_parent->d_inode); | ||
| 952 | sysfs_link_sibling(sd); | ||
| 953 | |||
| 954 | out_unlock: | ||
| 955 | mutex_unlock(&sysfs_mutex); | ||
| 956 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
| 957 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
| 958 | out: | ||
| 959 | dput(new_parent); | ||
| 960 | dput(old_dentry); | ||
| 961 | dput(new_dentry); | ||
| 962 | mutex_unlock(&sysfs_rename_mutex); | ||
| 963 | return error; | ||
| 964 | } | 822 | } |
| 965 | 823 | ||
| 966 | /* Relationship between s_mode and the DT_xxx types */ | 824 | /* Relationship between s_mode and the DT_xxx types */ |
