All of 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.