diff mbox series

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

Message ID 163045514640.771394.1779112875987604476.stgit@magnolia (mailing list archive)
State New, archived
Headers show
Series fstests: exercise code changes in 5.15 | expand

Commit Message

Darrick J. Wong Sept. 1, 2021, 12:12 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

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@kernel.org>
---
 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

Comments

Eryu Guan Sept. 12, 2021, 10:41 a.m. UTC | #1
On Tue, Aug 31, 2021 at 05:12:26PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> 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@kernel.org>
> ---
>  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

_supported_fs xfs

> +_require_test

Also need the following _require rules

_require_loop
_require_xfs_io_command "falloc"
_require_xfs_io_command "fpunch"
_require_xfs_io_command "fsmap"

I've fixed them all on commit.

Thanks,
Eryu
Darrick J. Wong Sept. 13, 2021, 6:26 p.m. UTC | #2
On Sun, Sep 12, 2021 at 06:41:22PM +0800, Eryu Guan wrote:
> On Tue, Aug 31, 2021 at 05:12:26PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > 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@kernel.org>
> > ---
> >  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
> 
> _supported_fs xfs
> 
> > +_require_test
> 
> Also need the following _require rules
> 
> _require_loop
> _require_xfs_io_command "falloc"
> _require_xfs_io_command "fpunch"
> _require_xfs_io_command "fsmap"
> 
> I've fixed them all on commit.

Thank you!

--D

> 
> Thanks,
> Eryu
diff mbox series

Patch

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