[PATCH] erofs: weaken full memory barriers to r/w barriers

Bingwu Zhang <[email protected]> Thu, 30 Jul 2026 12:01:20 +0800
Newsgroups org.ozlabs.lists.linux-erofs,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Bingwu Zhang <[email protected]>

fs/erofs/{xattr.c,zmap.c} both implemented one-time initialization locks
with general memory barriers.

Weaken these unnecessarily-strong general memory barriers to SMP
(ordering) read/write barriers for better performance on weakly-ordered
architectures.

Signed-off-by: Bingwu Zhang <[email protected]>
---
(All test results below are done using QEMU with KVM; guest VM root FS
are mounted with v9fs; test target is an EROFS mounted on a loop device
backed by a file in tmpfs, in attempt to reduce error caused by physical
disks; mkfs flags: --zD=1 --all-root -zzstd -E48bit)

On x86-64, with x86-TSO, a full barrier lowers to a fence instruction and
read/write barriers are just compiler barriers. This patch removes
several fence instructions although they don't affect performance much.

On weakly-ordered architectures, a full memory barrier could be very
expensive. Thus, on these platforms, this patch saves more performance
than x86-64.

Test result on x86-64:
(host: AMD Ryzen 7 255 (@ 3.3GHz))
(guest VM: ArchLinux, test data: linux.git/drivers @ commit fc02acf6ac0c)
  Original:
    read: IOPS=1684, BW=6737KiB/s (6899kB/s)(1006MiB/152838msec)
    clat (usec): min=25, max=26293, avg=578.58, stdev=426.55
     lat (usec): min=25, max=26293, avg=578.70, stdev=426.56
   bw (  KiB/s): min= 1976, max=10904, per=100.00%, avg=6749.91,
      stdev=1883.80, samples=305
   iops        : min=  494, max= 2726, avg=1687.48, stdev=470.95, samples=305

  New:
   read: IOPS=1687, BW=6751KiB/s (6913kB/s)(1006MiB/152513msec)
    clat (usec): min=25, max=19136, avg=577.00, stdev=425.66
     lat (usec): min=25, max=19136, avg=577.09, stdev=425.67
   bw (  KiB/s): min= 2192, max=11088, per=100.00%, avg=6770.26
      stdev=1870.55, samples=304
   iops        : min=  548, max= 2772, avg=1692.44, stdev=467.65, samples=304

IOPS +0.17%, bandwidth +0.20%, max completion latency -27.22%

Test result on ARM64:
(host: HUAWEI Kunpeng 920 @ 2.6GHz, both host & VM are AOSC OS)
(test data:
1. AOSC OS: aosc-os_base_20260621_arm64.squashfs, /usr/bin directory is
   repacked as EROFS.
2. linux.git at commit fc02acf6ac0c, drivers/ subdirectory
)
  Original:
   read: IOPS=12.3k, BW=47.9MiB/s (50.2MB/s)(1291MiB/26950msec)
    clat (nsec): min=910, max=37500k, avg=56026.68, stdev=198628.59
     lat (nsec): min=960, max=37500k, avg=56167.70, stdev=198639.09
   bw (  KiB/s): min= 3888, max=94328, per=100.00%, avg=49790.64,
      stdev=31594.09, samples=53
   iops        : min=  972, max=23582, avg=12447.57, stdev=7898.51, samples=53

  New:
   read: IOPS=13.8k, BW=54.0MiB/s (56.6MB/s)(1315MiB/24375msec)
    clat (nsec): min=930, max=34271k, avg=53069.97, stdev=145651.76
     lat (nsec): min=980, max=34271k, avg=53221.68, stdev=145661.24
   bw (  KiB/s): min= 5843, max=95054, per=100.00%, avg=55988.58,
      stdev=30477.44, samples=48
   iops        : min= 1460, max=23763, avg=13997.00, stdev=7619.37, samples=48

IOPS min +50.20%, avg +12.44%
bandwidth min +50.28%, max +0.76%, avg +12.44%
completion latency max -8.61%, avg -5.27%

I am not pretty sure why the minimum completion latencies vary so much on
AArch64. Even when I repeat the test with the same kernel without
rebooting/re-mounting, clat min fluctuates randomly, sometimes spiking to
over 1000 and sometimes dropping to as low as 2, but I think this patch
still improves the overall throughput performance.
---
 fs/erofs/xattr.c | 8 ++++----
 fs/erofs/zmap.c  | 8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/fs/erofs/xattr.c b/fs/erofs/xattr.c
index df7ea019526d..0b252cfe616a 100644
--- a/fs/erofs/xattr.c
+++ b/fs/erofs/xattr.c
@@ -44,10 +44,10 @@ static int erofs_init_inode_xattrs(struct inode *inode)
 	/* the most case is that xattrs of this inode are initialized. */
 	if (test_bit(EROFS_I_EA_INITED_BIT, &vi->flags)) {
 		/*
-		 * paired with smp_mb() at the end of the function to ensure
+		 * paired with smp_wmb() at the end of the function to ensure
 		 * fields will only be observed after the bit is set.
 		 */
-		smp_mb();
+		smp_rmb();
 		return 0;
 	}
 	if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_XATTR_BIT, TASK_KILLABLE))
@@ -111,8 +111,8 @@ static int erofs_init_inode_xattrs(struct inode *inode)
 		vi->xattr_shared_xattrs[i] = le32_to_cpu(*xattr_id);
 	}
 
-	/* paired with smp_mb() at the beginning of the function. */
-	smp_mb();
+	/* paired with smp_rmb() at the beginning of the function. */
+	smp_wmb();
 	set_bit(EROFS_I_EA_INITED_BIT, &vi->flags);
 out_unlock:
 	erofs_put_metabuf(&buf);
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index 5811556a7b71..d5b001a537f4 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -628,10 +628,10 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map)
 
 	if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) {
 		/*
-		 * paired with smp_mb() at the end of the function to ensure
+		 * paired with smp_wmb() at the end of the function to ensure
 		 * fields will only be observed after the bit is set.
 		 */
-		smp_mb();
+		smp_rmb();
 		return 0;
 	}
 
@@ -704,8 +704,8 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map)
 			goto out_unlock;
 	}
 done:
-	/* paired with smp_mb() at the beginning of the function */
-	smp_mb();
+	/* paired with smp_rmb() at the beginning of the function */
+	smp_wmb();
 	set_bit(EROFS_I_Z_INITED_BIT, &vi->flags);
 out_unlock:
 	clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags);

---
base-commit: 11028ab62899e4191e074ee364c712b77823a9c4
change-id: 20260729-erofs-weaken-dbar-9fd2edff90e5

Best regards,
--  
Bingwu Zhang <[email protected]>