Re: [PATCH v7 07/10] x86/vmscape: Use static_call() for predictor flush

From: Pawan Gupta

Date: Fri Mar 20 2026 - 02:25:03 EST


On Thu, Mar 19, 2026 at 10:44:09PM +0100, Peter Zijlstra wrote:
...
> > With _TRAMP, KVM complains:
> >
> > ERROR: modpost: "__SCK__vmscape_predictor_flush" [arch/x86/kvm/kvm.ko] undefined!
>
> Ah, tricky. Yeah, this would need to be solved differenlty. Perhaps wrap
> this in a helper and export that?

bool vmscape_mitigation_enabled(void)
{
return unlikely(static_call_query(vmscape_predictor_flush));
}
EXPORT_SYMBOL_FOR_KVM(vmscape_mitigation_enabled);

This is definitely simpler option, but adds an exported function and an
unnecessary call to it.

> Or use the below little thing and change it to
> EXPORT_STATIC_CALL_FOR_MODULES(foo, "kvm"); or whatnot.
>
> > Probably one option is to somehow make sure that the key can be set to
> > __ro_after_init? I don't see a use case for modifying the static_call() after
> > boot.
>
> So we have __ro_after_init for static_branch, but we'd not done
> it for static_call yet. It shouldn't be terribly difficult, just hasn't
> been done. Not sure this is the moment to do so.
>
>
> ---
> diff --git a/include/linux/static_call.h b/include/linux/static_call.h
> index 78a77a4ae0ea..b610afd1ed55 100644
> --- a/include/linux/static_call.h
> +++ b/include/linux/static_call.h
> @@ -216,6 +216,9 @@ extern long __static_call_return0(void);
> #define EXPORT_STATIC_CALL_GPL(name) \
> EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name)); \
> EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
> +#define EXPORT_STATIC_CALL_FOR_MODULES(name, mods) \
> + EXPORT_SYMBOL_FOR_MODULES(STATIC_CALL_KEY(name), mods); \
> + EXPORT_SYMBOL_FOR_MODULES(STATIC_CALL_TRAMP(name), mods)
>
> /* Leave the key unexported, so modules can't change static call targets: */
> #define EXPORT_STATIC_CALL_TRAMP(name) \
> @@ -276,6 +279,9 @@ extern long __static_call_return0(void);
> #define EXPORT_STATIC_CALL_GPL(name) \
> EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name)); \
> EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
> +#define EXPORT_STATIC_CALL_FOR_MODULES(name, mods) \
> + EXPORT_SYMBOL_FOR_MODULES(STATIC_CALL_KEY(name), mods); \
> + EXPORT_SYMBOL_FOR_MODULES(STATIC_CALL_TRAMP(name), mods)
>
> /* Leave the key unexported, so modules can't change static call targets: */
> #define EXPORT_STATIC_CALL_TRAMP(name) \
> @@ -346,6 +352,8 @@ static inline int static_call_text_reserved(void *start, void *end)
>
> #define EXPORT_STATIC_CALL(name) EXPORT_SYMBOL(STATIC_CALL_KEY(name))
> #define EXPORT_STATIC_CALL_GPL(name) EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name))
> +#define EXPORT_STATIC_CALL_FOR_MODULES(name, mods) \
> + EXPORT_SYMBOL_FOR_MODULES(STATIC_CALL_KEY(name), mods)
>
> #endif /* CONFIG_HAVE_STATIC_CALL */

This plus extending it to support EXPORT_STATIC_CALL_FOR_KVM() is probably
a better solution. Please let me know which one you prefer.

diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index a568d8e6f4e8..89c4964c8560 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -13,6 +13,9 @@
EXPORT_SYMBOL_FOR_MODULES(symbol, __stringify(KVM_SUB_MODULES))
#define EXPORT_SYMBOL_FOR_KVM(symbol) \
EXPORT_SYMBOL_FOR_MODULES(symbol, "kvm," __stringify(KVM_SUB_MODULES))
+#define EXPORT_STATIC_CALL_FOR_KVM(symbol) \
+ EXPORT_STATIC_CALL_FOR_MODULES(symbol ,"kvm," __stringify(KVM_SUB_MODULES))
+
#else
#define EXPORT_SYMBOL_FOR_KVM_INTERNAL(symbol)
/*
@@ -23,6 +26,7 @@
#ifndef EXPORT_SYMBOL_FOR_KVM
#if IS_MODULE(CONFIG_KVM)
#define EXPORT_SYMBOL_FOR_KVM(symbol) EXPORT_SYMBOL_FOR_MODULES(symbol, "kvm")
+#define EXPORT_STATIC_CALL_FOR_KVM(symbol) EXPORT_STATIC_CALL_FOR_MODULES(symbol ,"kvm")
#else
#define EXPORT_SYMBOL_FOR_KVM(symbol)
#endif /* IS_MODULE(CONFIG_KVM) */
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 5f102af4921f..0abdb54f7510 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -145,7 +145,7 @@ EXPORT_SYMBOL_GPL(cpu_buf_idle_clear);
DEFINE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);

DEFINE_STATIC_CALL_NULL(vmscape_predictor_flush, write_ibpb);
-EXPORT_STATIC_CALL_GPL(vmscape_predictor_flush);
+EXPORT_STATIC_CALL_FOR_KVM(vmscape_predictor_flush);

#undef pr_fmt
#define pr_fmt(fmt) "mitigations: " fmt