Re: [PATCH v1] LoongArch: Fix __smp_mb__{before,after}_atomic()

From: Tiezhu Yang

Date: Wed Aug 19 2026 - 00:33:12 EST


On 2026/8/18 下午10:05, Kumar Kartikeya Dwivedi wrote:
On Tue Aug 18, 2026 at 3:50 PM CEST, Tiezhu Yang wrote:
On 2026/8/18 下午9:35, Kumar Kartikeya Dwivedi wrote:
On Tue Aug 18, 2026 at 3:28 PM CEST, Tiezhu Yang wrote:
On 2026/8/17 上午11:59, Tiezhu Yang wrote:
When testing the BPF selftest "sudo ./test_progs -t timer_lockup", there
is a kernel lockup and panic:

...

There is a full barrier in both cases. I don't know what performance improvement
will be achieved by changing this.

We performed benchmarking using UnixBench on a physical LoongArch
machine, the UnixBench score is different (amadd.w + dbar < amadd_db.w).


I mean, this function is already quite heavy. We have multiple fully ordered
atomics (refcount bumps/drops, xchg(), etc.) spread across the operation. Do you
observe any measurable speedup in the throughput of this function? The second
question is whether timer cancellation is really frequent. In practice, I don't
think that is the case. The actual hrtimer_cancel() in itself is heavy and
waits synchronously for the callback to finish.

I'm not opposed to it or anything, I just don't think it's worth it in this
case. If the latency of cancel is a problem there are other bigger opportunities
to pursue than this.

Hi Kumar,

Thanks for your analysis. I totally agree that bpf_timer_cancel() is
heavy and cancellation is not a frequent fast path.

However, there is an interesting compiler and architecture background
here:

During our internal review, toolchain developers noted that executing
two separate instructions (amadd.w + dbar) causes a noticeable pipeline
bubble, and they are currently working on a compiler-level optimization
to automatically fuse them into a single ordered instruction amadd_db.w.

Since toolchain-level fusion into a single instruction is the clear
goal, explicitly using atomic_fetch_add() in the BPF helper achieves
this exact single-instruction benefit immediately, without waiting
for compiler updates.

More importantly, it hardens defensive programming, making the BPF
core logic immune to any architecture-level macro omissions.

To provide a concrete micro-architectural perspective, here is the
actual objdump comparison on a physical LoongArch machine between
the two approaches:

Approach 1 (Architecture fix: atomic_inc + smp_mb__after_atomic):
2610: amadd.w $zero, $t2, $t3 /* Relaxed atomic increment */
2614: dbar 0x10 /* Explicit data memory barrier */

Approach 2 (Our BPF core change: atomic_fetch_add):
2610: amadd_db.w $t3, $t1, $t4 /* Consolidated ordered atomic */

As the assembly shows, Approach 2 successfully eliminates a heavy
standalone hardware fence instruction (dbar 0x10).

What are your thoughts on this logic?

---
Appendix: Code Diff & Objdump for Reference

[1] Code Diff & Objdump for Approach 1:
diff --git a/arch/loongarch/include/asm/barrier.h b/arch/loongarch/include/asm/barrier.h
index 4b663f197706..adfe343dfa65 100644
--- a/arch/loongarch/include/asm/barrier.h
+++ b/arch/loongarch/include/asm/barrier.h
@@ -57,8 +57,8 @@
#define __WEAK_LLSC_MB " \n"
#endif

-#define __smp_mb__before_atomic() barrier()
-#define __smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() __smp_mb()
+#define __smp_mb__after_atomic() __smp_mb()

$ objdump -d -S kernel/bpf/helpers.o
ATOMIC_OPS(add, i, add, +)
2608: 0280040e li.w $t2, 1
260c: 02c2e2ef addi.d $t3, $s0, 184
2610: 386139e0 amadd.w $zero, $t2, $t3
smp_mb__after_atomic();
2614: 38720010 dbar 0x10

[2] Code Diff & Objdump for Approach 2:
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index c18f1e16edee..ee2b3a4dcc05 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -1591,9 +1591,7 @@ BPF_CALL_1(bpf_timer_cancel, struct bpf_async_kern *, async)
*/
if (!cur_t)
goto drop;
- atomic_inc(&t->cancelling);
- /* Need full barrier after relaxed atomic_inc */
- smp_mb__after_atomic();
+ atomic_fetch_add(1, &t->cancelling);
inc = true;
if (atomic_read(&cur_t->cancelling)) {

$ objdump -d -S kernel/bpf/helpers.o
ATOMIC_OPS(add, i, add, +)
2608: 0280040d li.w $t1, 1
260c: 02c2e2f0 addi.d $t4, $s0, 184
2610: 386a360f amadd_db.w $t3, $t1, $t4

Thanks,
Tiezhu