bpf, x86: Use global buffer for trampoline size generation

Currently arch_bpf_trampoline_size allocates and frees a temporary
trampoline buffer on every invocation. The buffer is only used as a
scratch space while __arch_prepare_bpf_trampoline() calculates the
required size, and the generated trampoline is discarded.

Allocating a writable scratch page during kernel initialization and
reusing it for all size calculations. This improves tracing_multi
attachment time.

With current code:

  # ./test_progs -t tracing_multi_bench_attach -v
  ...
  serial_test_tracing_multi_bench_attach: found 55227 functions
  serial_test_tracing_multi_bench_attach: attached in   1.563s
  serial_test_tracing_multi_bench_attach: detached in   0.256s

With the fix:

  # ./test_progs -t tracing_multi_bench_attach -v
  ...
  serial_test_tracing_multi_bench_attach: found 55235 functions
  serial_test_tracing_multi_bench_attach: attached in   0.798s
  serial_test_tracing_multi_bench_attach: detached in   0.258s

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20260910094353.1256316-1-jolsa@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Jiri Olsa 2026-09-10 11:43:53 +02:00 committed by Alexei Starovoitov
parent 698181b2d5
commit 29fcf9ce4b

View File

@ -9,6 +9,7 @@
#include <linux/filter.h>
#include <linux/if_vlan.h>
#include <linux/bitfield.h>
#include <linux/init.h>
#include <linux/bpf.h>
#include <linux/bpf_verifier.h>
#include <linux/memory.h>
@ -35,6 +36,21 @@ void __asan_store8(void *p);
static bool all_callee_regs_used[4] = {true, true, true, true};
static void *trampoline_size_image;
static int __init init_trampoline_size_image(void)
{
/*
* The generated trampoline contains calls and jumps with 32bit relative
* offsets, so the scratch image must be in the execmem range.
* On x86, module data and executable memory share the same address range,
* so using EXECMEM_MODULE_DATA to get writable memory.
*/
trampoline_size_image = execmem_alloc(EXECMEM_MODULE_DATA, PAGE_SIZE);
return trampoline_size_image ? 0 : -ENOMEM;
}
late_initcall(init_trampoline_size_image);
static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
{
if (len == 1)
@ -4067,24 +4083,14 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
struct bpf_tramp_nodes *tnodes, void *func_addr)
{
struct bpf_tramp_image im;
void *image;
int ret;
/* Allocate a temporary buffer for __arch_prepare_bpf_trampoline().
*
* We cannot use kvmalloc here, because we need image to be in
* module memory range.
* Since it must be writable use execmem_alloc(EXECMEM_MODULE_DATA)
* that returns writable memory in the module address space.
*/
image = execmem_alloc(EXECMEM_MODULE_DATA, PAGE_SIZE);
if (!image)
if (!trampoline_size_image)
return -ENOMEM;
ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, image,
m, flags, tnodes, func_addr);
execmem_free(image);
return ret;
return __arch_prepare_bpf_trampoline(&im, trampoline_size_image,
trampoline_size_image + PAGE_SIZE,
trampoline_size_image, m, flags,
tnodes, func_addr);
}
static int emit_bpf_dispatcher(u8 **pprog, int a, int b, s64 *progs, u8 *image, u8 *buf)