diff options
Diffstat (limited to 'fs/sysfs/dir.c')
| -rw-r--r-- | fs/sysfs/dir.c | 350 |
1 files changed, 222 insertions, 128 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 4d83cedb9fcb..5e73d6626e50 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -26,21 +26,21 @@ | |||
| 26 | #include "sysfs.h" | 26 | #include "sysfs.h" |
| 27 | 27 | ||
| 28 | DEFINE_MUTEX(sysfs_mutex); | 28 | DEFINE_MUTEX(sysfs_mutex); |
| 29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 29 | DEFINE_SPINLOCK(sysfs_symlink_target_lock); |
| 30 | 30 | ||
| 31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb); | 31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb) |
| 32 | 32 | ||
| 33 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 33 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
| 34 | static DEFINE_IDA(sysfs_ino_ida); | 34 | static DEFINE_IDA(sysfs_ino_ida); |
| 35 | 35 | ||
| 36 | /** | 36 | /** |
| 37 | * sysfs_name_hash | 37 | * sysfs_name_hash |
| 38 | * @ns: Namespace tag to hash | ||
| 39 | * @name: Null terminated string to hash | 38 | * @name: Null terminated string to hash |
| 39 | * @ns: Namespace tag to hash | ||
| 40 | * | 40 | * |
| 41 | * Returns 31 bit hash of ns + name (so it fits in an off_t ) | 41 | * Returns 31 bit hash of ns + name (so it fits in an off_t ) |
| 42 | */ | 42 | */ |
| 43 | static unsigned int sysfs_name_hash(const void *ns, const char *name) | 43 | static unsigned int sysfs_name_hash(const char *name, const void *ns) |
| 44 | { | 44 | { |
| 45 | unsigned long hash = init_name_hash(); | 45 | unsigned long hash = init_name_hash(); |
| 46 | unsigned int len = strlen(name); | 46 | unsigned int len = strlen(name); |
| @@ -56,8 +56,8 @@ static unsigned int sysfs_name_hash(const void *ns, const char *name) | |||
| 56 | return hash; | 56 | return hash; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static int sysfs_name_compare(unsigned int hash, const void *ns, | 59 | static int sysfs_name_compare(unsigned int hash, const char *name, |
| 60 | const char *name, const struct sysfs_dirent *sd) | 60 | const void *ns, const struct sysfs_dirent *sd) |
| 61 | { | 61 | { |
| 62 | if (hash != sd->s_hash) | 62 | if (hash != sd->s_hash) |
| 63 | return hash - sd->s_hash; | 63 | return hash - sd->s_hash; |
| @@ -69,7 +69,7 @@ static int sysfs_name_compare(unsigned int hash, const void *ns, | |||
| 69 | static int sysfs_sd_compare(const struct sysfs_dirent *left, | 69 | static int sysfs_sd_compare(const struct sysfs_dirent *left, |
| 70 | const struct sysfs_dirent *right) | 70 | const struct sysfs_dirent *right) |
| 71 | { | 71 | { |
| 72 | return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name, | 72 | return sysfs_name_compare(left->s_hash, left->s_name, left->s_ns, |
| 73 | right); | 73 | right); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| @@ -132,24 +132,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
| 132 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); | 132 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 136 | |||
| 137 | /* Test for attributes that want to ignore lockdep for read-locking */ | ||
| 138 | static bool ignore_lockdep(struct sysfs_dirent *sd) | ||
| 139 | { | ||
| 140 | return sysfs_type(sd) == SYSFS_KOBJ_ATTR && | ||
| 141 | sd->s_attr.attr->ignore_lockdep; | ||
| 142 | } | ||
| 143 | |||
| 144 | #else | ||
| 145 | |||
| 146 | static inline bool ignore_lockdep(struct sysfs_dirent *sd) | ||
| 147 | { | ||
| 148 | return true; | ||
| 149 | } | ||
| 150 | |||
| 151 | #endif | ||
| 152 | |||
| 153 | /** | 135 | /** |
| 154 | * sysfs_get_active - get an active reference to sysfs_dirent | 136 | * sysfs_get_active - get an active reference to sysfs_dirent |
| 155 | * @sd: sysfs_dirent to get an active reference to | 137 | * @sd: sysfs_dirent to get an active reference to |
| @@ -168,7 +150,7 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
| 168 | if (!atomic_inc_unless_negative(&sd->s_active)) | 150 | if (!atomic_inc_unless_negative(&sd->s_active)) |
| 169 | return NULL; | 151 | return NULL; |
| 170 | 152 | ||
| 171 | if (likely(!ignore_lockdep(sd))) | 153 | if (likely(!sysfs_ignore_lockdep(sd))) |
| 172 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); | 154 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); |
| 173 | return sd; | 155 | return sd; |
| 174 | } | 156 | } |
| @@ -187,7 +169,7 @@ void sysfs_put_active(struct sysfs_dirent *sd) | |||
| 187 | if (unlikely(!sd)) | 169 | if (unlikely(!sd)) |
| 188 | return; | 170 | return; |
| 189 | 171 | ||
| 190 | if (likely(!ignore_lockdep(sd))) | 172 | if (likely(!sysfs_ignore_lockdep(sd))) |
| 191 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | 173 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
| 192 | v = atomic_dec_return(&sd->s_active); | 174 | v = atomic_dec_return(&sd->s_active); |
| 193 | if (likely(v != SD_DEACTIVATED_BIAS)) | 175 | if (likely(v != SD_DEACTIVATED_BIAS)) |
| @@ -400,22 +382,19 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
| 400 | /** | 382 | /** |
| 401 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 383 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
| 402 | * @acxt: pointer to sysfs_addrm_cxt to be used | 384 | * @acxt: pointer to sysfs_addrm_cxt to be used |
| 403 | * @parent_sd: parent sysfs_dirent | ||
| 404 | * | 385 | * |
| 405 | * This function is called when the caller is about to add or | 386 | * This function is called when the caller is about to add or remove |
| 406 | * remove sysfs_dirent under @parent_sd. This function acquires | 387 | * sysfs_dirent. This function acquires sysfs_mutex. @acxt is used |
| 407 | * sysfs_mutex. @acxt is used to keep and pass context to | 388 | * to keep and pass context to other addrm functions. |
| 408 | * other addrm functions. | ||
| 409 | * | 389 | * |
| 410 | * LOCKING: | 390 | * LOCKING: |
| 411 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 391 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
| 412 | * return. | 392 | * return. |
| 413 | */ | 393 | */ |
| 414 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 394 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) |
| 415 | struct sysfs_dirent *parent_sd) | 395 | __acquires(sysfs_mutex) |
| 416 | { | 396 | { |
| 417 | memset(acxt, 0, sizeof(*acxt)); | 397 | memset(acxt, 0, sizeof(*acxt)); |
| 418 | acxt->parent_sd = parent_sd; | ||
| 419 | 398 | ||
| 420 | mutex_lock(&sysfs_mutex); | 399 | mutex_lock(&sysfs_mutex); |
| 421 | } | 400 | } |
| @@ -424,10 +403,11 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 424 | * __sysfs_add_one - add sysfs_dirent to parent without warning | 403 | * __sysfs_add_one - add sysfs_dirent to parent without warning |
| 425 | * @acxt: addrm context to use | 404 | * @acxt: addrm context to use |
| 426 | * @sd: sysfs_dirent to be added | 405 | * @sd: sysfs_dirent to be added |
| 406 | * @parent_sd: the parent sysfs_dirent to add @sd to | ||
| 427 | * | 407 | * |
| 428 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 408 | * Get @parent_sd and set @sd->s_parent to it and increment nlink of |
| 429 | * nlink of parent inode if @sd is a directory and link into the | 409 | * the parent inode if @sd is a directory and link into the children |
| 430 | * children list of the parent. | 410 | * list of the parent. |
| 431 | * | 411 | * |
| 432 | * This function should be called between calls to | 412 | * This function should be called between calls to |
| 433 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 413 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
| @@ -440,27 +420,28 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
| 440 | * 0 on success, -EEXIST if entry with the given name already | 420 | * 0 on success, -EEXIST if entry with the given name already |
| 441 | * exists. | 421 | * exists. |
| 442 | */ | 422 | */ |
| 443 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 424 | struct sysfs_dirent *parent_sd) | ||
| 444 | { | 425 | { |
| 445 | struct sysfs_inode_attrs *ps_iattr; | 426 | struct sysfs_inode_attrs *ps_iattr; |
| 446 | int ret; | 427 | int ret; |
| 447 | 428 | ||
| 448 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { | 429 | if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) { |
| 449 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 430 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
| 450 | sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid", | 431 | sysfs_ns_type(parent_sd) ? "required" : "invalid", |
| 451 | acxt->parent_sd->s_name, sd->s_name); | 432 | parent_sd->s_name, sd->s_name); |
| 452 | return -EINVAL; | 433 | return -EINVAL; |
| 453 | } | 434 | } |
| 454 | 435 | ||
| 455 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | 436 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
| 456 | sd->s_parent = sysfs_get(acxt->parent_sd); | 437 | sd->s_parent = sysfs_get(parent_sd); |
| 457 | 438 | ||
| 458 | ret = sysfs_link_sibling(sd); | 439 | ret = sysfs_link_sibling(sd); |
| 459 | if (ret) | 440 | if (ret) |
| 460 | return ret; | 441 | return ret; |
| 461 | 442 | ||
| 462 | /* Update timestamps on the parent */ | 443 | /* Update timestamps on the parent */ |
| 463 | ps_iattr = acxt->parent_sd->s_iattr; | 444 | ps_iattr = parent_sd->s_iattr; |
| 464 | if (ps_iattr) { | 445 | if (ps_iattr) { |
| 465 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | 446 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; |
| 466 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | 447 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; |
| @@ -490,14 +471,32 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) | |||
| 490 | return path; | 471 | return path; |
| 491 | } | 472 | } |
| 492 | 473 | ||
| 474 | void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name) | ||
| 475 | { | ||
| 476 | char *path; | ||
| 477 | |||
| 478 | path = kzalloc(PATH_MAX, GFP_KERNEL); | ||
| 479 | if (path) { | ||
| 480 | sysfs_pathname(parent, path); | ||
| 481 | strlcat(path, "/", PATH_MAX); | ||
| 482 | strlcat(path, name, PATH_MAX); | ||
| 483 | } | ||
| 484 | |||
| 485 | WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n", | ||
| 486 | path ? path : name); | ||
| 487 | |||
| 488 | kfree(path); | ||
| 489 | } | ||
| 490 | |||
| 493 | /** | 491 | /** |
| 494 | * sysfs_add_one - add sysfs_dirent to parent | 492 | * sysfs_add_one - add sysfs_dirent to parent |
| 495 | * @acxt: addrm context to use | 493 | * @acxt: addrm context to use |
| 496 | * @sd: sysfs_dirent to be added | 494 | * @sd: sysfs_dirent to be added |
| 495 | * @parent_sd: the parent sysfs_dirent to add @sd to | ||
| 497 | * | 496 | * |
| 498 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 497 | * Get @parent_sd and set @sd->s_parent to it and increment nlink of |
| 499 | * nlink of parent inode if @sd is a directory and link into the | 498 | * the parent inode if @sd is a directory and link into the children |
| 500 | * children list of the parent. | 499 | * list of the parent. |
| 501 | * | 500 | * |
| 502 | * This function should be called between calls to | 501 | * This function should be called between calls to |
| 503 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 502 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
| @@ -510,23 +509,15 @@ static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) | |||
| 510 | * 0 on success, -EEXIST if entry with the given name already | 509 | * 0 on success, -EEXIST if entry with the given name already |
| 511 | * exists. | 510 | * exists. |
| 512 | */ | 511 | */ |
| 513 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 512 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
| 513 | struct sysfs_dirent *parent_sd) | ||
| 514 | { | 514 | { |
| 515 | int ret; | 515 | int ret; |
| 516 | 516 | ||
| 517 | ret = __sysfs_add_one(acxt, sd); | 517 | ret = __sysfs_add_one(acxt, sd, parent_sd); |
| 518 | if (ret == -EEXIST) { | ||
| 519 | char *path = kzalloc(PATH_MAX, GFP_KERNEL); | ||
| 520 | WARN(1, KERN_WARNING | ||
| 521 | "sysfs: cannot create duplicate filename '%s'\n", | ||
| 522 | (path == NULL) ? sd->s_name | ||
| 523 | : (sysfs_pathname(acxt->parent_sd, path), | ||
| 524 | strlcat(path, "/", PATH_MAX), | ||
| 525 | strlcat(path, sd->s_name, PATH_MAX), | ||
| 526 | path)); | ||
| 527 | kfree(path); | ||
| 528 | } | ||
| 529 | 518 | ||
| 519 | if (ret == -EEXIST) | ||
| 520 | sysfs_warn_dup(parent_sd, sd->s_name); | ||
| 530 | return ret; | 521 | return ret; |
| 531 | } | 522 | } |
| 532 | 523 | ||
| @@ -545,16 +536,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 545 | * LOCKING: | 536 | * LOCKING: |
| 546 | * Determined by sysfs_addrm_start(). | 537 | * Determined by sysfs_addrm_start(). |
| 547 | */ | 538 | */ |
| 548 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 539 | static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, |
| 540 | struct sysfs_dirent *sd) | ||
| 549 | { | 541 | { |
| 550 | struct sysfs_inode_attrs *ps_iattr; | 542 | struct sysfs_inode_attrs *ps_iattr; |
| 551 | 543 | ||
| 552 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 544 | /* |
| 545 | * Removal can be called multiple times on the same node. Only the | ||
| 546 | * first invocation is effective and puts the base ref. | ||
| 547 | */ | ||
| 548 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
| 549 | return; | ||
| 553 | 550 | ||
| 554 | sysfs_unlink_sibling(sd); | 551 | sysfs_unlink_sibling(sd); |
| 555 | 552 | ||
| 556 | /* Update timestamps on the parent */ | 553 | /* Update timestamps on the parent */ |
| 557 | ps_iattr = acxt->parent_sd->s_iattr; | 554 | ps_iattr = sd->s_parent->s_iattr; |
| 558 | if (ps_iattr) { | 555 | if (ps_iattr) { |
| 559 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | 556 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; |
| 560 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | 557 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; |
| @@ -577,6 +574,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 577 | * sysfs_mutex is released. | 574 | * sysfs_mutex is released. |
| 578 | */ | 575 | */ |
| 579 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 576 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
| 577 | __releases(sysfs_mutex) | ||
| 580 | { | 578 | { |
| 581 | /* release resources acquired by sysfs_addrm_start() */ | 579 | /* release resources acquired by sysfs_addrm_start() */ |
| 582 | mutex_unlock(&sysfs_mutex); | 580 | mutex_unlock(&sysfs_mutex); |
| @@ -588,7 +586,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 588 | acxt->removed = sd->u.removed_list; | 586 | acxt->removed = sd->u.removed_list; |
| 589 | 587 | ||
| 590 | sysfs_deactivate(sd); | 588 | sysfs_deactivate(sd); |
| 591 | unmap_bin_file(sd); | 589 | sysfs_unmap_bin_file(sd); |
| 592 | sysfs_put(sd); | 590 | sysfs_put(sd); |
| 593 | } | 591 | } |
| 594 | } | 592 | } |
| @@ -597,6 +595,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 597 | * sysfs_find_dirent - find sysfs_dirent with the given name | 595 | * sysfs_find_dirent - find sysfs_dirent with the given name |
| 598 | * @parent_sd: sysfs_dirent to search under | 596 | * @parent_sd: sysfs_dirent to search under |
| 599 | * @name: name to look for | 597 | * @name: name to look for |
| 598 | * @ns: the namespace tag to use | ||
| 600 | * | 599 | * |
| 601 | * Look for sysfs_dirent with name @name under @parent_sd. | 600 | * Look for sysfs_dirent with name @name under @parent_sd. |
| 602 | * | 601 | * |
| @@ -607,8 +606,8 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
| 607 | * Pointer to sysfs_dirent if found, NULL if not. | 606 | * Pointer to sysfs_dirent if found, NULL if not. |
| 608 | */ | 607 | */ |
| 609 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 608 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, |
| 610 | const void *ns, | 609 | const unsigned char *name, |
| 611 | const unsigned char *name) | 610 | const void *ns) |
| 612 | { | 611 | { |
| 613 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 612 | struct rb_node *node = parent_sd->s_dir.children.rb_node; |
| 614 | unsigned int hash; | 613 | unsigned int hash; |
| @@ -620,13 +619,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
| 620 | return NULL; | 619 | return NULL; |
| 621 | } | 620 | } |
| 622 | 621 | ||
| 623 | hash = sysfs_name_hash(ns, name); | 622 | hash = sysfs_name_hash(name, ns); |
| 624 | while (node) { | 623 | while (node) { |
| 625 | struct sysfs_dirent *sd; | 624 | struct sysfs_dirent *sd; |
| 626 | int result; | 625 | int result; |
| 627 | 626 | ||
| 628 | sd = to_sysfs_dirent(node); | 627 | sd = to_sysfs_dirent(node); |
| 629 | result = sysfs_name_compare(hash, ns, name, sd); | 628 | result = sysfs_name_compare(hash, name, ns, sd); |
| 630 | if (result < 0) | 629 | if (result < 0) |
| 631 | node = node->rb_left; | 630 | node = node->rb_left; |
| 632 | else if (result > 0) | 631 | else if (result > 0) |
| @@ -638,9 +637,10 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
| 638 | } | 637 | } |
| 639 | 638 | ||
| 640 | /** | 639 | /** |
| 641 | * sysfs_get_dirent - find and get sysfs_dirent with the given name | 640 | * sysfs_get_dirent_ns - find and get sysfs_dirent with the given name |
| 642 | * @parent_sd: sysfs_dirent to search under | 641 | * @parent_sd: sysfs_dirent to search under |
| 643 | * @name: name to look for | 642 | * @name: name to look for |
| 643 | * @ns: the namespace tag to use | ||
| 644 | * | 644 | * |
| 645 | * Look for sysfs_dirent with name @name under @parent_sd and get | 645 | * Look for sysfs_dirent with name @name under @parent_sd and get |
| 646 | * it if found. | 646 | * it if found. |
| @@ -651,24 +651,25 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
| 651 | * RETURNS: | 651 | * RETURNS: |
| 652 | * Pointer to sysfs_dirent if found, NULL if not. | 652 | * Pointer to sysfs_dirent if found, NULL if not. |
| 653 | */ | 653 | */ |
| 654 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 654 | struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, |
| 655 | const void *ns, | 655 | const unsigned char *name, |
| 656 | const unsigned char *name) | 656 | const void *ns) |
| 657 | { | 657 | { |
| 658 | struct sysfs_dirent *sd; | 658 | struct sysfs_dirent *sd; |
| 659 | 659 | ||
| 660 | mutex_lock(&sysfs_mutex); | 660 | mutex_lock(&sysfs_mutex); |
| 661 | sd = sysfs_find_dirent(parent_sd, ns, name); | 661 | sd = sysfs_find_dirent(parent_sd, name, ns); |
| 662 | sysfs_get(sd); | 662 | sysfs_get(sd); |
| 663 | mutex_unlock(&sysfs_mutex); | 663 | mutex_unlock(&sysfs_mutex); |
| 664 | 664 | ||
| 665 | return sd; | 665 | return sd; |
| 666 | } | 666 | } |
| 667 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); | 667 | EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); |
| 668 | 668 | ||
| 669 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | 669 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, |
| 670 | enum kobj_ns_type type, const void *ns, const char *name, | 670 | enum kobj_ns_type type, |
| 671 | struct sysfs_dirent **p_sd) | 671 | const char *name, const void *ns, |
| 672 | struct sysfs_dirent **p_sd) | ||
| 672 | { | 673 | { |
| 673 | umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; | 674 | umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; |
| 674 | struct sysfs_addrm_cxt acxt; | 675 | struct sysfs_addrm_cxt acxt; |
| @@ -685,8 +686,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
| 685 | sd->s_dir.kobj = kobj; | 686 | sd->s_dir.kobj = kobj; |
| 686 | 687 | ||
| 687 | /* link in */ | 688 | /* link in */ |
| 688 | sysfs_addrm_start(&acxt, parent_sd); | 689 | sysfs_addrm_start(&acxt); |
| 689 | rc = sysfs_add_one(&acxt, sd); | 690 | rc = sysfs_add_one(&acxt, sd, parent_sd); |
| 690 | sysfs_addrm_finish(&acxt); | 691 | sysfs_addrm_finish(&acxt); |
| 691 | 692 | ||
| 692 | if (rc == 0) | 693 | if (rc == 0) |
| @@ -701,7 +702,7 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
| 701 | struct sysfs_dirent **p_sd) | 702 | struct sysfs_dirent **p_sd) |
| 702 | { | 703 | { |
| 703 | return create_dir(kobj, kobj->sd, | 704 | return create_dir(kobj, kobj->sd, |
| 704 | KOBJ_NS_TYPE_NONE, NULL, name, p_sd); | 705 | KOBJ_NS_TYPE_NONE, name, NULL, p_sd); |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 707 | /** | 708 | /** |
| @@ -730,14 +731,14 @@ static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) | |||
| 730 | } | 731 | } |
| 731 | 732 | ||
| 732 | /** | 733 | /** |
| 733 | * sysfs_create_dir - create a directory for an object. | 734 | * sysfs_create_dir_ns - create a directory for an object with a namespace tag |
| 734 | * @kobj: object we're creating directory for. | 735 | * @kobj: object we're creating directory for |
| 736 | * @ns: the namespace tag to use | ||
| 735 | */ | 737 | */ |
| 736 | int sysfs_create_dir(struct kobject *kobj) | 738 | int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) |
| 737 | { | 739 | { |
| 738 | enum kobj_ns_type type; | 740 | enum kobj_ns_type type; |
| 739 | struct sysfs_dirent *parent_sd, *sd; | 741 | struct sysfs_dirent *parent_sd, *sd; |
| 740 | const void *ns = NULL; | ||
| 741 | int error = 0; | 742 | int error = 0; |
| 742 | 743 | ||
| 743 | BUG_ON(!kobj); | 744 | BUG_ON(!kobj); |
| @@ -750,11 +751,9 @@ int sysfs_create_dir(struct kobject *kobj) | |||
| 750 | if (!parent_sd) | 751 | if (!parent_sd) |
| 751 | return -ENOENT; | 752 | return -ENOENT; |
| 752 | 753 | ||
| 753 | if (sysfs_ns_type(parent_sd)) | ||
| 754 | ns = kobj->ktype->namespace(kobj); | ||
| 755 | type = sysfs_read_ns_type(kobj); | 754 | type = sysfs_read_ns_type(kobj); |
| 756 | 755 | ||
| 757 | error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd); | 756 | error = create_dir(kobj, parent_sd, type, kobject_name(kobj), ns, &sd); |
| 758 | if (!error) | 757 | if (!error) |
| 759 | kobj->sd = sd; | 758 | kobj->sd = sd; |
| 760 | return error; | 759 | return error; |
| @@ -776,7 +775,7 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 776 | type = sysfs_ns_type(parent_sd); | 775 | type = sysfs_ns_type(parent_sd); |
| 777 | ns = sysfs_info(dir->i_sb)->ns[type]; | 776 | ns = sysfs_info(dir->i_sb)->ns[type]; |
| 778 | 777 | ||
| 779 | sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name); | 778 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); |
| 780 | 779 | ||
| 781 | /* no such entry */ | 780 | /* no such entry */ |
| 782 | if (!sd) { | 781 | if (!sd) { |
| @@ -807,41 +806,128 @@ const struct inode_operations sysfs_dir_inode_operations = { | |||
| 807 | .setxattr = sysfs_setxattr, | 806 | .setxattr = sysfs_setxattr, |
| 808 | }; | 807 | }; |
| 809 | 808 | ||
| 810 | static void remove_dir(struct sysfs_dirent *sd) | 809 | static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos) |
| 811 | { | 810 | { |
| 812 | struct sysfs_addrm_cxt acxt; | 811 | struct sysfs_dirent *last; |
| 813 | 812 | ||
| 814 | sysfs_addrm_start(&acxt, sd->s_parent); | 813 | while (true) { |
| 815 | sysfs_remove_one(&acxt, sd); | 814 | struct rb_node *rbn; |
| 816 | sysfs_addrm_finish(&acxt); | 815 | |
| 816 | last = pos; | ||
| 817 | |||
| 818 | if (sysfs_type(pos) != SYSFS_DIR) | ||
| 819 | break; | ||
| 820 | |||
| 821 | rbn = rb_first(&pos->s_dir.children); | ||
| 822 | if (!rbn) | ||
| 823 | break; | ||
| 824 | |||
| 825 | pos = to_sysfs_dirent(rbn); | ||
| 826 | } | ||
| 827 | |||
| 828 | return last; | ||
| 817 | } | 829 | } |
| 818 | 830 | ||
| 819 | void sysfs_remove_subdir(struct sysfs_dirent *sd) | 831 | /** |
| 832 | * sysfs_next_descendant_post - find the next descendant for post-order walk | ||
| 833 | * @pos: the current position (%NULL to initiate traversal) | ||
| 834 | * @root: sysfs_dirent whose descendants to walk | ||
| 835 | * | ||
| 836 | * Find the next descendant to visit for post-order traversal of @root's | ||
| 837 | * descendants. @root is included in the iteration and the last node to be | ||
| 838 | * visited. | ||
| 839 | */ | ||
| 840 | static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos, | ||
| 841 | struct sysfs_dirent *root) | ||
| 820 | { | 842 | { |
| 821 | remove_dir(sd); | 843 | struct rb_node *rbn; |
| 844 | |||
| 845 | lockdep_assert_held(&sysfs_mutex); | ||
| 846 | |||
| 847 | /* if first iteration, visit leftmost descendant which may be root */ | ||
| 848 | if (!pos) | ||
| 849 | return sysfs_leftmost_descendant(root); | ||
| 850 | |||
| 851 | /* if we visited @root, we're done */ | ||
| 852 | if (pos == root) | ||
| 853 | return NULL; | ||
| 854 | |||
| 855 | /* if there's an unvisited sibling, visit its leftmost descendant */ | ||
| 856 | rbn = rb_next(&pos->s_rb); | ||
| 857 | if (rbn) | ||
| 858 | return sysfs_leftmost_descendant(to_sysfs_dirent(rbn)); | ||
| 859 | |||
| 860 | /* no sibling left, visit parent */ | ||
| 861 | return pos->s_parent; | ||
| 822 | } | 862 | } |
| 823 | 863 | ||
| 864 | static void __sysfs_remove(struct sysfs_addrm_cxt *acxt, | ||
| 865 | struct sysfs_dirent *sd) | ||
| 866 | { | ||
| 867 | struct sysfs_dirent *pos, *next; | ||
| 868 | |||
| 869 | if (!sd) | ||
| 870 | return; | ||
| 824 | 871 | ||
| 825 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 872 | pr_debug("sysfs %s: removing\n", sd->s_name); |
| 873 | |||
| 874 | next = NULL; | ||
| 875 | do { | ||
| 876 | pos = next; | ||
| 877 | next = sysfs_next_descendant_post(pos, sd); | ||
| 878 | if (pos) | ||
| 879 | sysfs_remove_one(acxt, pos); | ||
| 880 | } while (next); | ||
| 881 | } | ||
| 882 | |||
| 883 | /** | ||
| 884 | * sysfs_remove - remove a sysfs_dirent recursively | ||
| 885 | * @sd: the sysfs_dirent to remove | ||
| 886 | * | ||
| 887 | * Remove @sd along with all its subdirectories and files. | ||
| 888 | */ | ||
| 889 | void sysfs_remove(struct sysfs_dirent *sd) | ||
| 826 | { | 890 | { |
| 827 | struct sysfs_addrm_cxt acxt; | 891 | struct sysfs_addrm_cxt acxt; |
| 828 | struct rb_node *pos; | ||
| 829 | 892 | ||
| 830 | if (!dir_sd) | 893 | sysfs_addrm_start(&acxt); |
| 831 | return; | 894 | __sysfs_remove(&acxt, sd); |
| 895 | sysfs_addrm_finish(&acxt); | ||
| 896 | } | ||
| 832 | 897 | ||
| 833 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 898 | /** |
| 834 | sysfs_addrm_start(&acxt, dir_sd); | 899 | * sysfs_hash_and_remove - find a sysfs_dirent by name and remove it |
| 835 | pos = rb_first(&dir_sd->s_dir.children); | 900 | * @dir_sd: parent of the target |
| 836 | while (pos) { | 901 | * @name: name of the sysfs_dirent to remove |
| 837 | struct sysfs_dirent *sd = to_sysfs_dirent(pos); | 902 | * @ns: namespace tag of the sysfs_dirent to remove |
| 838 | pos = rb_next(pos); | 903 | * |
| 839 | if (sysfs_type(sd) != SYSFS_DIR) | 904 | * Look for the sysfs_dirent with @name and @ns under @dir_sd and remove |
| 840 | sysfs_remove_one(&acxt, sd); | 905 | * it. Returns 0 on success, -ENOENT if such entry doesn't exist. |
| 906 | */ | ||
| 907 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, | ||
| 908 | const void *ns) | ||
| 909 | { | ||
| 910 | struct sysfs_addrm_cxt acxt; | ||
| 911 | struct sysfs_dirent *sd; | ||
| 912 | |||
| 913 | if (!dir_sd) { | ||
| 914 | WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", | ||
| 915 | name); | ||
| 916 | return -ENOENT; | ||
| 841 | } | 917 | } |
| 918 | |||
| 919 | sysfs_addrm_start(&acxt); | ||
| 920 | |||
| 921 | sd = sysfs_find_dirent(dir_sd, name, ns); | ||
| 922 | if (sd) | ||
| 923 | __sysfs_remove(&acxt, sd); | ||
| 924 | |||
| 842 | sysfs_addrm_finish(&acxt); | 925 | sysfs_addrm_finish(&acxt); |
| 843 | 926 | ||
| 844 | remove_dir(dir_sd); | 927 | if (sd) |
| 928 | return 0; | ||
| 929 | else | ||
| 930 | return -ENOENT; | ||
| 845 | } | 931 | } |
| 846 | 932 | ||
| 847 | /** | 933 | /** |
| @@ -852,21 +938,34 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | |||
| 852 | * the directory before we remove the directory, and we've inlined | 938 | * the directory before we remove the directory, and we've inlined |
| 853 | * what used to be sysfs_rmdir() below, instead of calling separately. | 939 | * what used to be sysfs_rmdir() below, instead of calling separately. |
| 854 | */ | 940 | */ |
| 855 | |||
| 856 | void sysfs_remove_dir(struct kobject *kobj) | 941 | void sysfs_remove_dir(struct kobject *kobj) |
| 857 | { | 942 | { |
| 858 | struct sysfs_dirent *sd = kobj->sd; | 943 | struct sysfs_dirent *sd = kobj->sd; |
| 859 | 944 | ||
| 860 | spin_lock(&sysfs_assoc_lock); | 945 | /* |
| 946 | * In general, kboject owner is responsible for ensuring removal | ||
| 947 | * doesn't race with other operations and sysfs doesn't provide any | ||
| 948 | * protection; however, when @kobj is used as a symlink target, the | ||
| 949 | * symlinking entity usually doesn't own @kobj and thus has no | ||
| 950 | * control over removal. @kobj->sd may be removed anytime and | ||
| 951 | * symlink code may end up dereferencing an already freed sd. | ||
| 952 | * | ||
| 953 | * sysfs_symlink_target_lock synchronizes @kobj->sd disassociation | ||
| 954 | * against symlink operations so that symlink code can safely | ||
| 955 | * dereference @kobj->sd. | ||
| 956 | */ | ||
| 957 | spin_lock(&sysfs_symlink_target_lock); | ||
| 861 | kobj->sd = NULL; | 958 | kobj->sd = NULL; |
| 862 | spin_unlock(&sysfs_assoc_lock); | 959 | spin_unlock(&sysfs_symlink_target_lock); |
| 863 | 960 | ||
| 864 | __sysfs_remove_dir(sd); | 961 | if (sd) { |
| 962 | WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); | ||
| 963 | sysfs_remove(sd); | ||
| 964 | } | ||
| 865 | } | 965 | } |
| 866 | 966 | ||
| 867 | int sysfs_rename(struct sysfs_dirent *sd, | 967 | int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, |
| 868 | struct sysfs_dirent *new_parent_sd, const void *new_ns, | 968 | const char *new_name, const void *new_ns) |
| 869 | const char *new_name) | ||
| 870 | { | 969 | { |
| 871 | int error; | 970 | int error; |
| 872 | 971 | ||
| @@ -878,7 +977,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 878 | goto out; /* nothing to rename */ | 977 | goto out; /* nothing to rename */ |
| 879 | 978 | ||
| 880 | error = -EEXIST; | 979 | error = -EEXIST; |
| 881 | if (sysfs_find_dirent(new_parent_sd, new_ns, new_name)) | 980 | if (sysfs_find_dirent(new_parent_sd, new_name, new_ns)) |
| 882 | goto out; | 981 | goto out; |
| 883 | 982 | ||
| 884 | /* rename sysfs_dirent */ | 983 | /* rename sysfs_dirent */ |
| @@ -899,7 +998,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 899 | sysfs_get(new_parent_sd); | 998 | sysfs_get(new_parent_sd); |
| 900 | sysfs_put(sd->s_parent); | 999 | sysfs_put(sd->s_parent); |
| 901 | sd->s_ns = new_ns; | 1000 | sd->s_ns = new_ns; |
| 902 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | 1001 | sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); |
| 903 | sd->s_parent = new_parent_sd; | 1002 | sd->s_parent = new_parent_sd; |
| 904 | sysfs_link_sibling(sd); | 1003 | sysfs_link_sibling(sd); |
| 905 | 1004 | ||
| @@ -909,30 +1008,25 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
| 909 | return error; | 1008 | return error; |
| 910 | } | 1009 | } |
| 911 | 1010 | ||
| 912 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | 1011 | int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, |
| 1012 | const void *new_ns) | ||
| 913 | { | 1013 | { |
| 914 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; | 1014 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; |
| 915 | const void *new_ns = NULL; | ||
| 916 | |||
| 917 | if (sysfs_ns_type(parent_sd)) | ||
| 918 | new_ns = kobj->ktype->namespace(kobj); | ||
| 919 | 1015 | ||
| 920 | return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name); | 1016 | return sysfs_rename(kobj->sd, parent_sd, new_name, new_ns); |
| 921 | } | 1017 | } |
| 922 | 1018 | ||
| 923 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 1019 | int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, |
| 1020 | const void *new_ns) | ||
| 924 | { | 1021 | { |
| 925 | struct sysfs_dirent *sd = kobj->sd; | 1022 | struct sysfs_dirent *sd = kobj->sd; |
| 926 | struct sysfs_dirent *new_parent_sd; | 1023 | struct sysfs_dirent *new_parent_sd; |
| 927 | const void *new_ns = NULL; | ||
| 928 | 1024 | ||
| 929 | BUG_ON(!sd->s_parent); | 1025 | BUG_ON(!sd->s_parent); |
| 930 | if (sysfs_ns_type(sd->s_parent)) | ||
| 931 | new_ns = kobj->ktype->namespace(kobj); | ||
| 932 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? | 1026 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
| 933 | new_parent_kobj->sd : &sysfs_root; | 1027 | new_parent_kobj->sd : &sysfs_root; |
| 934 | 1028 | ||
| 935 | return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name); | 1029 | return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); |
| 936 | } | 1030 | } |
| 937 | 1031 | ||
| 938 | /* Relationship between s_mode and the DT_xxx types */ | 1032 | /* Relationship between s_mode and the DT_xxx types */ |
