diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig.debug | 2 | ||||
-rw-r--r-- | lib/kobject.c | 95 | ||||
-rw-r--r-- | lib/percpu-refcount.c | 3 | ||||
-rw-r--r-- | lib/scatterlist.c | 3 |
4 files changed, 96 insertions, 7 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 29329374ff0d..ebef88f61b7d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -992,7 +992,7 @@ config DEBUG_KOBJECT | |||
992 | 992 | ||
993 | config DEBUG_KOBJECT_RELEASE | 993 | config DEBUG_KOBJECT_RELEASE |
994 | bool "kobject release debugging" | 994 | bool "kobject release debugging" |
995 | depends on DEBUG_KERNEL | 995 | depends on DEBUG_OBJECTS_TIMERS |
996 | help | 996 | help |
997 | kobjects are reference counted objects. This means that their | 997 | kobjects are reference counted objects. This means that their |
998 | last reference count put is not predictable, and the kobject can | 998 | last reference count put is not predictable, and the kobject can |
diff --git a/lib/kobject.c b/lib/kobject.c index 669bf190d4fb..7a1c203083eb 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -13,11 +13,33 @@ | |||
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 | const void *ns; | ||
34 | |||
35 | if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) | ||
36 | return NULL; | ||
37 | |||
38 | ns = kobj->ktype->namespace(kobj); | ||
39 | WARN_ON(!ns); /* @kobj in a namespace is required to have !NULL tag */ | ||
40 | return ns; | ||
41 | } | ||
42 | |||
21 | /* | 43 | /* |
22 | * populate_dir - populate directory with attributes. | 44 | * populate_dir - populate directory with attributes. |
23 | * @kobj: object we're working on. | 45 | * @kobj: object we're working on. |
@@ -46,13 +68,21 @@ static int populate_dir(struct kobject *kobj) | |||
46 | 68 | ||
47 | static int create_dir(struct kobject *kobj) | 69 | static int create_dir(struct kobject *kobj) |
48 | { | 70 | { |
49 | int error = 0; | 71 | int error; |
50 | error = sysfs_create_dir(kobj); | 72 | |
73 | error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); | ||
51 | if (!error) { | 74 | if (!error) { |
52 | error = populate_dir(kobj); | 75 | error = populate_dir(kobj); |
53 | if (error) | 76 | if (error) |
54 | sysfs_remove_dir(kobj); | 77 | sysfs_remove_dir(kobj); |
55 | } | 78 | } |
79 | |||
80 | /* | ||
81 | * @kobj->sd may be deleted by an ancestor going away. Hold an | ||
82 | * extra reference so that it stays until @kobj is gone. | ||
83 | */ | ||
84 | sysfs_get(kobj->sd); | ||
85 | |||
56 | return error; | 86 | return error; |
57 | } | 87 | } |
58 | 88 | ||
@@ -428,7 +458,7 @@ int kobject_rename(struct kobject *kobj, const char *new_name) | |||
428 | goto out; | 458 | goto out; |
429 | } | 459 | } |
430 | 460 | ||
431 | error = sysfs_rename_dir(kobj, new_name); | 461 | error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj)); |
432 | if (error) | 462 | if (error) |
433 | goto out; | 463 | goto out; |
434 | 464 | ||
@@ -472,6 +502,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
472 | if (kobj->kset) | 502 | if (kobj->kset) |
473 | new_parent = kobject_get(&kobj->kset->kobj); | 503 | new_parent = kobject_get(&kobj->kset->kobj); |
474 | } | 504 | } |
505 | |||
475 | /* old object path */ | 506 | /* old object path */ |
476 | devpath = kobject_get_path(kobj, GFP_KERNEL); | 507 | devpath = kobject_get_path(kobj, GFP_KERNEL); |
477 | if (!devpath) { | 508 | if (!devpath) { |
@@ -486,7 +517,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) | |||
486 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); | 517 | sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); |
487 | envp[0] = devpath_string; | 518 | envp[0] = devpath_string; |
488 | envp[1] = NULL; | 519 | envp[1] = NULL; |
489 | error = sysfs_move_dir(kobj, new_parent); | 520 | error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj)); |
490 | if (error) | 521 | if (error) |
491 | goto out; | 522 | goto out; |
492 | old_parent = kobj->parent; | 523 | old_parent = kobj->parent; |
@@ -508,10 +539,15 @@ out: | |||
508 | */ | 539 | */ |
509 | void kobject_del(struct kobject *kobj) | 540 | void kobject_del(struct kobject *kobj) |
510 | { | 541 | { |
542 | struct sysfs_dirent *sd; | ||
543 | |||
511 | if (!kobj) | 544 | if (!kobj) |
512 | return; | 545 | return; |
513 | 546 | ||
547 | sd = kobj->sd; | ||
514 | sysfs_remove_dir(kobj); | 548 | sysfs_remove_dir(kobj); |
549 | sysfs_put(sd); | ||
550 | |||
515 | kobj->state_in_sysfs = 0; | 551 | kobj->state_in_sysfs = 0; |
516 | kobj_kset_leave(kobj); | 552 | kobj_kset_leave(kobj); |
517 | kobject_put(kobj->parent); | 553 | kobject_put(kobj->parent); |
@@ -592,7 +628,7 @@ static void kobject_release(struct kref *kref) | |||
592 | { | 628 | { |
593 | struct kobject *kobj = container_of(kref, struct kobject, kref); | 629 | struct kobject *kobj = container_of(kref, struct kobject, kref); |
594 | #ifdef CONFIG_DEBUG_KOBJECT_RELEASE | 630 | #ifdef CONFIG_DEBUG_KOBJECT_RELEASE |
595 | pr_debug("kobject: '%s' (%p): %s, parent %p (delayed)\n", | 631 | pr_info("kobject: '%s' (%p): %s, parent %p (delayed)\n", |
596 | kobject_name(kobj), kobj, __func__, kobj->parent); | 632 | kobject_name(kobj), kobj, __func__, kobj->parent); |
597 | INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup); | 633 | INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup); |
598 | schedule_delayed_work(&kobj->release, HZ); | 634 | schedule_delayed_work(&kobj->release, HZ); |
@@ -727,6 +763,55 @@ const struct sysfs_ops kobj_sysfs_ops = { | |||
727 | }; | 763 | }; |
728 | 764 | ||
729 | /** | 765 | /** |
766 | * kobj_completion_init - initialize a kobj_completion object. | ||
767 | * @kc: kobj_completion | ||
768 | * @ktype: type of kobject to initialize | ||
769 | * | ||
770 | * kobj_completion structures can be embedded within structures with different | ||
771 | * lifetime rules. During the release of the enclosing object, we can | ||
772 | * wait on the release of the kobject so that we don't free it while it's | ||
773 | * still busy. | ||
774 | */ | ||
775 | void kobj_completion_init(struct kobj_completion *kc, struct kobj_type *ktype) | ||
776 | { | ||
777 | init_completion(&kc->kc_unregister); | ||
778 | kobject_init(&kc->kc_kobj, ktype); | ||
779 | } | ||
780 | EXPORT_SYMBOL_GPL(kobj_completion_init); | ||
781 | |||
782 | /** | ||
783 | * kobj_completion_release - release a kobj_completion object | ||
784 | * @kobj: kobject embedded in kobj_completion | ||
785 | * | ||
786 | * Used with kobject_release to notify waiters that the kobject has been | ||
787 | * released. | ||
788 | */ | ||
789 | void kobj_completion_release(struct kobject *kobj) | ||
790 | { | ||
791 | struct kobj_completion *kc = kobj_to_kobj_completion(kobj); | ||
792 | complete(&kc->kc_unregister); | ||
793 | } | ||
794 | EXPORT_SYMBOL_GPL(kobj_completion_release); | ||
795 | |||
796 | /** | ||
797 | * kobj_completion_del_and_wait - release the kobject and wait for it | ||
798 | * @kc: kobj_completion object to release | ||
799 | * | ||
800 | * Delete the kobject from sysfs and drop the reference count. Then wait | ||
801 | * until any other outstanding references are also dropped. This routine | ||
802 | * is only necessary once other references may have been taken on the | ||
803 | * kobject. Typically this happens when the kobject has been published | ||
804 | * to sysfs via kobject_add. | ||
805 | */ | ||
806 | void kobj_completion_del_and_wait(struct kobj_completion *kc) | ||
807 | { | ||
808 | kobject_del(&kc->kc_kobj); | ||
809 | kobject_put(&kc->kc_kobj); | ||
810 | wait_for_completion(&kc->kc_unregister); | ||
811 | } | ||
812 | EXPORT_SYMBOL_GPL(kobj_completion_del_and_wait); | ||
813 | |||
814 | /** | ||
730 | * kset_register - initialize and add a kset. | 815 | * kset_register - initialize and add a kset. |
731 | * @k: kset. | 816 | * @k: kset. |
732 | */ | 817 | */ |
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 7deeb6297a48..1a53d497a8c5 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c | |||
@@ -53,6 +53,7 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release) | |||
53 | ref->release = release; | 53 | ref->release = release; |
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
56 | EXPORT_SYMBOL_GPL(percpu_ref_init); | ||
56 | 57 | ||
57 | /** | 58 | /** |
58 | * percpu_ref_cancel_init - cancel percpu_ref_init() | 59 | * percpu_ref_cancel_init - cancel percpu_ref_init() |
@@ -84,6 +85,7 @@ void percpu_ref_cancel_init(struct percpu_ref *ref) | |||
84 | free_percpu(ref->pcpu_count); | 85 | free_percpu(ref->pcpu_count); |
85 | } | 86 | } |
86 | } | 87 | } |
88 | EXPORT_SYMBOL_GPL(percpu_ref_cancel_init); | ||
87 | 89 | ||
88 | static void percpu_ref_kill_rcu(struct rcu_head *rcu) | 90 | static void percpu_ref_kill_rcu(struct rcu_head *rcu) |
89 | { | 91 | { |
@@ -156,3 +158,4 @@ void percpu_ref_kill_and_confirm(struct percpu_ref *ref, | |||
156 | 158 | ||
157 | call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu); | 159 | call_rcu_sched(&ref->rcu, percpu_ref_kill_rcu); |
158 | } | 160 | } |
161 | EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); | ||
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index a685c8a79578..d16fa295ae1d 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -577,7 +577,8 @@ void sg_miter_stop(struct sg_mapping_iter *miter) | |||
577 | miter->__offset += miter->consumed; | 577 | miter->__offset += miter->consumed; |
578 | miter->__remaining -= miter->consumed; | 578 | miter->__remaining -= miter->consumed; |
579 | 579 | ||
580 | if (miter->__flags & SG_MITER_TO_SG) | 580 | if ((miter->__flags & SG_MITER_TO_SG) && |
581 | !PageSlab(miter->page)) | ||
581 | flush_kernel_dcache_page(miter->page); | 582 | flush_kernel_dcache_page(miter->page); |
582 | 583 | ||
583 | if (miter->__flags & SG_MITER_ATOMIC) { | 584 | if (miter->__flags & SG_MITER_ATOMIC) { |