From: Luca Di Maio <luca.dimaio1@gmail.com>
To: linux-xfs@vger.kernel.org
Cc: Luca Di Maio <luca.dimaio1@gmail.com>
Subject: [PATCH v2] xfs: test reproducible builds
Date: Fri, 12 Dec 2025 09:15:19 +0100 [thread overview]
Message-ID: <20251212081519.627879-1-luca.dimaio1@gmail.com> (raw)
With the addition of the `-p` populate option, SOURCE_DATE_EPOCH and
DETERMINISTIC_SEED support, it is possible to create fully reproducible
pre-populated filesystems. We should test them here.
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
---
tests/xfs/841 | 171 ++++++++++++++++++++++++++++++++++++++++++++++
tests/xfs/841.out | 3 +
2 files changed, 174 insertions(+)
create mode 100755 tests/xfs/841
create mode 100644 tests/xfs/841.out
diff --git a/tests/xfs/841 b/tests/xfs/841
new file mode 100755
index 00000000..e77533c3
--- /dev/null
+++ b/tests/xfs/841
@@ -0,0 +1,171 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Chainguard, Inc. All Rights Reserved.
+#
+# FS QA Test No. 841
+#
+# Test that XFS filesystems created with reproducibility options produce
+# identical images across multiple runs. This verifies that the combination
+# of SOURCE_DATE_EPOCH, DETERMINISTIC_SEED, and -m uuid= options result in
+# bit-for-bit reproducible filesystem images.
+
+. ./common/preamble
+_begin_fstest auto quick mkfs
+
+# Image file settings
+IMG_SIZE="512M"
+IMG_FILE="$TEST_DIR/xfs_reproducible_test.img"
+PROTO_DIR="$TEST_DIR/proto"
+
+# Fixed values for reproducibility
+FIXED_UUID="12345678-1234-1234-1234-123456789abc"
+FIXED_EPOCH="1234567890"
+
+# Check if mkfs.xfs supports required options
+_check_mkfs_xfs_options()
+{
+ local check_img="$TEST_DIR/mkfs_check.img"
+ truncate -s 64M "$check_img" || return 1
+
+ # Check -m uuid support
+ $MKFS_XFS_PROG -m uuid=00000000-0000-0000-0000-000000000000 \
+ -N "$check_img" &> /dev/null
+ local uuid_support=$?
+
+ # Check -p support (protofile/directory population)
+ $MKFS_XFS_PROG 2>&1 | grep populate &> /dev/null
+ local proto_support=$?
+
+ rm -f "$check_img"
+
+ if [ $uuid_support -ne 0 ]; then
+ _notrun "mkfs.xfs does not support -m uuid= option"
+ fi
+ if [ $proto_support -ne 0 ]; then
+ _notrun "mkfs.xfs does not support -p option for directory population"
+ fi
+}
+
+# Create a prototype directory with all file types supported by mkfs.xfs -p
+_create_proto_dir()
+{
+ rm -rf "$PROTO_DIR"
+ mkdir -p "$PROTO_DIR/subdir/nested"
+
+ # Regular files with different content
+ echo "test file content" > "$PROTO_DIR/regular.txt"
+ dd if=/dev/zero of="$PROTO_DIR/zeros" bs=1k count=4 2> /dev/null
+ echo "file in subdir" > "$PROTO_DIR/subdir/nested.txt"
+ echo "deeply nested" > "$PROTO_DIR/subdir/nested/deep.txt"
+
+ # Empty file
+ touch "$PROTO_DIR/empty"
+
+ # Symbolic links (file and directory)
+ ln -s regular.txt "$PROTO_DIR/symlink"
+ ln -s subdir "$PROTO_DIR/dirlink"
+
+ # Hardlink
+ ln "$PROTO_DIR/regular.txt" "$PROTO_DIR/hardlink"
+
+ # FIFO (named pipe)
+ mkfifo "$PROTO_DIR/fifo"
+
+ # Unix socket
+ $here/src/af_unix "$PROTO_DIR/socket" 2> /dev/null || true
+
+ # Block device (requires root)
+ mknod "$PROTO_DIR/blockdev" b 1 0 2> /dev/null || true
+
+ # Character device (requires root)
+ mknod "$PROTO_DIR/chardev" c 1 3 2> /dev/null || true
+
+ # File with extended attributes
+ echo "file with xattrs" > "$PROTO_DIR/xattrfile"
+ setfattr -n user.testattr -v "testvalue" "$PROTO_DIR/xattrfile" 2> /dev/null || true
+}
+
+_require_test
+_check_mkfs_xfs_options
+
+# Create XFS filesystem with full reproducibility options
+# Uses -p to populate from directory during mkfs (no mount needed)
+_mkfs_xfs_reproducible()
+{
+ local img=$1
+
+ # Create fresh image file
+ rm -f "$img"
+ truncate -s $IMG_SIZE "$img" || return 1
+
+ # Set environment variables for reproducibility:
+ # - SOURCE_DATE_EPOCH: fixes all inode timestamps to this value
+ # - DETERMINISTIC_SEED: uses fixed seed (0x53454544) instead of
+ # getrandom()
+ #
+ # mkfs.xfs options:
+ # - -m uuid=: fixed filesystem UUID
+ # - -p dir: populate filesystem from directory during creation
+ SOURCE_DATE_EPOCH=$FIXED_EPOCH \
+ DETERMINISTIC_SEED=1 \
+ $MKFS_XFS_PROG \
+ -f \
+ -m uuid=$FIXED_UUID \
+ -p "$PROTO_DIR" \
+ "$img" >> $seqres.full 2>&1
+
+ return $?
+}
+
+# Compute hash of the image file
+_hash_image()
+{
+ sha256sum "$1" | awk '{print $1}'
+}
+
+# Run a single reproducibility test iteration
+_run_iteration()
+{
+ local iteration=$1
+
+ echo "Iteration $iteration: Creating filesystem with -p $PROTO_DIR" >> $seqres.full
+ if ! _mkfs_xfs_reproducible "$IMG_FILE"; then
+ echo "mkfs.xfs failed" >> $seqres.full
+ return 1
+ fi
+
+ local hash=$(_hash_image "$IMG_FILE")
+ echo "Iteration $iteration: Hash = $hash" >> $seqres.full
+
+ echo $hash
+}
+
+# Create the prototype directory with various file types
+_create_proto_dir
+
+echo "Test: XFS reproducible filesystem image creation"
+
+# Run three iterations
+hash1=$(_run_iteration 1)
+[ -z "$hash1" ] && _fail "Iteration 1 failed"
+
+hash2=$(_run_iteration 2)
+[ -z "$hash2" ] && _fail "Iteration 2 failed"
+
+hash3=$(_run_iteration 3)
+[ -z "$hash3" ] && _fail "Iteration 3 failed"
+
+# Verify all hashes match
+if [ "$hash1" = "$hash2" ] && [ "$hash2" = "$hash3" ]; then
+ echo "All filesystem images are identical."
+else
+ echo "ERROR: Filesystem images differ!"
+ echo "Hash 1: $hash1"
+ echo "Hash 2: $hash2"
+ echo "Hash 3: $hash3"
+ _fail "Reproducibility test failed - images are not identical"
+fi
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/841.out b/tests/xfs/841.out
new file mode 100644
index 00000000..3bdfbfda
--- /dev/null
+++ b/tests/xfs/841.out
@@ -0,0 +1,3 @@
+QA output created by 841
+Test: XFS reproducible filesystem image creation
+All filesystem images are identical.
--
2.52.0
next reply other threads:[~2025-12-12 8:15 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-12 8:15 Luca Di Maio [this message]
2025-12-12 20:20 ` [PATCH v2] xfs: test reproducible builds Darrick J. Wong
2025-12-15 15:42 ` Luca Di Maio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251212081519.627879-1-luca.dimaio1@gmail.com \
--to=luca.dimaio1@gmail.com \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox