Commit 77dbd72b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'livepatching-for-5.17' of...

Merge tag 'livepatching-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/livepatching/livepatching

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
parents d0a231f0 b2dfc3fe
.. SPDX-License-Identifier: GPL-2.0
=================
Livepatching APIs
=================
Livepatch Enablement
====================
.. kernel-doc:: kernel/livepatch/core.c
:export:
Shadow Variables
================
.. kernel-doc:: kernel/livepatch/shadow.c
:export:
System State Changes
====================
.. kernel-doc:: kernel/livepatch/state.c
:export:
Object Types
============
.. kernel-doc:: include/linux/livepatch.h
:identifiers: klp_patch klp_object klp_func klp_callbacks klp_state
...@@ -14,6 +14,7 @@ Kernel Livepatching ...@@ -14,6 +14,7 @@ Kernel Livepatching
shadow-vars shadow-vars
system-state system-state
reliable-stacktrace reliable-stacktrace
api
.. only:: subproject and html .. only:: subproject and html
......
...@@ -82,8 +82,8 @@ to do actions that can be done only once when a new variable is allocated. ...@@ -82,8 +82,8 @@ to do actions that can be done only once when a new variable is allocated.
- call destructor function if defined - call destructor function if defined
- free shadow variable - free shadow variable
* klp_shadow_free_all() - detach and free all <*, id> shadow variables * klp_shadow_free_all() - detach and free all <_, id> shadow variables
- find and remove any <*, id> references from global hashtable - find and remove any <_, id> references from global hashtable
- if found - if found
......
...@@ -52,12 +52,12 @@ struct klp_state: ...@@ -52,12 +52,12 @@ struct klp_state:
The state can be manipulated using two functions: The state can be manipulated using two functions:
- *klp_get_state(patch, id)* - klp_get_state()
- Get struct klp_state associated with the given livepatch - Get struct klp_state associated with the given livepatch
and state id. and state id.
- *klp_get_prev_state(id)* - klp_get_prev_state()
- Get struct klp_state associated with the given feature id and - Get struct klp_state associated with the given feature id and
already installed livepatches. already installed livepatches.
......
...@@ -243,6 +243,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, ...@@ -243,6 +243,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); ret = fn(data, namebuf, NULL, kallsyms_sym_address(i));
if (ret != 0) if (ret != 0)
return ret; return ret;
cond_resched();
} }
return 0; return 0;
} }
......
...@@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch, ...@@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch,
list_add_tail(&obj->node, &patch->obj_list); list_add_tail(&obj->node, &patch->obj_list);
} }
static int klp_init_patch_early(struct klp_patch *patch) static void klp_init_patch_early(struct klp_patch *patch)
{ {
struct klp_object *obj; struct klp_object *obj;
struct klp_func *func; struct klp_func *func;
if (!patch->objs)
return -EINVAL;
INIT_LIST_HEAD(&patch->list); INIT_LIST_HEAD(&patch->list);
INIT_LIST_HEAD(&patch->obj_list); INIT_LIST_HEAD(&patch->obj_list);
kobject_init(&patch->kobj, &klp_ktype_patch); kobject_init(&patch->kobj, &klp_ktype_patch);
...@@ -879,20 +876,12 @@ static int klp_init_patch_early(struct klp_patch *patch) ...@@ -879,20 +876,12 @@ static int klp_init_patch_early(struct klp_patch *patch)
init_completion(&patch->finish); init_completion(&patch->finish);
klp_for_each_object_static(patch, obj) { klp_for_each_object_static(patch, obj) {
if (!obj->funcs)
return -EINVAL;
klp_init_object_early(patch, obj); klp_init_object_early(patch, obj);
klp_for_each_func_static(obj, func) { klp_for_each_func_static(obj, func) {
klp_init_func_early(obj, func); klp_init_func_early(obj, func);
} }
} }
if (!try_module_get(patch->mod))
return -ENODEV;
return 0;
} }
static int klp_init_patch(struct klp_patch *patch) static int klp_init_patch(struct klp_patch *patch)
...@@ -1024,10 +1013,17 @@ static int __klp_enable_patch(struct klp_patch *patch) ...@@ -1024,10 +1013,17 @@ static int __klp_enable_patch(struct klp_patch *patch)
int klp_enable_patch(struct klp_patch *patch) int klp_enable_patch(struct klp_patch *patch)
{ {
int ret; int ret;
struct klp_object *obj;
if (!patch || !patch->mod) if (!patch || !patch->mod || !patch->objs)
return -EINVAL; return -EINVAL;
klp_for_each_object_static(patch, obj) {
if (!obj->funcs)
return -EINVAL;
}
if (!is_livepatch_module(patch->mod)) { if (!is_livepatch_module(patch->mod)) {
pr_err("module %s is not marked as a livepatch module\n", pr_err("module %s is not marked as a livepatch module\n",
patch->mod->name); patch->mod->name);
...@@ -1051,12 +1047,13 @@ int klp_enable_patch(struct klp_patch *patch) ...@@ -1051,12 +1047,13 @@ int klp_enable_patch(struct klp_patch *patch)
return -EINVAL; return -EINVAL;
} }
ret = klp_init_patch_early(patch); if (!try_module_get(patch->mod)) {
if (ret) {
mutex_unlock(&klp_mutex); mutex_unlock(&klp_mutex);
return ret; return -ENODEV;
} }
klp_init_patch_early(patch);
ret = klp_init_patch(patch); ret = klp_init_patch(patch);
if (ret) if (ret)
goto err; goto err;
......
...@@ -272,12 +272,12 @@ void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) ...@@ -272,12 +272,12 @@ void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)
EXPORT_SYMBOL_GPL(klp_shadow_free); EXPORT_SYMBOL_GPL(klp_shadow_free);
/** /**
* klp_shadow_free_all() - detach and free all <*, id> shadow variables * klp_shadow_free_all() - detach and free all <_, id> shadow variables
* @id: data identifier * @id: data identifier
* @dtor: custom callback that can be used to unregister the variable * @dtor: custom callback that can be used to unregister the variable
* and/or free data that the shadow variable points to (optional) * and/or free data that the shadow variable points to (optional)
* *
* This function releases the memory for all <*, id> shadow variable * This function releases the memory for all <_, id> shadow variable
* instances, callers should stop referencing them accordingly. * instances, callers should stop referencing them accordingly.
*/ */
void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) 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) ...@@ -288,7 +288,7 @@ void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)
spin_lock_irqsave(&klp_shadow_lock, flags); spin_lock_irqsave(&klp_shadow_lock, flags);
/* Delete all <*, id> from hash */ /* Delete all <_, id> from hash */
hash_for_each(klp_shadow_hash, i, shadow, node) { hash_for_each(klp_shadow_hash, i, shadow, node) {
if (klp_shadow_match(shadow, shadow->obj, id)) if (klp_shadow_match(shadow, shadow->obj, id))
klp_shadow_free_struct(shadow, dtor); klp_shadow_free_struct(shadow, dtor);
......
...@@ -4499,6 +4499,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, ...@@ -4499,6 +4499,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
mod, kallsyms_symbol_value(sym)); mod, kallsyms_symbol_value(sym));
if (ret != 0) if (ret != 0)
goto out; goto out;
cond_resched();
} }
} }
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment