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

Tiezhu Yang <[email protected]>
Newsgroups dev.linux.lists.loongarch,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.