Skip to contentSkip to conversation

bpf, arm64/riscv: Remove redundant icache flush after pack allocator finalize

PATCH Applied Puranjay Mohan 8 participants 11 messages Apr 13 – Apr 30

Subsystems (6)
BPF RISC-V arm64 BPF JIT for arm64 +2 more subsystems
lore
Share & tools
lore

Puranjay Mohan

author maintainer
#0 lore raw

v2 cover bpf, arm64/riscv: Remove redundant icache flush after pack allocator finalize

Changelog:
v1: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Remove "#include <asm/cacheflush.h>" as it is not needed now.
- Add Acked-by: Song Liu <[email protected]>

When the BPF prog pack allocator was added for arm64 and riscv, the existing bpf_flush_icache() calls were retained after bpf_jit_binary_pack_finalize(). However, the finalize path copies the JITed code via architecture text patching routines (__text_poke on arm64, patch_text_nosync on riscv) that already perform a full flush_icache_range() internally. The subsequent bpf_flush_icache() repeats the same cache maintenance on the same range.

Remove the redundant flush and the now-unused bpf_flush_icache() definitions on both architectures.

Puranjay Mohan (2):
bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator
finalize
bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator
finalize

 arch/arm64/net/bpf_jit_comp.c | 12 ------------
 arch/riscv/net/bpf_jit.h      |  6 ------
 arch/riscv/net/bpf_jit_core.c |  7 -------
 3 files changed, 25 deletions(-)

base-commit: 71b500afd2f7336f5b6c6026f2af546fc079be26

Signature · 1 line
2.52.0
author maintainer
#1 lore raw

PATCH v2 1/2 bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management"), this flush is redundant.

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), and __text_poke() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range, including an unnecessary second synchronous IPI to all CPUs via kick_all_cpus_sync().

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management")
---
 arch/arm64/net/bpf_jit_comp.c | 12 ------------
 1 file changed, 12 deletions(-)
arch/arm64/net/bpf_jit_comp.c +0 -12
index adf84962d579..7417d24a5b6f 100644
@@ -18,7 +18,6 @@
 
 #include <asm/asm-extable.h>
 #include <asm/byteorder.h>
-#include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/insn.h>
@@ -1961,11 +1960,6 @@ static int validate_ctx(struct jit_ctx *ctx)
 	return 0;
 }
 
-static inline void bpf_flush_icache(void *start, void *end)
-{
-	flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
 static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
 {
 	int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
@@ -2204,12 +2198,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 			prog = orig_prog;
 			goto out_off;
 		}
-		/*
-		 * The instructions have now been copied to the ROX region from
-		 * where they will execute. Now the data cache has to be cleaned to
-		 * the PoU and the I-cache has to be invalidated for the VAs.
-		 */
-		bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx);
 	} else {
 		jit_data->ctx = ctx;
 		jit_data->ro_image = ro_image_ptr;
Signature · 1 line
2.52.0
reviewer
#2 lore raw

Re: [PATCH bpf-next v2 1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

Quoted 5 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management"), this flush is redundant.

Quoted 7 lines

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), and __text_poke() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range, including an unnecessary second synchronous IPI to all CPUs via kick_all_cpus_sync().

So icache is flushed twice: once per instruction and again after all instructions are copied. I think it's better to remove the per-instruction flush and retain the single final flush to avoid repeating flush overhead for each instruction.

Quoted 47 lines

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management")
---
  arch/arm64/net/bpf_jit_comp.c | 12 ------------
  1 file changed, 12 deletions(-)
arch/arm64/net/bpf_jit_comp.c +0 -12
index adf84962d579..7417d24a5b6f 100644
@@ -18,7 +18,6 @@
 
  #include <asm/asm-extable.h>
  #include <asm/byteorder.h>
-#include <asm/cacheflush.h>
  #include <asm/cpufeature.h>
  #include <asm/debug-monitors.h>
  #include <asm/insn.h>
@@ -1961,11 +1960,6 @@ static int validate_ctx(struct jit_ctx *ctx)
  	return 0;
  }
 
-static inline void bpf_flush_icache(void *start, void *end)
-{
-	flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
  static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size)
  {
  	int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3;
@@ -2204,12 +2198,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
  			prog = orig_prog;
  			goto out_off;
  		}
-		/*
-		 * The instructions have now been copied to the ROX region from
-		 * where they will execute. Now the data cache has to be cleaned to
-		 * the PoU and the I-cache has to be invalidated for the VAs.
-		 */
-		bpf_flush_icache(ro_header, ctx.ro_image + ctx.idx);
  	} else {
  		jit_data->ctx = ctx;
  		jit_data->ro_image = ro_image_ptr;
#3 lore raw

Re: [PATCH bpf-next v2 1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

Quoted 15 lines · Xu Kuohai
Quoted 5 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management"), this flush is redundant.

Quoted 7 lines

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), and __text_poke() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range, including an unnecessary second synchronous IPI to all CPUs via kick_all_cpus_sync().

Quoted 4 lines

So icache is flushed twice: once per instruction and again after all instructions are copied. I think it's better to remove the per-instruction flush and retain the single final flush to avoid repeating flush overhead for each instruction.

No, bpf_jit_binary_pack_finalize() is called at the end after the whole program is jited, and it calls: bpf_arch_text_copy(ro_header, rw_header, rw_header->size); which does aarch64_insn_copy(dst, src, len), this calls __text_poke() which copies the whole program and then does flush_icache_range((uintptr_t)addr, (uintptr_t)addr + len); once. This is correct, after this we don't need to call flush_icache_range() on the same range again.

If we had been calling flush_icache_range() for each instruction, the system would hang due to the storm of IPIs.

reviewer
#4 lore raw

Re: [PATCH bpf-next v2 1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

Quoted 29 lines · Puranjay Mohan
Quoted 15 lines · Xu Kuohai
Quoted 5 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management"), this flush is redundant.

Quoted 7 lines

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), and __text_poke() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range, including an unnecessary second synchronous IPI to all CPUs via kick_all_cpus_sync().

Quoted 4 lines

So icache is flushed twice: once per instruction and again after all instructions are copied. I think it's better to remove the per-instruction flush and retain the single final flush to avoid repeating flush overhead for each instruction.

No, bpf_jit_binary_pack_finalize() is called at the end after the whole program is jited, and it calls: bpf_arch_text_copy(ro_header, rw_header, rw_header->size); which does aarch64_insn_copy(dst, src, len), this calls __text_poke() which copies the whole program and then does flush_icache_range((uintptr_t)addr, (uintptr_t)addr + len); once. This is correct, after this we don't need to call flush_icache_range() on the same range again.

Quoted 2 lines

If we had been calling flush_icache_range() for each instruction, the system would hang due to the storm of IPIs.

Right, thanks for the explanation!

LGTM.

Acked-by on v2 1/2
#5 lore raw

Re: [PATCH bpf-next v2 1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

In reply to Puranjay Mohan
Quoted 12 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management"), this flush is redundant.

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> aarch64_insn_copy() -> __text_poke(), and __text_poke() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range, including an unnecessary second synchronous IPI to all CPUs via kick_all_cpus_sync().

Quoted 6 lines

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 1dad391daef1 ("bpf, arm64: use bpf_prog_pack for memory management")
author maintainer
#6 lore raw

PATCH v2 2/2 bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator finalize

In reply to Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT"), this flush is redundant.

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> patch_text_nosync(), and patch_text_nosync() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range.

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT")
---
 arch/riscv/net/bpf_jit.h      | 6 ------
 arch/riscv/net/bpf_jit_core.c | 7 -------
 2 files changed, 13 deletions(-)
arch/riscv/net/bpf_jit.h +0 -6
index 632ced07bca4..da0271790244 100644
@@ -11,7 +11,6 @@
 
 #include <linux/bpf.h>
 #include <linux/filter.h>
-#include <asm/cacheflush.h>
 
 /* verify runtime detection extension status */
 #define rv_ext_enabled(ext) \
@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size)
 	memset(area, 0, size);
 }
 
-static inline void bpf_flush_icache(void *start, void *end)
-{
-	flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
 /* Emit a 4-byte riscv instruction. */
 static inline void emit(const u32 insn, struct rv_jit_context *ctx)
 {
arch/riscv/net/bpf_jit_core.c +0 -7
index b3581e926436..f7fd4afc3ca3 100644
@@ -183,13 +183,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
 			prog = orig_prog;
 			goto out_offset;
 		}
-		/*
-		 * The instructions have now been copied to the ROX region from
-		 * where they will execute.
-		 * Write any modified data cache blocks out to memory and
-		 * invalidate the corresponding blocks in the instruction cache.
-		 */
-		bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns);
 		for (i = 0; i < prog->len; i++)
 			ctx->offset[i] = ninsns_rvoff(ctx->offset[i]);
 		bpf_prog_fill_jited_linfo(prog, ctx->offset);
Signature · 1 line
2.52.0
maintainer Reviewed-by on v2 2/2
#7 lore raw

Re: [PATCH bpf-next v2 2/2] bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator finalize

Quoted 54 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT"), this flush is redundant.

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> patch_text_nosync(), and patch_text_nosync() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range.

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT")
---
  arch/riscv/net/bpf_jit.h      | 6 ------
  arch/riscv/net/bpf_jit_core.c | 7 -------
  2 files changed, 13 deletions(-)
arch/riscv/net/bpf_jit.h +0 -6
index 632ced07bca4..da0271790244 100644
@@ -11,7 +11,6 @@
 
  #include <linux/bpf.h>
  #include <linux/filter.h>
-#include <asm/cacheflush.h>
 
  /* verify runtime detection extension status */
  #define rv_ext_enabled(ext) \
@@ -105,11 +104,6 @@ static inline void bpf_fill_ill_insns(void *area, unsigned int size)
  	memset(area, 0, size);
  }
 
-static inline void bpf_flush_icache(void *start, void *end)
-{
-	flush_icache_range((unsigned long)start, (unsigned long)end);
-}
-
  /* Emit a 4-byte riscv instruction. */
  static inline void emit(const u32 insn, struct rv_jit_context *ctx)
  {
arch/riscv/net/bpf_jit_core.c +0 -0
index b3581e926436..f7fd4afc3ca3 100644
@@ -183,13 +183,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
  			prog = orig_prog;
  			goto out_offset;
  		}

arch/riscv/net/bpf_jit_core.c struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) · line 188

Quoted 10 lines
arch/riscv/net/bpf_jit_core.c +0 -7
-		/*
-		 * The instructions have now been copied to the ROX region from
-		 * where they will execute.
-		 * Write any modified data cache blocks out to memory and
-		 * invalidate the corresponding blocks in the instruction cache.
-		 */
-		bpf_flush_icache(jit_data->ro_header, ctx->ro_insns + ctx->ninsns);
  		for (i = 0; i < prog->len; i++)
  			ctx->offset[i] = ninsns_rvoff(ctx->offset[i]);
  		bpf_prog_fill_jited_linfo(prog, ctx->offset);
Tested-by on v2 2/2
#8 lore raw

Re: [PATCH bpf-next v2 2/2] bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator finalize

In reply to Puranjay Mohan
Quoted 11 lines · Puranjay Mohan

bpf_flush_icache() calls flush_icache_range() to clean the data cache and invalidate the instruction cache for the JITed code region. However, since commit 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT"), this flush is redundant.

bpf_jit_binary_pack_finalize() copies the JITed instructions to the ROX region via bpf_arch_text_copy() -> patch_text_nosync(), and patch_text_nosync() already calls flush_icache_range() on the written range. The subsequent bpf_flush_icache() repeats the same cache maintenance on an overlapping range.

Quoted 6 lines

Remove the redundant bpf_flush_icache() call and its now-unused definition.

Fixes 48a8f78c50bd ("bpf, riscv: use prog pack allocator in the BPF JIT")

[...]

#9 lore raw
In reply to Puranjay Mohan
This series was applied to bpf/bpf.git (master) by Alexei Starovoitov <[email protected]>:

Hello:

This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <[email protected]>:

Quoted 14 lines · On Mon, 13 Apr 2026 12:11:07 -0700 you wrote:

Changelog:
v1: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Remove "#include <asm/cacheflush.h>" as it is not needed now.
- Add Acked-by: Song Liu <[email protected]>

When the BPF prog pack allocator was added for arm64 and riscv, the existing bpf_flush_icache() calls were retained after bpf_jit_binary_pack_finalize(). However, the finalize path copies the JITed code via architecture text patching routines (__text_poke on arm64, patch_text_nosync on riscv) that already perform a full flush_icache_range() internally. The subsequent bpf_flush_icache() repeats the same cache maintenance on the same range.

Quoted 1 line

[...]

Here is the summary with links:
- [bpf-next,v2,1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

    https://git.kernel.org/bpf/bpf/c/42f18ae53011
  - [bpf-next,v2,2/2] bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator finalize
    https://git.kernel.org/bpf/bpf/c/46ee1342b887

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
#10 lore raw
In reply to Puranjay Mohan
This series was applied to riscv/linux.git (fixes) by Alexei Starovoitov <[email protected]>:

Hello:

This series was applied to riscv/linux.git (fixes) by Alexei Starovoitov <[email protected]>:

Quoted 14 lines · On Mon, 13 Apr 2026 12:11:07 -0700 you wrote:

Changelog:
v1: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- Remove "#include <asm/cacheflush.h>" as it is not needed now.
- Add Acked-by: Song Liu <[email protected]>

When the BPF prog pack allocator was added for arm64 and riscv, the existing bpf_flush_icache() calls were retained after bpf_jit_binary_pack_finalize(). However, the finalize path copies the JITed code via architecture text patching routines (__text_poke on arm64, patch_text_nosync on riscv) that already perform a full flush_icache_range() internally. The subsequent bpf_flush_icache() repeats the same cache maintenance on the same range.

Quoted 1 line

[...]

Here is the summary with links:
- [bpf-next,v2,1/2] bpf, arm64: Remove redundant bpf_flush_icache() after pack allocator finalize

    https://git.kernel.org/riscv/c/42f18ae53011
  - [bpf-next,v2,2/2] bpf, riscv: Remove redundant bpf_flush_icache() after pack allocator finalize
    https://git.kernel.org/riscv/c/46ee1342b887

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html