[PATCH 4/4] xfs: regresion test for fsmap problems with realtime

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]



From: Darrick J. Wong <djwong@xxxxxxxxxx>

This is a regression test for:

xfs: make xfs_rtalloc_query_range input parameters const
xfs: fix off-by-one error when the last rt extent is in use
xfs: make fsmap backend function key parameters const

In which we synthesize an XFS with a realtime volume and a special
realtime volume to trip the bugs fixed by all three patches that
resulted in incomplete fsmap output.

Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
---
 tests/xfs/922     |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/922.out |    2 +
 2 files changed, 185 insertions(+)
 create mode 100755 tests/xfs/922
 create mode 100644 tests/xfs/922.out


diff --git a/tests/xfs/922 b/tests/xfs/922
new file mode 100755
index 00000000..95304d57
--- /dev/null
+++ b/tests/xfs/922
@@ -0,0 +1,183 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021 Oracle.  All Rights Reserved.
+#
+# FS QA Test 922
+#
+# Regression test for commits:
+#
+# c02f6529864a ("xfs: make xfs_rtalloc_query_range input parameters const")
+# 9ab72f222774 ("xfs: fix off-by-one error when the last rt extent is in use")
+# 7e1826e05ba6 ("xfs: make fsmap backend function key parameters const")
+#
+# These commits fix a bug in fsmap where the data device fsmap function would
+# corrupt the high key passed to the rt fsmap function if the data device
+# number is smaller than the rt device number and the data device itself is
+# smaller than the rt device.
+#
+. ./common/preamble
+_begin_fstest auto fsmap
+
+_cleanup()
+{
+	cd /
+	rm -r -f $tmp.*
+	_scratch_unmount
+	test -n "$ddloop" && _destroy_loop_device "$ddloop"
+	test -n "$rtloop" && _destroy_loop_device "$rtloop"
+	test -n "$ddfile" && rm -f "$ddfile"
+	test -n "$rtfile" && rm -f "$rtfile"
+	test -n "$old_use_external" && USE_EXTERNAL="$old_use_external"
+}
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs generic
+_require_test
+
+# Synthesize data and rt volumes that as needed to trigger the bug
+ddfile=$TEST_DIR/data
+rtfile=$TEST_DIR/rt
+rm -f "$rtfile" "$ddfile"
+
+ddsize="$((100 * 1048576))"
+rtsize="$((200 * 1048576))"
+
+truncate -s $ddsize $ddfile
+truncate -s $rtsize $rtfile
+ddloop="$(_create_loop_device $ddfile)"
+rtloop="$(_create_loop_device $rtfile)"
+
+test -z "$ddloop" && _fail "Could not create data loop device"
+test -z "$rtloop" && _fail "Could not create rt loop device"
+
+# dataloop must have a smaller device number than rtloop because fsmap sorts
+# the output by device number
+ddmajor=$(stat -c '%t' "$ddloop")
+rtmajor=$(stat -c '%t' "$rtloop")
+test $ddmajor -le $rtmajor || \
+	_notrun "Data loopdev major $ddmajor larger than rt major $rtmajor"
+
+ddminor=$(stat -c '%T' "$ddloop")
+rtminor=$(stat -c '%T' "$rtloop")
+test $ddmajor -le $rtmajor || \
+	_notrun "Data loopdev minor $ddminor larger than rt minor $rtminor"
+
+# Inject our custom-built devices as an rt-capable scratch device.
+# We avoid touching "require_scratch" so that post-test fsck will not try to
+# run on our synthesized scratch device.
+old_use_external="$USE_EXTERNAL"
+USE_EXTERNAL=yes
+SCRATCH_RTDEV="$rtloop"
+SCRATCH_DEV="$ddloop"
+
+_scratch_mkfs >> $seqres.full
+_try_scratch_mount >> $seqres.full || \
+	_notrun "mount with injected rt device failed"
+
+# Create a file that we'll use to seed fsmap entries for the rt device,
+# and force the root directory to create only data device files
+rtfile="$SCRATCH_MNT/rtfile"
+$XFS_IO_PROG -R -f -c 'stat -v' $rtfile | grep -q 'fsxattr.*xflags.*realtime' || \
+	_notrun "could not create realtime file"
+$XFS_IO_PROG -c 'chattr -t' $SCRATCH_MNT
+rtextsize="$(stat -c '%o' $rtfile)"
+
+# Make sure the data device is smaller than the rt device by at least a few
+# realtime extents.
+ddbytes="$(stat -f -c '%S * %b' $SCRATCH_MNT | bc)"
+rtbytes="$(stat -f -c '%S * %b' $rtfile | bc)"
+
+test "$ddbytes" -lt "$((rtbytes + (10 * rtextsize) ))" || \
+	echo "data device ($ddbytes) has more bytes than rt ($rtbytes)"
+
+# Craft the layout of the sole realtime file in such a way that the only
+# allocated space on the realtime device is at a physical disk address that is
+# higher than the size of the data device.  For realtime files this is really
+# easy because fallocate for the first rt file always starts allocating at
+# physical offset zero.
+alloc_rtx="$((rtbytes / rtextsize))"
+$XFS_IO_PROG -c "falloc 0 $((alloc_rtx * rtextsize))" $rtfile
+
+expected_end="$(( (alloc_rtx * rtextsize - 1) / 512 ))"
+
+# Print extent mapping of rtfile in format:
+# file_offset file_end physical_offset physical_end
+rtfile_exts() {
+	$XFS_IO_PROG -c 'bmap -elp' $rtfile | \
+		egrep -v '(^/|EXT:|hole)' | \
+		tr ':.[]' '    ' | \
+		while read junk foff fend physoff physend junk; do
+			echo "$foff $fend $physoff $physend"
+		done
+}
+
+# Make sure that we actually got the entire device.
+rtfile_exts | awk -v end=$expected_end '
+{
+	if ($3 != 0)
+		printf("%s: unexpected physical offset %s, wanted 0\n", $0, $3);
+	if ($4 != end)
+		printf("%s: unexpected physical end %s, wanted %d\n", $0, $4, end);
+}'
+
+# Now punch out a range that is slightly larger than the size of the data
+# device.
+punch_bytes="$((ddsize + rtextsize))"
+punch_rtx="$((punch_bytes / rtextsize))"
+$XFS_IO_PROG -c "fpunch 0 $((punch_rtx * rtextsize))" $rtfile
+
+expected_offset="$((punch_rtx * rtextsize / 512))"
+
+echo "rtfile should have physical extent from $expected_offset to $expected_end sectors" >> $seqres.full
+
+# Make sure that the realtime file now has only one extent at the end of the
+# realtime device
+rtfile_exts | awk -v offset=$expected_offset -v end=$expected_end '
+{
+	if ($3 != offset)
+		printf("%s: unexpected physical offset %s, wanted %d\n", $0, $3, offset);
+	if ($4 != end)
+		printf("%s: unexpected physical end %s, wanted %d\n", $0, $4, end);
+}'
+
+$XFS_IO_PROG -c 'bmap -elpv' $rtfile >> $seqres.full
+$XFS_IO_PROG -c 'fsmap' $SCRATCH_MNT >> $seqres.full
+
+fsmap() {
+	$XFS_IO_PROG -c 'fsmap' $SCRATCH_MNT | \
+		grep -v 'EXT:' | \
+		tr ':.[]' '    ' | \
+		while read junk major minor physoff physend junk; do
+			echo "$major:$minor $physoff $physend"
+		done
+}
+
+# Check the fsmap output contains a record for the realtime device at a
+# physical offset higher than end of the data device and corresponding to the
+# beginning of the non-punched area.
+fsmap | awk -v dev="$rtmajor:$rtminor" -v offset=$expected_offset -v end=$expected_end '
+BEGIN {
+	found_start = 0;
+	found_end = 0;
+}
+{
+	if ($1 == dev && $2 >= offset) {
+		found_start = 1;
+		if ($3 == end) {
+			found_end = 1;
+		}
+	}
+}
+END {
+	if (found_start == 0)
+		printf("No fsmap record for rtdev %s above sector %d\n", dev, offset);
+	if (found_end == 0)
+		printf("No fsmap record for rtdev %s ending at sector %d\n", dev, end);
+}'
+
+echo Silence is golden
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/922.out b/tests/xfs/922.out
new file mode 100644
index 00000000..3f90539d
--- /dev/null
+++ b/tests/xfs/922.out
@@ -0,0 +1,2 @@
+QA output created by 922
+Silence is golden




[Index of Archives]     [Linux Filesystems Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux