> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 1c6863ce89e0..db89b3a591fa 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h

[ ... ]

> diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
> index a4298a25d4ba..df7634de0ca2 100644
> --- a/kernel/bpf/trampoline.c
> +++ b/kernel/bpf/trampoline.c
> @@ -30,6 +30,35 @@ static struct hlist_head 
> trampoline_ip_table[TRAMPOLINE_TABLE_SIZE];
>  /* serializes access to trampoline tables */
>  static DEFINE_MUTEX(trampoline_mutex);
>
> +/*
> + * Keep 32 trampoline locks (5 bits) in the pool so trampoline_lock_all()
> + * stays below MAX_LOCK_DEPTH.  Each pool slot has a distinct lockdep
> + * class because trampoline_lock_all() takes all pool mutexes at once;
> + * otherwise lockdep would report recursive locking on same-class mutexes.
> + */
> +#define TRAMPOLINE_LOCKS_BITS 5
> +#define TRAMPOLINE_LOCKS_TABLE_SIZE (1 << TRAMPOLINE_LOCKS_BITS)
> +
> +static struct {
> +     struct mutex mutex;
> +     struct lock_class_key key;
> +} trampoline_locks[TRAMPOLINE_LOCKS_TABLE_SIZE];
> +
> +static struct mutex *select_trampoline_lock(struct bpf_trampoline *tr)
> +{
> +     return &trampoline_locks[hash_64((u64)(uintptr_t) tr, 
> TRAMPOLINE_LOCKS_BITS)].mutex;
> +}

[ ... ]

> @@ -99,12 +128,12 @@ static int bpf_tramp_ftrace_ops_func(struct ftrace_ops 
> *ops, unsigned long ip,
>        *   cleanup_direct_functions_after_ipmodify
>        *
>        * In both cases, direct_mutex is already locked. Use
> -      * mutex_trylock(&tr->mutex) to avoid deadlock in race condition
> -      * (something else is making changes to this same trampoline).
> +      * mutex_trylock(select_trampoline_lock(tr)) to avoid deadlock in race 
> condition
> +      * (something else holds the same pool lock).
>        */
> -     if (!mutex_trylock(&tr->mutex)) {
> -             /* sleep 1 ms to make sure whatever holding tr->mutex makes
> -              * some progress.
> +     if (!mutex_trylock(select_trampoline_lock(tr))) {
> +             /* sleep 1 ms to make sure whatever holding 
> select_trampoline_lock(tr)
> +              * makes some progress.
>                */
>               msleep(1);
>               return -EAGAIN;

With 32 trampolines sharing pool locks, can mutex_trylock fail spuriously
when an unrelated trampoline holds the same bucket?

If the trylock fails, the function returns -EAGAIN. Could this mean
concurrent ftrace or kprobe registrations might randomly fail due to false
sharing in the pool?

Also, when the upcoming tracing_multi feature locks all 32 mutexes at once,
wouldn't that deterministically abort any concurrent ftrace IPMODIFY
registrations system-wide?

Finally, if this trylock failure happens during unregistration, could
ftrace cleanup routines ignore the -EAGAIN, potentially leaving the
BPF_TRAMP_F_SHARE_IPMODIFY flag permanently set and corrupting the
trampoline state?

Reference: 
https://lore.kernel.org/bpf/[email protected]/


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/26509800686

Reply via email to