Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Yifan Zhao <stopire@gmail.com>
To: linux-erofs@lists.ozlabs.org
Cc: Yifan Zhao <stopire@gmail.com>
Subject: [PATCH 2/2] erofs-utils: tests: add multi-device chunk read regression test
Date: Fri, 26 Jun 2026 10:50:25 +0800	[thread overview]
Message-ID: <20260626025025.805563-2-stopire@gmail.com> (raw)
In-Reply-To: <20260626025025.805563-1-stopire@gmail.com>

Unfortunately, erofs-utils currently lacks image injection support,
so the test has to hard-code the relevant offsets.

Assisted-by: Codex:GPT-5.5
Signed-off-by: Yifan Zhao <stopire@gmail.com>
---
 tests/Makefile.am   |   3 +
 tests/erofs/032     | 135 ++++++++++++++++++++++++++++++++++++++++++++
 tests/erofs/032.out |   2 +
 3 files changed, 140 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 a1e31fb..3c41eb3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -132,6 +132,9 @@ TESTS += erofs/030
 # 031 - test chunk-based inodes
 TESTS += erofs/031
 
+# 032 - regression test for buffered reads across device chunks
+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..416ff5e
--- /dev/null
+++ b/tests/erofs/032
@@ -0,0 +1,135 @@
+#!/bin/sh
+# SPDX-License-Identifier: MIT
+#
+# Regression test for buffered reads crossing EROFS device chunks.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$(echo $0 | awk '{print $((NF-1))"/"$NF}' FS="/")
+
+# get standard environment, filters and checks
+. "${srcdir}/common/rc"
+
+cleanup()
+{
+	[ -n "$mnt" ] && $UMOUNT_PROG "$mnt" 2>/dev/null
+
+	for dev in "$meta_loop" "$dev1_loop" "$dev2_loop" "$dev3_loop"; do
+		[ -n "$dev" ] && losetup -d "$dev" 2>/dev/null
+	done
+
+	rm -rf $tmp.*
+}
+
+_require_root
+[ "$FSTYP" = "erofsfuse" ] && _notrun "kernel EROFS is required"
+_require_erofs
+which losetup >/dev/null 2>&1 || _notrun "losetup is not found"
+which blockdev >/dev/null 2>&1 || _notrun "blockdev is not found"
+[ -w /proc/sys/vm/drop_caches ] || _notrun "drop_caches is not writable"
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+echo "QA output created by $seq"
+
+chunk=4096
+localdir="$tmp/$seq"
+src="$localdir/src"
+mnt="$localdir/mnt"
+img="$localdir/merged.erofs"
+blob="$localdir/blob.bin"
+dev1="$localdir/device1.bin"
+dev2="$localdir/device2.bin"
+dev3="$localdir/device3.bin"
+expected="$localdir/expected.bin"
+affected="$localdir/affected.bin"
+actual="$localdir/actual.bin"
+
+mkdir -p "$src" "$mnt" || _fail "failed to create test directories"
+
+emit_byte()
+{
+	dd if=/dev/zero bs="$1" count=1 2>/dev/null | tr '\000' "$2"
+}
+
+write_at()
+{
+	printf '%b' "$1" | dd of="$2" bs=1 seek="$3" conv=notrunc \
+		>>$seqres.full 2>&1 || _fail "failed to patch image"
+}
+
+setup_loop()
+{
+	loopdev=`losetup -f 2>/dev/null` || _notrun "no free loop device"
+	losetup "$loopdev" "$1" >>$seqres.full 2>&1 || \
+		_fail "failed to setup loop device"
+}
+
+emit_byte $chunk X > "$src/mem.bin" || _fail "failed to create source file"
+emit_byte $chunk Y >> "$src/mem.bin" || _fail "failed to create source file"
+emit_byte $chunk Z >> "$src/mem.bin" || _fail "failed to create source file"
+
+emit_byte $((chunk * 3)) A > "$dev1" || _fail "failed to create device 1"
+emit_byte $chunk P > "$dev2" || _fail "failed to create device 2"
+emit_byte $((chunk * 2)) B >> "$dev2" || _fail "failed to create device 2"
+emit_byte $((chunk * 2)) P > "$dev3" || _fail "failed to create device 3"
+emit_byte $chunk C >> "$dev3" || _fail "failed to create device 3"
+
+emit_byte $chunk A > "$expected" || _fail "failed to create expected output"
+emit_byte $chunk B >> "$expected" || _fail "failed to create expected output"
+emit_byte $chunk C >> "$expected" || _fail "failed to create expected output"
+
+emit_byte $((chunk * 3)) A > "$affected" || _fail "failed to create affected output"
+
+"$MKFS_EROFS_PROG" -T0 -Eforce-inode-compact,nosbcrc --chunksize=$chunk \
+	--blobdev="$blob" "$img" "$src" >>$seqres.full 2>&1 || \
+	_fail "failed to create chunk-based image"
+
+# Convert mkfs' single blob-device image into three blob devices whose chunk
+# block addresses are contiguous.  A buggy kernel can merge the buffered read
+# bios across those iomap/device boundaries and read A/A/A instead of A/B/C.
+write_at '\003\000' "$img" $((1024 + 86))
+write_at '\030\000' "$img" $((1024 + 88))
+write_at '\000\000\001\000\000\000\000\000' "$img" 1408
+write_at '\000\000\002\000\001\000\000\000' "$img" 1416
+write_at '\000\000\003\000\002\000\000\000' "$img" 1424
+dd if=/dev/zero of="$img" bs=128 count=3 seek=24 conv=notrunc \
+	>>$seqres.full 2>&1 || _fail "failed to patch device table"
+write_at '\003\000\000\000' "$img" $((3072 + 64))
+write_at '\003\000\000\000' "$img" $((3072 + 128 + 64))
+write_at '\003\000\000\000' "$img" $((3072 + 256 + 64))
+
+setup_loop "$img"
+meta_loop="$loopdev"
+setup_loop "$dev1"
+dev1_loop="$loopdev"
+setup_loop "$dev2"
+dev2_loop="$loopdev"
+setup_loop "$dev3"
+dev3_loop="$loopdev"
+
+$MOUNT_PROG -t erofs \
+	-o device=$dev1_loop,device=$dev2_loop,device=$dev3_loop \
+	"$meta_loop" "$mnt" >>$seqres.full 2>&1 || \
+	_notrun "this test requires EROFS multiple device support"
+
+for dev in "$meta_loop" "$dev1_loop" "$dev2_loop" "$dev3_loop"; do
+	blockdev --setra 5120 "$dev" >>$seqres.full 2>&1 || \
+		_fail "failed to set readahead"
+done
+
+sync
+echo 3 > /proc/sys/vm/drop_caches || _notrun "failed to drop page cache"
+
+cat "$mnt/mem.bin" > "$actual" || _fail "failed to read mem.bin"
+
+if cmp -s "$actual" "$affected"; then
+	_fail "buffered read merged across device chunks"
+fi
+
+cmp -s "$actual" "$expected" || _fail "unexpected data from device chunks"
+
+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.54.0



  reply	other threads:[~2026-06-26  2:51 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-26  2:50 [PATCH 1/2] erofs-utils: tests: register chunk-based inode test Yifan Zhao
2026-06-26  2:50 ` Yifan Zhao [this message]
2026-06-26  3:07 ` Gao Xiang

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=20260626025025.805563-2-stopire@gmail.com \
    --to=stopire@gmail.com \
    --cc=linux-erofs@lists.ozlabs.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