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 | 14 | shadow-vars |
| 15 | 15 | system-state |
| 16 | 16 | reliable-stacktrace |
| 17 | + api | |
| 17 | 18 | |
| 18 | 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 | 82 | - call destructor function if defined |
| 83 | 83 | - free shadow variable |
| 84 | 84 | |
| 85 | −* klp_shadow_free_all() - detach and free all <*, id> shadow variables | |
| 86 | − - find and remove any <*, id> references from global hashtable | |
| 85 | +* klp_shadow_free_all() - detach and free all <_, id> shadow variables | |
| 86 | + - find and remove any <_, id> references from global hashtable | |
| 87 | 87 | |
| 88 | 88 | - if found |
| 89 | 89 | |
| @@ -52,12 +52,12 @@ struct klp_state: · 51 unmodified lines | ||
| 52 | 52 | |
| 53 | 53 | The state can be manipulated using two functions: |
| 54 | 54 | |
| 55 | − - *klp_get_state(patch, id)* | |
| 55 | + - klp_get_state() | |
| 56 | 56 | |
| 57 | 57 | - Get struct klp_state associated with the given livepatch |
| 58 | 58 | and state id. |
| 59 | 59 | |
| 60 | − - *klp_get_prev_state(id)* | |
| 60 | + - klp_get_prev_state() | |
| 61 | 61 | |
| 62 | 62 | - Get struct klp_state associated with the given feature id and |
| 63 | 63 | already installed livepatches. |
| @@ -243,6 +243,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, · 242 unmodified lines | ||
| 243 | 243 | ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); |
| 244 | 244 | if (ret != 0) |
| 245 | 245 | return ret; |
| 246 | + cond_resched(); | |
| 246 | 247 | } |
| 247 | 248 | return 0; |
| 248 | 249 | } |
| @@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch, · 861 unmodified lines | ||
| 862 | 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 | 867 | struct klp_object *obj; |
| 868 | 868 | struct klp_func *func; |
| 869 | 869 | |
| 870 | − if (!patch->objs) | |
| 871 | − return -EINVAL; | |
| 872 | − | |
| 873 | 870 | INIT_LIST_HEAD(&patch->list); |
| 874 | 871 | INIT_LIST_HEAD(&patch->obj_list); |
| 875 | 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 | 876 | init_completion(&patch->finish); |
| 880 | 877 | |
| 881 | 878 | klp_for_each_object_static(patch, obj) { |
| 882 | − if (!obj->funcs) | |
| 883 | − return -EINVAL; | |
| 884 | − | |
| 885 | 879 | klp_init_object_early(patch, obj); |
| 886 | 880 | |
| 887 | 881 | klp_for_each_func_static(obj, func) { |
| 888 | 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 | 887 | static int klp_init_patch(struct klp_patch *patch) |
| @@ -1024,10 +1013,17 @@ err: · 125 unmodified lines | ||
| 1024 | 1013 | int klp_enable_patch(struct klp_patch *patch) |
| 1025 | 1014 | { |
| 1026 | 1015 | int ret; |
| 1016 | + struct klp_object *obj; | |
| 1027 | 1017 | |
| 1028 | − if (!patch || !patch->mod) | |
| 1018 | + if (!patch || !patch->mod || !patch->objs) | |
| 1029 | 1019 | return -EINVAL; |
| 1030 | 1020 | |
| 1021 | + klp_for_each_object_static(patch, obj) { | |
| 1022 | + if (!obj->funcs) | |
| 1023 | + return -EINVAL; | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + | |
| 1031 | 1027 | if (!is_livepatch_module(patch->mod)) { |
| 1032 | 1028 | pr_err("module %s is not marked as a livepatch module\n", |
| 1033 | 1029 | patch->mod->name); |
| @@ -1051,12 +1047,13 @@ int klp_enable_patch(struct klp_patch *patch) · 17 unmodified lines | ||
| 1051 | 1047 | return -EINVAL; |
| 1052 | 1048 | } |
| 1053 | 1049 | |
| 1054 | − ret = klp_init_patch_early(patch); | |
| 1055 | − if (ret) { | |
| 1050 | + if (!try_module_get(patch->mod)) { | |
| 1056 | 1051 | mutex_unlock(&klp_mutex); |
| 1057 | − return ret; | |
| 1052 | + return -ENODEV; | |
| 1058 | 1053 | } |
| 1059 | 1054 | |
| 1055 | + klp_init_patch_early(patch); | |
| 1056 | + | |
| 1060 | 1057 | ret = klp_init_patch(patch); |
| 1061 | 1058 | if (ret) |
| 1062 | 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 | 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 | 276 | * @id: data identifier |
| 277 | 277 | * @dtor: custom callback that can be used to unregister the variable |
| 278 | 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 | 281 | * instances, callers should stop referencing them accordingly. |
| 282 | 282 | */ |
| 283 | 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 | 289 | spin_lock_irqsave(&klp_shadow_lock, flags); |
| 290 | 290 | |
| 291 | − /* Delete all <*, id> from hash */ | |
| 291 | + /* Delete all <_, id> from hash */ | |
| 292 | 292 | hash_for_each(klp_shadow_hash, i, shadow, node) { |
| 293 | 293 | if (klp_shadow_match(shadow, shadow->obj, id)) |
| 294 | 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 | 4499 | mod, kallsyms_symbol_value(sym)); |
| 4500 | 4500 | if (ret != 0) |
| 4501 | 4501 | goto out; |
| 4502 | + | |
| 4503 | + cond_resched(); | |
| 4502 | 4504 | } |
| 4503 | 4505 | } |
| 4504 | 4506 | out: |