* [PATCH bpf] bpf: Don't hold pack_mutex over arm64 IPIs
@ 2026-10-24 3:10 Alexei Starovoitov
2026-10-27 19:59 ` Puranjay Mohan
0 siblings, 1 reply; 3+ messages in thread
From: Alexei Starovoitov @ 2026-10-24 3:10 UTC (permalink / raw)
To: bpf; +Cc: daniel, andrii, eddyz87, memxor
From: Alexei Starovoitov <ast@kernel.org>
bpf_prog_pack_free() calls bpf_arch_text_invalidate() with pack_mutex
held. On arm64 it interrupts all other CPUs and waits for them:
bpf_prog_free_deferred
bpf_jit_free
bpf_prog_pack_free
bpf_arch_text_invalidate
aarch64_insn_set
flush_icache_range
kick_all_cpus_sync
When many progs are freed at once, every prog load waits in
bpf_prog_pack_alloc() for all of these broadcasts. On arm64 hosts with
many CPUs we saw hung task reports with sk_attach_filter() blocked on
pack_mutex for minutes.
The bits of the range are still set in the bitmap during the
invalidation, so nobody can allocate it and the pack cannot be freed.
Drop pack_mutex around bpf_arch_text_invalidate() and take it again to
clear the bits.
Do it on arm64 only. x86, riscv, powerpc and loongarch take text_mutex in
bpf_arch_text_invalidate(). The frees would wait there instead, and the
load would wait for them in bpf_arch_text_copy().
Tested in arm64 KVM guests with 16 and 96 cpus on a 96 cpu host. cpus/2
processes attach a cBPF filter to 256 sockets and close them in a loop
for 20 sec. One more process attaches a filter every msec. Median of
5 runs.
The loops get more done. Sockets attached and closed in 20 sec, in
millions (higher is better):
before after
16 cpus 1.6 4.7
96 cpus 0.38 4.2
setsockopt(SO_ATTACH_FILTER) of the process that attaches every msec
takes less time, in msec (lower is better):
16 cpus 96 cpus
before after before after
avg 0.97 0.18 11 0.54
p99 20 2.8 421 4.0
max 204 90 1738 255
Fixes: 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
kernel/bpf/core.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 3030beb531d9..0fef87cfa152 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1069,8 +1069,17 @@ void bpf_prog_pack_free(void *ptr, u32 size)
nbits = BPF_PROG_SIZE_TO_NBITS(size);
pos = ((unsigned long)ptr - (unsigned long)pack->ptr) >> BPF_PROG_CHUNK_SHIFT;
+ /*
+ * arm64 sends IPI to all CPUs in bpf_arch_text_invalidate().
+ * Don't hold pack_mutex across it. The bits are still set,
+ * so the range cannot be reused and the pack cannot be freed.
+ */
+ if (IS_ENABLED(CONFIG_ARM64))
+ mutex_unlock(&pack_mutex);
WARN_ONCE(bpf_arch_text_invalidate(ptr, size),
"bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n");
+ if (IS_ENABLED(CONFIG_ARM64))
+ mutex_lock(&pack_mutex);
bitmap_clear(pack->bitmap, pos, nbits);
base-commit: b116ac6087541d3d98031e786adbe9c733cd6df3
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH bpf] bpf: Don't hold pack_mutex over arm64 IPIs
2026-10-24 3:10 [PATCH bpf] bpf: Don't hold pack_mutex over arm64 IPIs Alexei Starovoitov
@ 2026-10-27 19:59 ` Puranjay Mohan
2026-10-28 4:23 ` Alexei Starovoitov
0 siblings, 1 reply; 3+ messages in thread
From: Puranjay Mohan @ 2026-10-27 19:59 UTC (permalink / raw)
To: Alexei Starovoitov, bpf; +Cc: daniel, andrii, eddyz87, memxor, Puranjay Mohan
Alexei Starovoitov <alexei.starovoitov@gmail.com> writes:
> From: Alexei Starovoitov <ast@kernel.org>
>
> bpf_prog_pack_free() calls bpf_arch_text_invalidate() with pack_mutex
> held. On arm64 it interrupts all other CPUs and waits for them:
>
> bpf_prog_free_deferred
> bpf_jit_free
> bpf_prog_pack_free
> bpf_arch_text_invalidate
> aarch64_insn_set
> flush_icache_range
> kick_all_cpus_sync
>
> When many progs are freed at once, every prog load waits in
> bpf_prog_pack_alloc() for all of these broadcasts. On arm64 hosts with
> many CPUs we saw hung task reports with sk_attach_filter() blocked on
> pack_mutex for minutes.
>
> The bits of the range are still set in the bitmap during the
> invalidation, so nobody can allocate it and the pack cannot be freed.
> Drop pack_mutex around bpf_arch_text_invalidate() and take it again to
> clear the bits.
>
> Do it on arm64 only. x86, riscv, powerpc and loongarch take text_mutex in
> bpf_arch_text_invalidate(). The frees would wait there instead, and the
> load would wait for them in bpf_arch_text_copy().
>
> Tested in arm64 KVM guests with 16 and 96 cpus on a 96 cpu host. cpus/2
> processes attach a cBPF filter to 256 sockets and close them in a loop
> for 20 sec. One more process attaches a filter every msec. Median of
> 5 runs.
>
> The loops get more done. Sockets attached and closed in 20 sec, in
> millions (higher is better):
>
> before after
> 16 cpus 1.6 4.7
> 96 cpus 0.38 4.2
>
> setsockopt(SO_ATTACH_FILTER) of the process that attaches every msec
> takes less time, in msec (lower is better):
>
> 16 cpus 96 cpus
> before after before after
> avg 0.97 0.18 11 0.54
> p99 20 2.8 421 4.0
> max 204 90 1738 255
>
> Fixes: 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management")
> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
> ---
> kernel/bpf/core.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 3030beb531d9..0fef87cfa152 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1069,8 +1069,17 @@ void bpf_prog_pack_free(void *ptr, u32 size)
> nbits = BPF_PROG_SIZE_TO_NBITS(size);
> pos = ((unsigned long)ptr - (unsigned long)pack->ptr) >> BPF_PROG_CHUNK_SHIFT;
>
> + /*
> + * arm64 sends IPI to all CPUs in bpf_arch_text_invalidate().
> + * Don't hold pack_mutex across it. The bits are still set,
> + * so the range cannot be reused and the pack cannot be freed.
> + */
> + if (IS_ENABLED(CONFIG_ARM64))
> + mutex_unlock(&pack_mutex);
> WARN_ONCE(bpf_arch_text_invalidate(ptr, size),
> "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n");
> + if (IS_ENABLED(CONFIG_ARM64))
Can't we do the bpf_arch_text_invalidate() before taking the pack_mutex?
then it works on all architectures and there is no lock nesting.
Because the caller owns [ptr, ptr+size) until bitmap_clear() so it
should work.
I can commandeer it if you want.
Thanks,
Puranjay
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH bpf] bpf: Don't hold pack_mutex over arm64 IPIs
2026-10-27 19:59 ` Puranjay Mohan
@ 2026-10-28 4:23 ` Alexei Starovoitov
0 siblings, 0 replies; 3+ messages in thread
From: Alexei Starovoitov @ 2026-10-28 4:23 UTC (permalink / raw)
To: Puranjay Mohan, bpf; +Cc: daniel, andrii, eddyz87, memxor, Puranjay Mohan
On Tue, Oct 27, 2026 at 12:59 PM Puranjay Mohan <puranjay@kernel.org> wrote:
> Can't we do the bpf_arch_text_invalidate() before taking the pack_mutex?
> then it works on all architectures and there is no lock nesting.
>
> Because the caller owns [ptr, ptr+size) until bitmap_clear() so it
> should work.
Interesting idea. I guess that's simpler.
bpf_arch_text_copy() already writes into a pack without pack_mutex.
but other archs gain nothing. fine.
> I can commandeer it if you want.
Sure. pls go ahead.
pw-bot:cr
first time for my own patches. next level unlocked :)
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-28 4:23 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-24 3:10 [PATCH bpf] bpf: Don't hold pack_mutex over arm64 IPIs Alexei Starovoitov
2026-10-27 19:59 ` Puranjay Mohan
2026-10-28 4:23 ` Alexei Starovoitov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox