Pull livepatching updates from Petr Mladek: - Correctly handle kobjects when a livepatch init fails - Avoid CPU hogging when searching for many livepatched symbols - Add livepatch API page into documentation * tag 'livepatching-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching: livepatch: Avoid CPU hogging with cond_resched livepatch: Fix missing unlock on error in klp_enable_patch() livepatch: Fix kobject refcount bug on klp_init_patch_early failure path Documentation: livepatch: Add livepatch API page
Unified · Split
| @@ -0,0 +1,30 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | ================= | ||
| 4 | Livepatching APIs | ||
| 5 | ================= | ||
| 6 | |||
| 7 | Livepatch Enablement | ||
| 8 | ==================== | ||
| 9 | |||
| 10 | .. kernel-doc:: kernel/livepatch/core.c | ||
| 11 | :export: | ||
| 12 | |||
| 13 | |||
| 14 | Shadow Variables | ||
| 15 | ================ | ||
| 16 | |||
| 17 | .. kernel-doc:: kernel/livepatch/shadow.c | ||
| 18 | :export: | ||
| 19 | |||
| 20 | System State Changes | ||
| 21 | ==================== | ||
| 22 | |||
| 23 | .. kernel-doc:: kernel/livepatch/state.c | ||
| 24 | :export: | ||
| 25 | |||
| 26 | Object Types | ||
| 27 | ============ | ||
| 28 | |||
| 29 | .. kernel-doc:: include/linux/livepatch.h | ||
| 30 | :identifiers: klp_patch klp_object klp_func klp_callbacks klp_state | ||
| @@ -14,6 +14,7 @@ Kernel Livepatching · 13 unmodified lines | |||
| 14 | shadow-vars | 14 | shadow-vars |
| 15 | system-state | 15 | system-state |
| 16 | reliable-stacktrace | 16 | reliable-stacktrace |
| 17 | api | ||
| 17 | 18 | ||
| 18 | .. only:: subproject and html | 19 | .. only:: subproject and html |
| 19 | 20 | ||
| @@ -82,8 +82,8 @@ to do actions that can be done only once when a new variable is allocated. · 81 unmodified lines | |||
| 82 | - call destructor function if defined | 82 | - call destructor function if defined |
| 83 | - free shadow variable | 83 | - free shadow variable |
| 84 | 84 | ||
| 85 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables | 85 | * klp_shadow_free_all() - detach and free all <_, id> shadow variables |
| 86 | - find and remove any <*, id> references from global hashtable | 86 | - find and remove any <_, id> references from global hashtable |
| 87 | 87 | ||
| 88 | - if found | 88 | - if found |
| 89 | 89 | ||
| @@ -52,12 +52,12 @@ struct klp_state: · 51 unmodified lines | |||
| 52 | 52 | ||
| 53 | The state can be manipulated using two functions: | 53 | The state can be manipulated using two functions: |
| 54 | 54 | ||
| 55 | - *klp_get_state(patch, id)* | 55 | - klp_get_state() |
| 56 | 56 | ||
| 57 | - Get struct klp_state associated with the given livepatch | 57 | - Get struct klp_state associated with the given livepatch |
| 58 | and state id. | 58 | and state id. |
| 59 | 59 | ||
| 60 | - *klp_get_prev_state(id)* | 60 | - klp_get_prev_state() |
| 61 | 61 | ||
| 62 | - Get struct klp_state associated with the given feature id and | 62 | - Get struct klp_state associated with the given feature id and |
| 63 | already installed livepatches. | 63 | already installed livepatches. |
| @@ -243,6 +243,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, · 242 unmodified lines | |||
| 243 | ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); | 243 | ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); |
| 244 | if (ret != 0) | 244 | if (ret != 0) |
| 245 | return ret; | 245 | return ret; |
| 246 | cond_resched(); | ||
| 246 | } | 247 | } |
| 247 | return 0; | 248 | return 0; |
| 248 | } | 249 | } |
| @@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch, · 861 unmodified lines | |||
| 862 | list_add_tail(&obj->node, &patch->obj_list); | 862 | list_add_tail(&obj->node, &patch->obj_list); |
| 863 | } | 863 | } |
| 864 | 864 | ||
| 865 | static int klp_init_patch_early(struct klp_patch *patch) | 865 | static void klp_init_patch_early(struct klp_patch *patch) |
| 866 | { | 866 | { |
| 867 | struct klp_object *obj; | 867 | struct klp_object *obj; |
| 868 | struct klp_func *func; | 868 | struct klp_func *func; |
| 869 | 869 | ||
| 870 | if (!patch->objs) | ||
| 871 | return -EINVAL; | ||
| 872 | |||
| 873 | INIT_LIST_HEAD(&patch->list); | 870 | INIT_LIST_HEAD(&patch->list); |
| 874 | INIT_LIST_HEAD(&patch->obj_list); | 871 | INIT_LIST_HEAD(&patch->obj_list); |
| 875 | kobject_init(&patch->kobj, &klp_ktype_patch); | 872 | kobject_init(&patch->kobj, &klp_ktype_patch); |
| @@ -879,20 +876,12 @@ static int klp_init_patch_early(struct klp_patch *patch) · 3 unmodified lines | |||
| 879 | init_completion(&patch->finish); | 876 | init_completion(&patch->finish); |
| 880 | 877 | ||
| 881 | klp_for_each_object_static(patch, obj) { | 878 | klp_for_each_object_static(patch, obj) { |
| 882 | if (!obj->funcs) | ||
| 883 | return -EINVAL; | ||
| 884 | |||
| 885 | klp_init_object_early(patch, obj); | 879 | klp_init_object_early(patch, obj); |
| 886 | 880 | ||
| 887 | klp_for_each_func_static(obj, func) { | 881 | klp_for_each_func_static(obj, func) { |
| 888 | klp_init_func_early(obj, func); | 882 | klp_init_func_early(obj, func); |
| 889 | } | 883 | } |
| 890 | } | 884 | } |
| 891 | |||
| 892 | if (!try_module_get(patch->mod)) | ||
| 893 | return -ENODEV; | ||
| 894 | |||
| 895 | return 0; | ||
| 896 | } | 885 | } |
| 897 | 886 | ||
| 898 | static int klp_init_patch(struct klp_patch *patch) | 887 | static int klp_init_patch(struct klp_patch *patch) |
| @@ -1024,10 +1013,17 @@ err: · 125 unmodified lines | |||
| 1024 | int klp_enable_patch(struct klp_patch *patch) | 1013 | int klp_enable_patch(struct klp_patch *patch) |
| 1025 | { | 1014 | { |
| 1026 | int ret; | 1015 | int ret; |
| 1016 | struct klp_object *obj; | ||
| 1027 | 1017 | ||
| 1028 | if (!patch || !patch->mod) | 1018 | if (!patch || !patch->mod || !patch->objs) |
| 1029 | return -EINVAL; | 1019 | return -EINVAL; |
| 1030 | 1020 | ||
| 1021 | klp_for_each_object_static(patch, obj) { | ||
| 1022 | if (!obj->funcs) | ||
| 1023 | return -EINVAL; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | |||
| 1031 | if (!is_livepatch_module(patch->mod)) { | 1027 | if (!is_livepatch_module(patch->mod)) { |
| 1032 | pr_err("module %s is not marked as a livepatch module\n", | 1028 | pr_err("module %s is not marked as a livepatch module\n", |
| 1033 | patch->mod->name); | 1029 | patch->mod->name); |
| @@ -1051,12 +1047,13 @@ int klp_enable_patch(struct klp_patch *patch) · 17 unmodified lines | |||
| 1051 | return -EINVAL; | 1047 | return -EINVAL; |
| 1052 | } | 1048 | } |
| 1053 | 1049 | ||
| 1054 | ret = klp_init_patch_early(patch); | 1050 | if (!try_module_get(patch->mod)) { |
| 1055 | if (ret) { | ||
| 1056 | mutex_unlock(&klp_mutex); | 1051 | mutex_unlock(&klp_mutex); |
| 1057 | return ret; | 1052 | return -ENODEV; |
| 1058 | } | 1053 | } |
| 1059 | 1054 | ||
| 1055 | klp_init_patch_early(patch); | ||
| 1056 | |||
| 1060 | ret = klp_init_patch(patch); | 1057 | ret = klp_init_patch(patch); |
| 1061 | if (ret) | 1058 | if (ret) |
| 1062 | goto err; | 1059 | goto err; |
| @@ -272,12 +272,12 @@ void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) · 271 unmodified lines | |||
| 272 | EXPORT_SYMBOL_GPL(klp_shadow_free); | 272 | EXPORT_SYMBOL_GPL(klp_shadow_free); |
| 273 | 273 | ||
| 274 | /** | 274 | /** |
| 275 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables | 275 | * klp_shadow_free_all() - detach and free all <_, id> shadow variables |
| 276 | * @id: data identifier | 276 | * @id: data identifier |
| 277 | * @dtor: custom callback that can be used to unregister the variable | 277 | * @dtor: custom callback that can be used to unregister the variable |
| 278 | * and/or free data that the shadow variable points to (optional) | 278 | * and/or free data that the shadow variable points to (optional) |
| 279 | * | 279 | * |
| 280 | * This function releases the memory for all <*, id> shadow variable | 280 | * This function releases the memory for all <_, id> shadow variable |
| 281 | * instances, callers should stop referencing them accordingly. | 281 | * instances, callers should stop referencing them accordingly. |
| 282 | */ | 282 | */ |
| 283 | void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) | 283 | void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) |
| @@ -288,7 +288,7 @@ void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) · 4 unmodified lines | |||
| 288 | 288 | ||
| 289 | spin_lock_irqsave(&klp_shadow_lock, flags); | 289 | spin_lock_irqsave(&klp_shadow_lock, flags); |
| 290 | 290 | ||
| 291 | /* Delete all <*, id> from hash */ | 291 | /* Delete all <_, id> from hash */ |
| 292 | hash_for_each(klp_shadow_hash, i, shadow, node) { | 292 | hash_for_each(klp_shadow_hash, i, shadow, node) { |
| 293 | if (klp_shadow_match(shadow, shadow->obj, id)) | 293 | if (klp_shadow_match(shadow, shadow->obj, id)) |
| 294 | klp_shadow_free_struct(shadow, dtor); | 294 | klp_shadow_free_struct(shadow, dtor); |
| @@ -4499,6 +4499,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, · 4498 unmodified lines | |||
| 4499 | mod, kallsyms_symbol_value(sym)); | 4499 | mod, kallsyms_symbol_value(sym)); |
| 4500 | if (ret != 0) | 4500 | if (ret != 0) |
| 4501 | goto out; | 4501 | goto out; |
| 4502 | |||
| 4503 | cond_resched(); | ||
| 4502 | } | 4504 | } |
| 4503 | } | 4505 | } |
| 4504 | out: | 4506 | out: |