[PATCH 3/3] erofs-utils: tests: check that the xattr layout is order-independent

Martin Pitt <[email protected]> Tue, 4 Aug 2026 05:32:14 +0200
Newsgroups org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>
b260119b8edb ("erofs-utils: mkfs: emit an inode's xattrs in a canonical
order") made the layout independent of the order listxattr(2) reports an
inode's attributes in. Cover it: stage the same tree twice with the same
attributes set in opposite order, and compare the two images. The names
differ in length and share prefixes, so a subtly wrong comparison cannot
order them correctly by accident.

Signed-off-by: Martin Pitt <[email protected]>
---
 tests/Makefile.am   |  3 ++
 tests/erofs/032     | 77 +++++++++++++++++++++++++++++++++++++++++++++
 tests/erofs/032.out |  2 ++
 3 files changed, 82 insertions(+)
 create mode 100755 tests/erofs/032
 create mode 100644 tests/erofs/032.out

diff --git a/tests/Makefile.am b/tests/Makefile.am
index c0291ac..363b93d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -132,6 +132,9 @@ TESTS += erofs/030
 # 031 - test chunk-based mapping with shared chunks across inodes
 TESTS += erofs/031
 
+# 032 - check that the xattr layout does not depend on listxattr(2) order
+TESTS += erofs/032
+
 # NEW TEST CASE HERE
 # TESTS += erofs/999
 
diff --git a/tests/erofs/032 b/tests/erofs/032
new file mode 100755
index 0000000..063ed2c
--- /dev/null
+++ b/tests/erofs/032
@@ -0,0 +1,77 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Check that the xattr layout does not depend on listxattr(2) order
+#
+# listxattr(2) makes no promise about the order it reports, and filesystems
+# disagree: tmpfs reports the order the attributes were set in, while ext4 and
+# btrfs report their own on-disk order. The same set of attributes must end up
+# in the same layout however mkfs.erofs is handed them, otherwise images are
+# not reproducible. The names also differ in length and share prefixes, which
+# exercises the length tiebreak.
+#
+# On a filesystem that reports its own order rather than the insertion order
+# this check cannot fail, so it needs $tmp on a filesystem that keeps insertion
+# order or randomizes it, like tmpfs, which /tmp normally is.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$(echo $0 | awk '{print $((NF-1))"/"$NF}' FS="/")
+
+# get standard environment, filters and checks
+. "${srcdir}/common/rc"
+
+cleanup()
+{
+	cd /
+	rm -rf $tmp.*
+}
+
+_require_xattr
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+echo "QA output created by $seq"
+
+attrs="user.aa=1 user.mm=22 user.mm_long=333 user.zz=4444
+user.a_long_attribute_name=55555 user.growfs=666666 user.roothash=7777777
+user.verity=88888888 user.gpt_label=999999999 user.gpt_type_uuid=aaaaaaaaaa"
+
+localdir=$tmp/$seq
+rm -rf $localdir
+
+# same tree and same attributes twice, set in opposite order
+for pass in forward reverse; do
+	tree=$localdir/$pass
+	mkdir -p $tree/dir
+	echo payload > $tree/dir/file
+
+	list=$attrs
+	if [ $pass = reverse ]; then
+		list=
+		for attr in $attrs; do
+			list="$attr $list"
+		done
+	fi
+	for attr in $list; do
+		setfattr -n "${attr%%=*}" -v "${attr#*=}" $tree ||
+			_fail "failed to set ${attr%%=*}"
+	done
+
+	# pin the timestamps and the filesystem UUID, so the attribute order
+	# is the only thing that can differ
+	$MKFS_EROFS_PROG -T1739577600 -U 5230d7cf-f2ce-43ed-9ae2-39e7e2fe48ca \
+		$localdir/$pass.img $tree >> $seqres.full 2>&1 ||
+		_fail "failed to mkfs"
+done
+
+$FSCK_EROFS_PROG --extract $localdir/forward.img >> $seqres.full 2>&1 ||
+	_fail "fsck failed"
+
+cmp -s $localdir/forward.img $localdir/reverse.img ||
+	_fail "the image depends on the order listxattr(2) reported"
+
+echo Silence is golden
+status=0
+exit 0
diff --git a/tests/erofs/032.out b/tests/erofs/032.out
new file mode 100644
index 0000000..34e059f
--- /dev/null
+++ b/tests/erofs/032.out
@@ -0,0 +1,2 @@
+QA output created by 032
+Silence is golden
-- 
2.55.0