[RFC PATCH 41/56] static_call: Add update_all_static_calls()

David Kaplan
2025-10-13T14:36:20Z

The update_all_static_calls() function re-scans all static call sites and
re-patches them. This is used during re-patching.

Signed-off-by: David Kaplan <david.kaplan@amd.com>
---
arch/x86/kernel/static_call.c | 3 ++-
include/linux/static_call.h | 2 ++
kernel/static_call_inline.c | 22 ++++++++++++++++++++++
3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c
index 378c388d1b31..2d16d69b17d0 100644
--- a/arch/x86/kernel/static_call.c
+++ b/arch/x86/kernel/static_call.c
@@ -105,7 +105,8 @@ static void __ref __static_call_transform(void *insn, enum insn_type type,
if (memcmp(insn, code, size) == 0)
return;

- if (system_state == SYSTEM_BOOTING || modinit)
+ /* alternatives_patched is false if we are doing dynamic re-patching. */
+ if (system_state == SYSTEM_BOOTING || modinit || !alternatives_patched)
return text_poke_early(insn, code, size);

smp_text_poke_single(insn, code, size, emulate);
diff --git a/include/linux/static_call.h b/include/linux/static_call.h
index 78a77a4ae0ea..cc5f28a04539 100644
--- a/include/linux/static_call.h
+++ b/include/linux/static_call.h
@@ -181,6 +181,8 @@ struct static_call_tramp_key {
extern void __static_call_update(struct static_call_key *key, void *tramp, void *func);
extern int static_call_mod_init(struct module *mod);
extern int static_call_text_reserved(void *start, void *end);
+extern void update_all_static_calls(struct static_call_site *start,
+ struct static_call_site *stop, struct module *mod);

extern long __static_call_return0(void);

diff --git a/kernel/static_call_inline.c b/kernel/static_call_inline.c
index 269683d41aa9..504b69496711 100644
--- a/kernel/static_call_inline.c
+++ b/kernel/static_call_inline.c
@@ -9,6 +9,7 @@
#include <linux/cpu.h>
#include <linux/processor.h>
#include <asm/sections.h>
+#include <linux/kallsyms.h>

extern struct static_call_site __start_static_call_sites[],
__stop_static_call_sites[];
@@ -492,6 +493,27 @@ int static_call_text_reserved(void *start, void *end)
return __static_call_mod_text_reserved(start, end);
}

+void update_all_static_calls(struct static_call_site *start,
+ struct static_call_site *stop,
+ struct module *mod)
+{
+ struct static_call_site *site;
+ struct static_call_key *key;
+
+ for (site = start; site < stop; site++) {
+ void *site_addr = static_call_addr(site);
+
+ /* All init code is gone when this function is called. */
+ if (is_kernel_text((u64) site_addr) ||
+ (mod &&
+ within_module_mem_type((u64) site_addr, mod, MOD_TEXT))) {
+ key = static_call_key(site);
+ arch_static_call_transform(site_addr, NULL, key->func,
+ static_call_is_tail(site));
+ }
+ }
+}
+
int __init static_call_init(void)
{
int ret;
--
2.34.1