diff options
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r-- | kernel/livepatch/core.c | 56 |
1 files changed, 17 insertions, 39 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 14f33ab6c583..42385f23252a 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
@@ -426,6 +426,9 @@ static void klp_free_object_dynamic(struct klp_object *obj) | |||
426 | kfree(obj); | 426 | kfree(obj); |
427 | } | 427 | } |
428 | 428 | ||
429 | static struct kobj_type klp_ktype_object; | ||
430 | static struct kobj_type klp_ktype_func; | ||
431 | |||
429 | static struct klp_object *klp_alloc_object_dynamic(const char *name) | 432 | static struct klp_object *klp_alloc_object_dynamic(const char *name) |
430 | { | 433 | { |
431 | struct klp_object *obj; | 434 | struct klp_object *obj; |
@@ -443,6 +446,7 @@ static struct klp_object *klp_alloc_object_dynamic(const char *name) | |||
443 | } | 446 | } |
444 | 447 | ||
445 | INIT_LIST_HEAD(&obj->func_list); | 448 | INIT_LIST_HEAD(&obj->func_list); |
449 | kobject_init(&obj->kobj, &klp_ktype_object); | ||
446 | obj->dynamic = true; | 450 | obj->dynamic = true; |
447 | 451 | ||
448 | return obj; | 452 | return obj; |
@@ -471,6 +475,7 @@ static struct klp_func *klp_alloc_func_nop(struct klp_func *old_func, | |||
471 | } | 475 | } |
472 | } | 476 | } |
473 | 477 | ||
478 | kobject_init(&func->kobj, &klp_ktype_func); | ||
474 | /* | 479 | /* |
475 | * func->new_func is same as func->old_func. These addresses are | 480 | * func->new_func is same as func->old_func. These addresses are |
476 | * set when the object is loaded, see klp_init_object_loaded(). | 481 | * set when the object is loaded, see klp_init_object_loaded(). |
@@ -588,13 +593,7 @@ static void __klp_free_funcs(struct klp_object *obj, bool nops_only) | |||
588 | continue; | 593 | continue; |
589 | 594 | ||
590 | list_del(&func->node); | 595 | list_del(&func->node); |
591 | 596 | kobject_put(&func->kobj); | |
592 | /* Might be called from klp_init_patch() error path. */ | ||
593 | if (func->kobj_added) { | ||
594 | kobject_put(&func->kobj); | ||
595 | } else if (func->nop) { | ||
596 | klp_free_func_nop(func); | ||
597 | } | ||
598 | } | 597 | } |
599 | } | 598 | } |
600 | 599 | ||
@@ -624,13 +623,7 @@ static void __klp_free_objects(struct klp_patch *patch, bool nops_only) | |||
624 | continue; | 623 | continue; |
625 | 624 | ||
626 | list_del(&obj->node); | 625 | list_del(&obj->node); |
627 | 626 | kobject_put(&obj->kobj); | |
628 | /* Might be called from klp_init_patch() error path. */ | ||
629 | if (obj->kobj_added) { | ||
630 | kobject_put(&obj->kobj); | ||
631 | } else if (obj->dynamic) { | ||
632 | klp_free_object_dynamic(obj); | ||
633 | } | ||
634 | } | 627 | } |
635 | } | 628 | } |
636 | 629 | ||
@@ -675,10 +668,8 @@ static void klp_free_patch_finish(struct klp_patch *patch) | |||
675 | * this is called when the patch gets disabled and it | 668 | * this is called when the patch gets disabled and it |
676 | * cannot get enabled again. | 669 | * cannot get enabled again. |
677 | */ | 670 | */ |
678 | if (patch->kobj_added) { | 671 | kobject_put(&patch->kobj); |
679 | kobject_put(&patch->kobj); | 672 | wait_for_completion(&patch->finish); |
680 | wait_for_completion(&patch->finish); | ||
681 | } | ||
682 | 673 | ||
683 | /* Put the module after the last access to struct klp_patch. */ | 674 | /* Put the module after the last access to struct klp_patch. */ |
684 | if (!patch->forced) | 675 | if (!patch->forced) |
@@ -700,8 +691,6 @@ static void klp_free_patch_work_fn(struct work_struct *work) | |||
700 | 691 | ||
701 | static int klp_init_func(struct klp_object *obj, struct klp_func *func) | 692 | static int klp_init_func(struct klp_object *obj, struct klp_func *func) |
702 | { | 693 | { |
703 | int ret; | ||
704 | |||
705 | if (!func->old_name) | 694 | if (!func->old_name) |
706 | return -EINVAL; | 695 | return -EINVAL; |
707 | 696 | ||
@@ -724,13 +713,9 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) | |||
724 | * object. If the user selects 0 for old_sympos, then 1 will be used | 713 | * object. If the user selects 0 for old_sympos, then 1 will be used |
725 | * since a unique symbol will be the first occurrence. | 714 | * since a unique symbol will be the first occurrence. |
726 | */ | 715 | */ |
727 | ret = kobject_init_and_add(&func->kobj, &klp_ktype_func, | 716 | return kobject_add(&func->kobj, &obj->kobj, "%s,%lu", |
728 | &obj->kobj, "%s,%lu", func->old_name, | 717 | func->old_name, |
729 | func->old_sympos ? func->old_sympos : 1); | 718 | func->old_sympos ? func->old_sympos : 1); |
730 | if (!ret) | ||
731 | func->kobj_added = true; | ||
732 | |||
733 | return ret; | ||
734 | } | 719 | } |
735 | 720 | ||
736 | /* Arches may override this to finish any remaining arch-specific tasks */ | 721 | /* Arches may override this to finish any remaining arch-specific tasks */ |
@@ -801,11 +786,9 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj) | |||
801 | klp_find_object_module(obj); | 786 | klp_find_object_module(obj); |
802 | 787 | ||
803 | name = klp_is_module(obj) ? obj->name : "vmlinux"; | 788 | name = klp_is_module(obj) ? obj->name : "vmlinux"; |
804 | ret = kobject_init_and_add(&obj->kobj, &klp_ktype_object, | 789 | ret = kobject_add(&obj->kobj, &patch->kobj, "%s", name); |
805 | &patch->kobj, "%s", name); | ||
806 | if (ret) | 790 | if (ret) |
807 | return ret; | 791 | return ret; |
808 | obj->kobj_added = true; | ||
809 | 792 | ||
810 | klp_for_each_func(obj, func) { | 793 | klp_for_each_func(obj, func) { |
811 | ret = klp_init_func(obj, func); | 794 | ret = klp_init_func(obj, func); |
@@ -829,7 +812,7 @@ static int klp_init_patch_early(struct klp_patch *patch) | |||
829 | 812 | ||
830 | INIT_LIST_HEAD(&patch->list); | 813 | INIT_LIST_HEAD(&patch->list); |
831 | INIT_LIST_HEAD(&patch->obj_list); | 814 | INIT_LIST_HEAD(&patch->obj_list); |
832 | patch->kobj_added = false; | 815 | kobject_init(&patch->kobj, &klp_ktype_patch); |
833 | patch->enabled = false; | 816 | patch->enabled = false; |
834 | patch->forced = false; | 817 | patch->forced = false; |
835 | INIT_WORK(&patch->free_work, klp_free_patch_work_fn); | 818 | INIT_WORK(&patch->free_work, klp_free_patch_work_fn); |
@@ -840,11 +823,11 @@ static int klp_init_patch_early(struct klp_patch *patch) | |||
840 | return -EINVAL; | 823 | return -EINVAL; |
841 | 824 | ||
842 | INIT_LIST_HEAD(&obj->func_list); | 825 | INIT_LIST_HEAD(&obj->func_list); |
843 | obj->kobj_added = false; | 826 | kobject_init(&obj->kobj, &klp_ktype_object); |
844 | list_add_tail(&obj->node, &patch->obj_list); | 827 | list_add_tail(&obj->node, &patch->obj_list); |
845 | 828 | ||
846 | klp_for_each_func_static(obj, func) { | 829 | klp_for_each_func_static(obj, func) { |
847 | func->kobj_added = false; | 830 | kobject_init(&func->kobj, &klp_ktype_func); |
848 | list_add_tail(&func->node, &obj->func_list); | 831 | list_add_tail(&func->node, &obj->func_list); |
849 | } | 832 | } |
850 | } | 833 | } |
@@ -860,11 +843,9 @@ static int klp_init_patch(struct klp_patch *patch) | |||
860 | struct klp_object *obj; | 843 | struct klp_object *obj; |
861 | int ret; | 844 | int ret; |
862 | 845 | ||
863 | ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch, | 846 | ret = kobject_add(&patch->kobj, klp_root_kobj, "%s", patch->mod->name); |
864 | klp_root_kobj, "%s", patch->mod->name); | ||
865 | if (ret) | 847 | if (ret) |
866 | return ret; | 848 | return ret; |
867 | patch->kobj_added = true; | ||
868 | 849 | ||
869 | if (patch->replace) { | 850 | if (patch->replace) { |
870 | ret = klp_add_nops(patch); | 851 | ret = klp_add_nops(patch); |
@@ -926,9 +907,6 @@ static int __klp_enable_patch(struct klp_patch *patch) | |||
926 | if (WARN_ON(patch->enabled)) | 907 | if (WARN_ON(patch->enabled)) |
927 | return -EINVAL; | 908 | return -EINVAL; |
928 | 909 | ||
929 | if (!patch->kobj_added) | ||
930 | return -EINVAL; | ||
931 | |||
932 | pr_notice("enabling patch '%s'\n", patch->mod->name); | 910 | pr_notice("enabling patch '%s'\n", patch->mod->name); |
933 | 911 | ||
934 | klp_init_transition(patch, KLP_PATCHED); | 912 | klp_init_transition(patch, KLP_PATCHED); |