diff options
Diffstat (limited to 'lib/kobject.c')
| -rw-r--r-- | lib/kobject.c | 90 |
1 files changed, 86 insertions, 4 deletions
diff --git a/lib/kobject.c b/lib/kobject.c index 084f7b18d0c0..5b4b8886435e 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
| @@ -13,11 +13,30 @@ | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/kobject.h> | 15 | #include <linux/kobject.h> |
| 16 | #include <linux/kobj_completion.h> | ||
| 16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 17 | #include <linux/export.h> | 18 | #include <linux/export.h> |
| 18 | #include <linux/stat.h> | 19 | #include <linux/stat.h> |
| 19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 20 | 21 | ||
| 22 | /** | ||
| 23 | * kobject_namespace - return @kobj's namespace tag | ||
| 24 | * @kobj: kobject in question | ||
| 25 | * | ||
| 26 | * Returns namespace tag of @kobj if its parent has namespace ops enabled | ||
| 27 | * and thus @kobj should have a namespace tag associated with it. Returns | ||
| 28 | * %NULL otherwise. | ||
| 29 | */ | ||
| 30 | const void *kobject_namespace(struct kobject *kobj) | ||
| 31 | { | ||
| 32 | const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); | ||
| 33 | |||
| 34 | if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) | ||
| 35 | return NULL; | ||
| 36 | |||
| 37 | return kobj->ktype->namespace(kobj); | ||
| 38 | } | ||
| 39 | |||
| 21 | /* | 40 | /* |
| 22 | * populate_dir - populate directory with attributes. | 41 | * populate_dir - populate directory with attributes. |
| 23 | * @kobj: object we're working on. | 42 | * @kobj: object we're working on. |
| @@ -46,13 +65,21 @@ static int populate_dir(struct kobject *kobj) | |||
| 46 | 65 | ||
| 47 | static int create_dir(struct kobject *kobj) | 66 | static int create_dir(struct kobject *kobj) |
| 48 | { | 67 | { |
| 49 | int error = 0; | 68 | int error; |
| 50 | error = sysfs_create_dir(kobj); | 69 | |
| 70 | error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); | ||
| 51 | if (!error) { | 71 | if (!error) { |
| 52 | error = populate_dir(kobj); | 72 | error = populate_dir(kobj); |
| 53 | if (error) | 73 | if (error) |
| 54 | sysfs_remove_dir(kobj); | 74 | sysfs_remove_dir(kobj); |
| 55 | } | 75 | } |
| 76 | |||
| 77 | /* | ||
| 78 | * @kobj->sd may be deleted by an ancestor going away. Hold an | ||
| 79 | * extra reference so that it stays until @kobj is gone. | ||
| 80 | */ | ||
| 81 | sysfs_get(kobj->sd); | ||
| 82 | |||
| 56 | return error; | 83 | return error; |
| 57 | } | 84 | } |
| 58 | 85 | ||
| @@ -428,7 +455,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) | |||
| 428 | goto out; | 455 | goto out; |
| 429 | } | 456 | } |
| 430 | 457 | ||
| 431 | error = sysfs_rename_dir(kobj, new_name); | 458 | error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj)); |
| 432 | if (error) | 459 | if (error) |
| 433 | goto out; | 460 | goto out; |
| 434 | 461 | ||
| @@ -472,6 +499,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
| 472 | if (kobj->kset) | 499 | if (kobj->kset) |
| 473 | new_parent = kobject_get(&kobj->kset->kobj); | 500 | new_parent = kobject_get(&kobj->kset->kobj); |
| 474 | } | 501 | } |
| 502 | |||
| 475 | /* old object path */ | 503 | /* old object path */ |
| 476 | devpath = kobject_get_path(kobj, GFP_KERNEL); | 504 | devpath = kobject_get_path(kobj, GFP_KERNEL); |
| 477 | if (!devpath) { | 505 | if (!devpath) { |
| @@ -486,7 +514,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
| 486 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); | 514 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); |
| 487 | envp[0] = devpath_string; | 515 | envp[0] = devpath_string; |
| 488 | envp[1] = NULL; | 516 | envp[1] = NULL; |
| 489 | error = sysfs_move_dir(kobj, new_parent); | 517 | error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj)); |
| 490 | if (error) | 518 | if (error) |
| 491 | goto out; | 519 | goto out; |
| 492 | old_parent = kobj->parent; | 520 | old_parent = kobj->parent; |
| @@ -508,10 +536,15 @@ out: | |||
| 508 | */ | 536 | */ |
| 509 | void kobject_del(struct kobject *kobj) | 537 | void kobject_del(struct kobject *kobj) |
| 510 | { | 538 | { |
| 539 | struct sysfs_dirent *sd; | ||
| 540 | |||
| 511 | if (!kobj) | 541 | if (!kobj) |
| 512 | return; | 542 | return; |
| 513 | 543 | ||
| 544 | sd = kobj->sd; | ||
| 514 | sysfs_remove_dir(kobj); | 545 | sysfs_remove_dir(kobj); |
| 546 | sysfs_put(sd); | ||
| 547 | |||
| 515 | kobj->state_in_sysfs = 0; | 548 | kobj->state_in_sysfs = 0; |
| 516 | kobj_kset_leave(kobj); | 549 | kobj_kset_leave(kobj); |
| 517 | kobject_put(kobj->parent); | 550 | kobject_put(kobj->parent); |
| @@ -727,6 +760,55 @@ const struct sysfs_ops kobj_sysfs_ops = { | |||
| 727 | }; | 760 | }; |
| 728 | 761 | ||
| 729 | /** | 762 | /** |
| 763 | * kobj_completion_init - initialize a kobj_completion object. | ||
| 764 | * @kc: kobj_completion | ||
| 765 | * @ktype: type of kobject to initialize | ||
| 766 | * | ||
| 767 | * kobj_completion structures can be embedded within structures with different | ||
| 768 | * lifetime rules. During the release of the enclosing object, we can | ||
| 769 | * wait on the release of the kobject so that we don't free it while it's | ||
| 770 | * still busy. | ||
| 771 | */ | ||
| 772 | void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype) | ||
| 773 | { | ||
| 774 | init_completion(&kc->kc_unregister); | ||
| 775 | kobject_init(&kc->kc_kobj, ktype); | ||
| 776 | } | ||
| 777 | EXPORT_SYMBOL_GPL(kobj_completion_init); | ||
| 778 | |||
| 779 | /** | ||
| 780 | * kobj_completion_release - release a kobj_completion object | ||
| 781 | * @kobj: kobject embedded in kobj_completion | ||
| 782 | * | ||
| 783 | * Used with kobject_release to notify waiters that the kobject has been | ||
| 784 | * released. | ||
| 785 | */ | ||
| 786 | void kobj_completion_release(struct kobject *kobj) | ||
| 787 | { | ||
| 788 | struct kobj_completion *kc = kobj_to_kobj_completion(kobj); | ||
| 789 | complete(&kc->kc_unregister); | ||
| 790 | } | ||
| 791 | EXPORT_SYMBOL_GPL(kobj_completion_release); | ||
| 792 | |||
| 793 | /** | ||
| 794 | * kobj_completion_del_and_wait - release the kobject and wait for it | ||
| 795 | * @kc: kobj_completion object to release | ||
| 796 | * | ||
| 797 | * Delete the kobject from sysfs and drop the reference count. Then wait | ||
| 798 | * until any other outstanding references are also dropped. This routine | ||
| 799 | * is only necessary once other references may have been taken on the | ||
| 800 | * kobject. Typically this happens when the kobject has been published | ||
| 801 | * to sysfs via kobject_add. | ||
| 802 | */ | ||
| 803 | void kobj_completion_del_and_wait(struct kobj_completion *kc) | ||
| 804 | { | ||
| 805 | kobject_del(&kc->kc_kobj); | ||
| 806 | kobject_put(&kc->kc_kobj); | ||
| 807 | wait_for_completion(&kc->kc_unregister); | ||
| 808 | } | ||
| 809 | EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait); | ||
| 810 | |||
| 811 | /** | ||
| 730 | * kset_register - initialize and add a kset. | 812 | * kset_register - initialize and add a kset. |
| 731 | * @k: kset. | 813 | * @k: kset. |
| 732 | */ | 814 | */ |
