Skip to content

Commit 7825451

Browse files
author
Peter Zijlstra
committed
static_call: Add call depth tracking support
When indirect calls are switched to direct calls then it has to be ensured that the call target is not the function, but the call thunk when call depth tracking is enabled. But static calls are available before call thunks have been set up. Ensure a second run through the static call patching code after call thunks have been created. When call thunks are not enabled this has no side effects. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent f5c1bb2 commit 7825451

5 files changed

Lines changed: 44 additions & 5 deletions

File tree

arch/x86/include/asm/alternative.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,16 @@ struct callthunk_sites {
9191
extern void callthunks_patch_builtin_calls(void);
9292
extern void callthunks_patch_module_calls(struct callthunk_sites *sites,
9393
struct module *mod);
94+
extern void *callthunks_translate_call_dest(void *dest);
9495
#else
9596
static __always_inline void callthunks_patch_builtin_calls(void) {}
9697
static __always_inline void
9798
callthunks_patch_module_calls(struct callthunk_sites *sites,
9899
struct module *mod) {}
100+
static __always_inline void *callthunks_translate_call_dest(void *dest)
101+
{
102+
return dest;
103+
}
99104
#endif
100105

101106
#ifdef CONFIG_SMP

arch/x86/kernel/callthunks.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/kallsyms.h>
77
#include <linux/memory.h>
88
#include <linux/moduleloader.h>
9+
#include <linux/static_call.h>
910

1011
#include <asm/alternative.h>
1112
#include <asm/asm-offsets.h>
@@ -271,10 +272,27 @@ void __init callthunks_patch_builtin_calls(void)
271272
pr_info("Setting up call depth tracking\n");
272273
mutex_lock(&text_mutex);
273274
callthunks_setup(&cs, &builtin_coretext);
275+
static_call_force_reinit();
274276
thunks_initialized = true;
275277
mutex_unlock(&text_mutex);
276278
}
277279

280+
void *callthunks_translate_call_dest(void *dest)
281+
{
282+
void *target;
283+
284+
lockdep_assert_held(&text_mutex);
285+
286+
if (!thunks_initialized || skip_addr(dest))
287+
return dest;
288+
289+
if (!is_coretext(NULL, dest))
290+
return dest;
291+
292+
target = patch_dest(dest, false);
293+
return target ? : dest;
294+
}
295+
278296
#ifdef CONFIG_MODULES
279297
void noinline callthunks_patch_module_calls(struct callthunk_sites *cs,
280298
struct module *mod)

arch/x86/kernel/static_call.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ static void __ref __static_call_transform(void *insn, enum insn_type type,
3434

3535
switch (type) {
3636
case CALL:
37+
func = callthunks_translate_call_dest(func);
3738
code = text_gen_insn(CALL_INSN_OPCODE, insn, func);
3839
if (func == &__static_call_return0) {
3940
emulate = code;

include/linux/static_call.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ extern void arch_static_call_transform(void *site, void *tramp, void *func, bool
162162

163163
extern int __init static_call_init(void);
164164

165+
extern void static_call_force_reinit(void);
166+
165167
struct static_call_mod {
166168
struct static_call_mod *next;
167169
struct module *mod; /* for vmlinux, mod == NULL */

kernel/static_call_inline.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,18 @@ extern struct static_call_site __start_static_call_sites[],
1515
extern struct static_call_tramp_key __start_static_call_tramp_key[],
1616
__stop_static_call_tramp_key[];
1717

18-
static bool static_call_initialized;
18+
static int static_call_initialized;
19+
20+
/*
21+
* Must be called before early_initcall() to be effective.
22+
*/
23+
void static_call_force_reinit(void)
24+
{
25+
if (WARN_ON_ONCE(!static_call_initialized))
26+
return;
27+
28+
static_call_initialized++;
29+
}
1930

2031
/* mutex to protect key modules/sites */
2132
static DEFINE_MUTEX(static_call_mutex);
@@ -475,7 +486,8 @@ int __init static_call_init(void)
475486
{
476487
int ret;
477488

478-
if (static_call_initialized)
489+
/* See static_call_force_reinit(). */
490+
if (static_call_initialized == 1)
479491
return 0;
480492

481493
cpus_read_lock();
@@ -490,11 +502,12 @@ int __init static_call_init(void)
490502
BUG();
491503
}
492504

493-
static_call_initialized = true;
494-
495505
#ifdef CONFIG_MODULES
496-
register_module_notifier(&static_call_module_nb);
506+
if (!static_call_initialized)
507+
register_module_notifier(&static_call_module_nb);
497508
#endif
509+
510+
static_call_initialized = 1;
498511
return 0;
499512
}
500513
early_initcall(static_call_init);

0 commit comments

Comments
 (0)