Livepatching changes for 5.17
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEESH4wyp42V4tXvYsjUqAMR0iAlPIFAmHhbrwACgkQUqAMR0iA lPJkAg//ZSvlc/dB7LdAiVmc2JBnDC49yxn7OguCW6t5T8RmVuaurPa/ZNDcZomw tbT7QSjndg0LHAGiWRrjGzQZ89D7/cbTzOxz821F0LLFDjiEMbUB+tCYznHud1cP 5+83QMwAkpME+RAj471SAHlhGAGJ3YKgFBbUP9sHSbtQqXzLGHBl4MluMh1wpVPq K1lyVG8TaOCXhWtpuO8MVrz7Q52qqi/85fHZKbQq9Tm5x+nDxVfGw24QcrkQB/Il 4B2T5UP9rzbHQYemc0hascLMJc1mxcFMtK8WKH48cPEL+kQarvsRn6fvVlCxdNUe ZgQfhixDQPQyC0/CaN7qM9EOpKbwoY8+Lc36kq06YMAJj/NPa4LE/1j2DyRvaein lJ2vy/E/TdaR71pApL02P5BeU4XAmhm10D/Qpj0pgRuERYVayNE/7wqzyrae7mqm 8zgpUDftGS6BXnwmRWmgFYI5bZWVfzwGjs+JjKIDXPhWHZInpOCkHGCehvabd+4U 02jwCAmKmpkhAxslm2579CZ0+VFK52z5mUwrWwsxhflUD1q3dNj7CAtPKYLqw5Xe iz2rrulDlwVll5pdbRf18A/+I2YSdz8pDwCpI6WKggompd6r+du3Y/GTGTBhoRcD L9Q/rENx1gpJgdZYL5zefKlrjMSQhdwp3CRk34DEronTTkty5mc= =fTdn -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
77dbd72b98
30
Documentation/livepatch/api.rst
Normal file
30
Documentation/livepatch/api.rst
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.. 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
|
|||||||
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.
|
|||||||
- 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:
|
|||||||
|
|
||||||
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 *,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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 @@ err:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 *,
|
|||||||
mod, kallsyms_symbol_value(sym));
|
mod, kallsyms_symbol_value(sym));
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
Loading…
Reference in New Issue
Block a user