Skip to content

Commit 9183c3f

Browse files
jpoimboeIngo Molnar
authored andcommitted
static_call: Add inline static call infrastructure
Add infrastructure for an arch-specific CONFIG_HAVE_STATIC_CALL_INLINE option, which is a faster version of CONFIG_HAVE_STATIC_CALL. At runtime, the static call sites are patched directly, rather than using the out-of-line trampolines. Compared to out-of-line static calls, the performance benefits are more modest, but still measurable. Steven Rostedt did some tracepoint measurements: https://lkml.kernel.org/r/20181126155405.72b4f718@gandalf.local.home This code is heavily inspired by the jump label code (aka "static jumps"), as some of the concepts are very similar. For more details, see the comments in include/linux/static_call.h. [peterz: simplified interface; merged trampolines] Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lore.kernel.org/r/20200818135804.684334440@infradead.org
1 parent 115284d commit 9183c3f

File tree

8 files changed

+373
-1
lines changed

8 files changed

+373
-1
lines changed

arch/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,10 @@ config ARCH_HAS_VDSO_DATA
978978
config HAVE_STATIC_CALL
979979
bool
980980

981+
config HAVE_STATIC_CALL_INLINE
982+
bool
983+
depends on HAVE_STATIC_CALL
984+
981985
source "kernel/gcov/Kconfig"
982986

983987
source "scripts/gcc-plugins/Kconfig"

include/asm-generic/vmlinux.lds.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@
388388
KEEP(*(__jump_table)) \
389389
__stop___jump_table = .;
390390

391+
#define STATIC_CALL_DATA \
392+
. = ALIGN(8); \
393+
__start_static_call_sites = .; \
394+
KEEP(*(.static_call_sites)) \
395+
__stop_static_call_sites = .;
396+
391397
/*
392398
* Allow architectures to handle ro_after_init data on their
393399
* own by defining an empty RO_AFTER_INIT_DATA.
@@ -398,6 +404,7 @@
398404
__start_ro_after_init = .; \
399405
*(.data..ro_after_init) \
400406
JUMP_TABLE_DATA \
407+
STATIC_CALL_DATA \
401408
__end_ro_after_init = .;
402409
#endif
403410

include/linux/module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/error-injection.h>
2626
#include <linux/tracepoint-defs.h>
2727
#include <linux/srcu.h>
28+
#include <linux/static_call_types.h>
2829

2930
#include <linux/percpu.h>
3031
#include <asm/module.h>
@@ -498,6 +499,10 @@ struct module {
498499
unsigned long *kprobe_blacklist;
499500
unsigned int num_kprobe_blacklist;
500501
#endif
502+
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
503+
int num_static_call_sites;
504+
struct static_call_site *static_call_sites;
505+
#endif
501506

502507
#ifdef CONFIG_LIVEPATCH
503508
bool klp; /* Is this a livepatch module? */

include/linux/static_call.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,41 @@ extern void arch_static_call_transform(void *site, void *tramp, void *func);
9595
STATIC_CALL_TRAMP_ADDR(name), func); \
9696
})
9797

98-
#if defined(CONFIG_HAVE_STATIC_CALL)
98+
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
99+
100+
struct static_call_mod {
101+
struct static_call_mod *next;
102+
struct module *mod; /* for vmlinux, mod == NULL */
103+
struct static_call_site *sites;
104+
};
105+
106+
struct static_call_key {
107+
void *func;
108+
struct static_call_mod *mods;
109+
};
110+
111+
extern void __static_call_update(struct static_call_key *key, void *tramp, void *func);
112+
extern int static_call_mod_init(struct module *mod);
113+
114+
#define DEFINE_STATIC_CALL(name, _func) \
115+
DECLARE_STATIC_CALL(name, _func); \
116+
struct static_call_key STATIC_CALL_KEY(name) = { \
117+
.func = _func, \
118+
.mods = NULL, \
119+
}; \
120+
ARCH_DEFINE_STATIC_CALL_TRAMP(name, _func)
121+
122+
#define static_call(name) __static_call(name)
123+
124+
#define EXPORT_STATIC_CALL(name) \
125+
EXPORT_SYMBOL(STATIC_CALL_KEY(name)); \
126+
EXPORT_SYMBOL(STATIC_CALL_TRAMP(name))
127+
128+
#define EXPORT_STATIC_CALL_GPL(name) \
129+
EXPORT_SYMBOL_GPL(STATIC_CALL_KEY(name)); \
130+
EXPORT_SYMBOL_GPL(STATIC_CALL_TRAMP(name))
131+
132+
#elif defined(CONFIG_HAVE_STATIC_CALL)
99133

100134
struct static_call_key {
101135
void *func;

include/linux/static_call_types.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@
22
#ifndef _STATIC_CALL_TYPES_H
33
#define _STATIC_CALL_TYPES_H
44

5+
#include <linux/types.h>
56
#include <linux/stringify.h>
67

78
#define STATIC_CALL_KEY_PREFIX __SCK__
9+
#define STATIC_CALL_KEY_PREFIX_STR __stringify(STATIC_CALL_KEY_PREFIX)
10+
#define STATIC_CALL_KEY_PREFIX_LEN (sizeof(STATIC_CALL_KEY_PREFIX_STR) - 1)
811
#define STATIC_CALL_KEY(name) __PASTE(STATIC_CALL_KEY_PREFIX, name)
912

1013
#define STATIC_CALL_TRAMP_PREFIX __SCT__
1114
#define STATIC_CALL_TRAMP_PREFIX_STR __stringify(STATIC_CALL_TRAMP_PREFIX)
15+
#define STATIC_CALL_TRAMP_PREFIX_LEN (sizeof(STATIC_CALL_TRAMP_PREFIX_STR) - 1)
1216
#define STATIC_CALL_TRAMP(name) __PASTE(STATIC_CALL_TRAMP_PREFIX, name)
1317
#define STATIC_CALL_TRAMP_STR(name) __stringify(STATIC_CALL_TRAMP(name))
1418

19+
/*
20+
* The static call site table needs to be created by external tooling (objtool
21+
* or a compiler plugin).
22+
*/
23+
struct static_call_site {
24+
s32 addr;
25+
s32 key;
26+
};
27+
1528
#endif /* _STATIC_CALL_TYPES_H */

kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ obj-$(CONFIG_CPU_PM) += cpu_pm.o
111111
obj-$(CONFIG_BPF) += bpf/
112112
obj-$(CONFIG_KCSAN) += kcsan/
113113
obj-$(CONFIG_SHADOW_CALL_STACK) += scs.o
114+
obj-$(CONFIG_HAVE_STATIC_CALL_INLINE) += static_call.o
114115

115116
obj-$(CONFIG_PERF_EVENTS) += events/
116117

kernel/module.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3274,6 +3274,11 @@ static int find_module_sections(struct module *mod, struct load_info *info)
32743274
mod->kprobe_blacklist = section_objs(info, "_kprobe_blacklist",
32753275
sizeof(unsigned long),
32763276
&mod->num_kprobe_blacklist);
3277+
#endif
3278+
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
3279+
mod->static_call_sites = section_objs(info, ".static_call_sites",
3280+
sizeof(*mod->static_call_sites),
3281+
&mod->num_static_call_sites);
32773282
#endif
32783283
mod->extable = section_objs(info, "__ex_table",
32793284
sizeof(*mod->extable), &mod->num_exentries);

0 commit comments

Comments
 (0)