fstests.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection
@ 2020-11-13 11:26 Chandan Babu R
  2020-11-13 11:26 ` [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count Chandan Babu R
                   ` (11 more replies)
  0 siblings, 12 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

The patchset at
https://lore.kernel.org/linux-xfs/20201103150642.2032284-1-chandanrlinux@gmail.com/T/#m90a8754df516bbd0c36830904a2e31c37983792c  
added support to XFS to detect inode extent count overflow when
performing various filesystem operations. The patchset also added
new error injection tags for,
1. Reducing maximum extent count to 10.
2. Allocating only single block sized extents.

The corresponding code for xfsprogs can be obtained from
https://lore.kernel.org/linux-xfs/20201104114900.172147-1-chandanrlinux@gmail.com/.

The patches posted along with this cover letter add tests to verify if
the in-kernel inode extent count overflow detection mechanism works
correctly.

These patches can also be obtained from
https://github.com/chandanr/xfsprogs-dev.git at branch
extent-overflow-tests.

Chandan Babu R (11):
  common/xfs: Add a helper to get an inode fork's extent count
  xfs: Check for extent overflow when trivally adding a new extent
  xfs: Check for extent overflow when trivally adding a new extent
  xfs: Check for extent overflow when punching a hole
  xfs: Check for extent overflow when adding/removing xattrs
  xfs: Check for extent overflow when adding/removing dir entries
  xfs: Check for extent overflow when writing to unwritten extent
  xfs: Check for extent overflow when moving extent from cow to data
    fork
  xfs: Check for extent overflow when remapping an extent
  xfs: Check for extent overflow when swapping extents
  xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled

 common/xfs        |  22 +++
 tests/xfs/522     | 214 +++++++++++++++++++++++++++
 tests/xfs/522.out |  24 ++++
 tests/xfs/523     | 176 +++++++++++++++++++++++
 tests/xfs/523.out |  18 +++
 tests/xfs/524     | 210 +++++++++++++++++++++++++++
 tests/xfs/524.out |  25 ++++
 tests/xfs/525     | 154 ++++++++++++++++++++
 tests/xfs/525.out |  16 +++
 tests/xfs/526     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/526.out |  47 ++++++
 tests/xfs/527     | 125 ++++++++++++++++
 tests/xfs/527.out |  13 ++
 tests/xfs/528     |  87 +++++++++++
 tests/xfs/528.out |   8 ++
 tests/xfs/529     |  86 +++++++++++
 tests/xfs/529.out |   8 ++
 tests/xfs/530     | 115 +++++++++++++++
 tests/xfs/530.out |  13 ++
 tests/xfs/531     |  85 +++++++++++
 tests/xfs/531.out |   6 +
 tests/xfs/group   |  10 ++
 22 files changed, 1822 insertions(+)
 create mode 100755 tests/xfs/522
 create mode 100644 tests/xfs/522.out
 create mode 100755 tests/xfs/523
 create mode 100644 tests/xfs/523.out
 create mode 100755 tests/xfs/524
 create mode 100644 tests/xfs/524.out
 create mode 100755 tests/xfs/525
 create mode 100644 tests/xfs/525.out
 create mode 100755 tests/xfs/526
 create mode 100644 tests/xfs/526.out
 create mode 100755 tests/xfs/527
 create mode 100644 tests/xfs/527.out
 create mode 100755 tests/xfs/528
 create mode 100644 tests/xfs/528.out
 create mode 100755 tests/xfs/529
 create mode 100644 tests/xfs/529.out
 create mode 100755 tests/xfs/530
 create mode 100644 tests/xfs/530.out
 create mode 100755 tests/xfs/531
 create mode 100644 tests/xfs/531.out

-- 
2.28.0


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:10   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent Chandan Babu R
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This commit adds the helper _scratch_get_iext_count() which returns an
inode fork's extent count.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 common/xfs | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/common/xfs b/common/xfs
index 79dab058..45cd329c 100644
--- a/common/xfs
+++ b/common/xfs
@@ -883,6 +883,28 @@ _scratch_get_bmx_prefix() {
 	return 1
 }
 
+_scratch_get_iext_count()
+{
+	ino=$1
+	whichfork=$2
+
+	case $whichfork in
+		"attr")
+			field=core.naextents
+			;;
+		"data")
+			field=core.nextents
+			;;
+		*)
+			return 1
+	esac
+
+	nextents=$(_scratch_xfs_db  -c "inode $ino" -c "print $field")
+	nextents=${nextents##${field} = }
+
+	echo $nextents
+}
+
 #
 # Ensures that we don't pass any mount options incompatible with XFS v4
 #
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
  2020-11-13 11:26 ` [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:24   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 03/11] " Chandan Babu R
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when adding a single extent while there's no possibility of
splitting an existing mapping (limited to non-realtime files).

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/522     | 214 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/522.out |  24 ++++++
 tests/xfs/group   |   1 +
 3 files changed, 239 insertions(+)
 create mode 100755 tests/xfs/522
 create mode 100644 tests/xfs/522.out

diff --git a/tests/xfs/522 b/tests/xfs/522
new file mode 100755
index 00000000..a54fe136
--- /dev/null
+++ b/tests/xfs/522
@@ -0,0 +1,214 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 522
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# adding a single extent while there's no possibility of splitting an existing
+# mapping (limited to non-realtime files).
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/quota
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_quota
+_require_xfs_debug
+_require_xfs_io_command "falloc"
+_require_xfs_io_error_injection "reduce_max_iextents"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+
+delalloc_to_written_extent()
+{
+	echo "* Delalloc to written extent conversion"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	nr_blks=$((15 * 2))
+
+	echo "Create fragmented file"
+	for i in $(seq 0 2 $((nr_blks - 1))); do
+		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			   _fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+falloc_unwritten_extent()
+{
+	echo "* Fallocate of unwritten extents"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	nr_blks=$((15 * 2))
+
+	echo "Fallocate fragmented file"
+	for i in $(seq 0 2 $((nr_blks - 1))); do
+		xfs_io -f -c "falloc $((i * bsize)) $bsize" $testfile >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			   _fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+quota_inode_extend()
+{
+	echo "* Extend quota inodes"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount -o uquota >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	nr_blks=20
+
+	# This is a rough calculation; It doesn't take block headers into
+	# consideration.
+	# gdb -batch vmlinux -ex 'print sizeof(struct xfs_disk_dquot)'
+	# $1 = 104
+	nr_quotas_per_block=$((bsize / 104))
+	nr_quotas=$((nr_quotas_per_block * nr_blks))
+
+	echo "Extend uquota file"
+	for i in $(seq 0 $nr_quotas); do
+		chown $i $testfile >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify uquota inode's extent count"
+	uquotino=$(_scratch_xfs_db -c sb -c "print uquotino")
+	uquotino=${uquotino##uquotino = }
+
+	nextents=$(_scratch_get_iext_count $uquotino data || \
+			   _fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+directio_write()
+{
+	echo "* Directio write"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	nr_blks=$((15 * 2))
+
+	echo "Create fragmented file via directio writes"
+	for i in $(seq 0 2 $((nr_blks - 1))); do
+		xfs_io -d -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			   _fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+delalloc_to_written_extent
+falloc_unwritten_extent
+quota_inode_extend
+directio_write
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/522.out b/tests/xfs/522.out
new file mode 100644
index 00000000..98791aae
--- /dev/null
+++ b/tests/xfs/522.out
@@ -0,0 +1,24 @@
+QA output created by 522
+* Delalloc to written extent conversion
+Format and mount fs
+Inject reduce_max_iextents error tag
+Create fragmented file
+Verify $testfile's extent count
+* Fallocate of unwritten extents
+Format and mount fs
+Inject reduce_max_iextents error tag
+Fallocate fragmented file
+Verify $testfile's extent count
+* Extend quota inodes
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Extend uquota file
+Verify uquota inode's extent count
+* Directio write
+Format and mount fs
+Inject reduce_max_iextents error tag
+Create fragmented file via directio writes
+Verify $testfile's extent count
diff --git a/tests/xfs/group b/tests/xfs/group
index b89c0a4e..1831f0b5 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -519,3 +519,4 @@
 519 auto quick reflink
 520 auto quick reflink
 521 auto quick realtime growfs
+522 auto quick quota
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
  2020-11-13 11:26 ` [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count Chandan Babu R
  2020-11-13 11:26 ` [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:18   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 04/11] xfs: Check for extent overflow when punching a hole Chandan Babu R
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

Verify that XFS does not cause inode fork's extent count to overflow
when adding a single extent while there's no possibility of splitting an
existing mapping (limited to realtime files only).

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/523     | 176 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/523.out |  18 +++++
 tests/xfs/group   |   1 +
 3 files changed, 195 insertions(+)
 create mode 100755 tests/xfs/523
 create mode 100644 tests/xfs/523.out

diff --git a/tests/xfs/523 b/tests/xfs/523
new file mode 100755
index 00000000..4f5b3584
--- /dev/null
+++ b/tests/xfs/523
@@ -0,0 +1,176 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 523
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# adding a single extent while there's no possibility of splitting an existing
+# mapping (limited to realtime files only).
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	_scratch_unmount >> $seqres.full 2>&1
+	test -e "$rtdev" && losetup -d $rtdev >> $seqres.full 2>&1
+	rm -f $tmp.* $TEST_DIR/$seq.rtvol
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_test
+_require_xfs_debug
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "reduce_max_iextents"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+_require_scratch_nocheck
+
+grow_rtinodes()
+{
+	echo "* Test extending rt inodes"
+
+	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
+	. $tmp.mkfs
+
+	echo "Create fake rt volume"
+	nr_bitmap_blks=25
+	nr_bits=$((nr_bitmap_blks * dbsize * 8))
+	rtextsz=$dbsize
+	rtdevsz=$((nr_bits * rtextsz))
+	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
+	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
+
+	echo "Format and mount rt volume"
+	export USE_EXTERNAL=yes
+	export SCRATCH_RTDEV=$rtdev
+	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
+		      -r size=2M,extsize=${rtextsz} >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	echo "Grow realtime volume"
+	xfs_growfs -r $SCRATCH_MNT >> $seqres.full 2>&1
+	if [[ $? == 0 ]]; then
+		echo "Growfs succeeded; should have failed."
+		exit 1
+	fi
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify rbmino's and rsumino's extent count"
+	for rtino in rbmino rsumino; do
+		ino=$(_scratch_xfs_db -c sb -c "print $rtino")
+		ino=${ino##${rtino} = }
+		echo "$rtino = $ino" >> $seqres.full
+
+		nextents=$(_scratch_get_iext_count $ino data || \
+				_fail "Unable to obtain inode fork's extent count")
+		if (( $nextents > 10 )); then
+			echo "Extent count overflow check failed: nextents = $nextents"
+			exit 1
+		fi
+	done
+
+	echo "Check filesystem"
+	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
+
+	losetup -d $rtdev
+	rm -f $TEST_DIR/$seq.rtvol
+
+	export USE_EXTERNAL=""
+	export SCRATCH_RTDEV=""
+}
+
+rtfile_extend()
+{
+	echo "* Test extending an rt file"
+
+	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
+	. $tmp.mkfs
+
+	echo "Create fake rt volume"
+	nr_blks=$((15 * 2))
+	rtextsz=$dbsize
+	rtdevsz=$((2 * nr_blks * rtextsz))
+	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
+	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
+
+	echo "Format and mount rt volume"
+	export USE_EXTERNAL=yes
+	export SCRATCH_RTDEV=$rtdev
+	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
+		      -r size=$rtdevsz >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Create fragmented file on rt volume"
+	testfile=$SCRATCH_MNT/testfile
+	for i in $(seq 0 2 $((nr_blks - 1))); do
+		xfs_io -Rf -c "pwrite $((i * dbsize)) $dbsize" -c fsync \
+		       $testfile >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+
+	echo "Check filesystem"
+	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
+
+	losetup -d $rtdev
+	rm -f $TEST_DIR/$seq.rtvol
+
+	export USE_EXTERNAL=""
+	export SCRATCH_RTDEV=""
+}
+
+grow_rtinodes
+rtfile_extend
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/523.out b/tests/xfs/523.out
new file mode 100644
index 00000000..16b4e0ad
--- /dev/null
+++ b/tests/xfs/523.out
@@ -0,0 +1,18 @@
+QA output created by 523
+* Test extending rt inodes
+Create fake rt volume
+Format and mount rt volume
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Grow realtime volume
+Verify rbmino's and rsumino's extent count
+Check filesystem
+* Test extending an rt file
+Create fake rt volume
+Format and mount rt volume
+Inject reduce_max_iextents error tag
+Create fragmented file on rt volume
+Verify $testfile's extent count
+Check filesystem
diff --git a/tests/xfs/group b/tests/xfs/group
index 1831f0b5..018c70ef 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -520,3 +520,4 @@
 520 auto quick reflink
 521 auto quick realtime growfs
 522 auto quick quota
+523 auto quick realtime growfs
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/11] xfs: Check for extent overflow when punching a hole
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (2 preceding siblings ...)
  2020-11-13 11:26 ` [PATCH 03/11] " Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:28   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs Chandan Babu R
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when punching out an extent.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/524     | 210 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/524.out |  25 ++++++
 tests/xfs/group   |   1 +
 3 files changed, 236 insertions(+)
 create mode 100755 tests/xfs/524
 create mode 100644 tests/xfs/524.out

diff --git a/tests/xfs/524 b/tests/xfs/524
new file mode 100755
index 00000000..9e140c99
--- /dev/null
+++ b/tests/xfs/524
@@ -0,0 +1,210 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 524
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# punching out an extent.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_debug
+_require_xfs_io_command "finsert"
+_require_xfs_io_command "fcollapse"
+_require_xfs_io_command "fzero"
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "reduce_max_iextents"
+
+punch_range()
+{
+	echo "* Fpunch regular file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	nr_blks=30
+
+	echo "Create \$testfile"
+	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
+	       -c sync $testfile  >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "fpunch alternating blocks"
+	$here/src/punch-alternating $testfile >> $seqres.full 2>&1
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data ||
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+finsert_range()
+{
+	echo "* Finsert regular file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)	
+
+	nr_blks=30
+
+	echo "Create \$testfile"
+	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
+	       -c sync $testfile  >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Finsert at every other block offset"
+	for i in $(seq 1 2 $((nr_blks - 1))); do
+		xfs_io -f -c "finsert $((i * bsize)) $bsize" $testfile \
+		       >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = ${nextents}"
+		exit 1
+	fi
+}
+
+fcollapse_range()
+{
+	echo "* Fcollapse regular file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)	
+
+	nr_blks=30
+
+	echo "Create \$testfile"
+	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
+	       -c sync $testfile  >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Fcollapse at every other block offset"
+	for i in $(seq 1 $((nr_blks / 2 - 1))); do
+		xfs_io -f -c "fcollapse $((i * bsize)) $bsize" $testfile \
+		       >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = ${nextents}"
+		exit 1
+	fi
+}
+
+fzero_range()
+{
+	echo "* Fzero regular file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+	bsize=$(_get_block_size $SCRATCH_MNT)	
+
+	nr_blks=30
+
+	echo "Create \$testfile"
+	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
+	       -c sync $testfile  >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Fzero at every other block offset"
+	for i in $(seq 1 2 $((nr_blks - 1))); do
+		xfs_io -f -c "fzero $((i * bsize)) $bsize" $testfile \
+		       >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = ${nextents}"
+		exit 1
+	fi
+}
+
+punch_range
+finsert_range
+fcollapse_range
+fzero_range
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/524.out b/tests/xfs/524.out
new file mode 100644
index 00000000..58f7d7ae
--- /dev/null
+++ b/tests/xfs/524.out
@@ -0,0 +1,25 @@
+QA output created by 524
+* Fpunch regular file
+Format and mount fs
+Create $testfile
+Inject reduce_max_iextents error tag
+fpunch alternating blocks
+Verify $testfile's extent count
+* Finsert regular file
+Format and mount fs
+Create $testfile
+Inject reduce_max_iextents error tag
+Finsert at every other block offset
+Verify $testfile's extent count
+* Fcollapse regular file
+Format and mount fs
+Create $testfile
+Inject reduce_max_iextents error tag
+Fcollapse at every other block offset
+Verify $testfile's extent count
+* Fzero regular file
+Format and mount fs
+Create $testfile
+Inject reduce_max_iextents error tag
+Fzero at every other block offset
+Verify $testfile's extent count
diff --git a/tests/xfs/group b/tests/xfs/group
index 018c70ef..3fa38c36 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -521,3 +521,4 @@
 521 auto quick realtime growfs
 522 auto quick quota
 523 auto quick realtime growfs
+524 auto quick punch zero insert collapse
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (3 preceding siblings ...)
  2020-11-13 11:26 ` [PATCH 04/11] xfs: Check for extent overflow when punching a hole Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:34   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries Chandan Babu R
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when adding/removing xattrs.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/525     | 154 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/525.out |  16 +++++
 tests/xfs/group   |   1 +
 3 files changed, 171 insertions(+)
 create mode 100755 tests/xfs/525
 create mode 100644 tests/xfs/525.out

diff --git a/tests/xfs/525 b/tests/xfs/525
new file mode 100755
index 00000000..1d5d6e7c
--- /dev/null
+++ b/tests/xfs/525
@@ -0,0 +1,154 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 525
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# Adding/removing xattrs.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/attr
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_attrs
+_require_xfs_debug
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "reduce_max_iextents"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+
+attr_set()
+{
+	echo "* Set xattrs"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	echo "Create xattrs"
+
+	attr_len=$(uuidgen | wc -c)
+	nr_attrs=$((bsize * 20 / attr_len))
+	for i in $(seq 1 $nr_attrs); do
+		$SETFATTR_PROG -n "trusted.""$(uuidgen)" $testfile \
+			 >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify uquota inode's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino attr || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+		exit 1
+	fi
+}
+
+attr_remove()
+{
+	echo "* Remove xattrs"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	testino=$(stat -c "%i" $testfile)
+
+	naextents=0
+	last=""
+
+	attr_len=$(uuidgen | wc -c)
+	nr_attrs=$((bsize / attr_len))
+
+	echo "Create initial xattr extents"
+	while (( $naextents < 4 )); do
+		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+		for i in $(seq 1 $nr_attrs); do
+			last="trusted.""$(uuidgen)"
+			$SETFATTR_PROG -n $last $testfile
+		done
+
+		_scratch_unmount >> $seqres.full
+
+		naextents=$(_scratch_get_iext_count $testino attr || \
+				_fail "Unable to obtain inode fork's extent count")
+
+		_scratch_mount >> $seqres.full
+	done
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Remove xattr to trigger -EFBIG"
+	$SETFATTR_PROG -x "$last" $testfile >> $seqres.full 2>&1
+	if [[ $? == 0 ]]; then
+		echo "Xattr removal succeeded; Should have failed "
+		exit 1
+	fi
+}
+
+attr_set
+attr_remove
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/525.out b/tests/xfs/525.out
new file mode 100644
index 00000000..cc40e6e2
--- /dev/null
+++ b/tests/xfs/525.out
@@ -0,0 +1,16 @@
+QA output created by 525
+* Set xattrs
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Create xattrs
+Verify uquota inode's extent count
+* Remove xattrs
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Create initial xattr extents
+Inject reduce_max_iextents error tag
+Remove xattr to trigger -EFBIG
diff --git a/tests/xfs/group b/tests/xfs/group
index 3fa38c36..bd38aff0 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -522,3 +522,4 @@
 522 auto quick quota
 523 auto quick realtime growfs
 524 auto quick punch zero insert collapse
+525 auto quick attr
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (4 preceding siblings ...)
  2020-11-13 11:26 ` [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:37   ` Darrick J. Wong
  2020-11-13 11:26 ` [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent Chandan Babu R
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when adding/removing directory entries.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/526     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/526.out |  47 ++++++
 tests/xfs/group   |   1 +
 3 files changed, 408 insertions(+)
 create mode 100755 tests/xfs/526
 create mode 100644 tests/xfs/526.out

diff --git a/tests/xfs/526 b/tests/xfs/526
new file mode 100755
index 00000000..39cfbcf8
--- /dev/null
+++ b/tests/xfs/526
@@ -0,0 +1,360 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 526
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# adding/removing directory entries.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_debug
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "reduce_max_iextents"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+
+_scratch_mkfs_sized $((1024 * 1024 * 1024)) | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
+. $tmp.mkfs
+
+dir_entry_create()
+{
+	echo "* Create directory entries"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	echo "Create directory entries"
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dbsize * 20 / dent_len))
+	for i in $(seq 1 $nr_dents); do
+		touch $SCRATCH_MNT/$(uuidgen) >> $seqres.full 2>&1 || break
+	done
+
+	dirino=$(stat -c "%i" $SCRATCH_MNT)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify directory's extent count"
+
+	nextents=$(_scratch_get_iext_count $dirino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+dir_entry_rename_dst()
+{
+	echo "* Rename: Populate destination directory"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	dstdir=$SCRATCH_MNT/dstdir
+	mkdir $dstdir
+
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dirbsize * 20 / dent_len))
+
+	echo "Populate \$dstdir by mv-ing new directory entries"
+	for i in $(seq 1 $nr_dents); do
+		file=${SCRATCH_MNT}/$(uuidgen)
+		touch $file || break
+		mv $file $dstdir >> $seqres.full 2>&1 || break
+	done
+
+	dirino=$(stat -c "%i" $dstdir)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$dstdir's extent count"
+
+	nextents=$(_scratch_get_iext_count $dirino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+dir_entry_rename_src()
+{
+	echo "* Rename: Populate source directory and mv one entry to destination directory"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	srcdir=${SCRATCH_MNT}/srcdir
+	dstdir=${SCRATCH_MNT}/dstdir
+
+	mkdir $srcdir $dstdir
+
+	dirino=$(stat -c "%i" $srcdir)
+
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dirbsize / dent_len))
+	nextents=0
+	last=""
+
+	echo "Populate \$srcdir with atleast 4 extents"
+	while (( $nextents < 4 )); do
+		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+		for i in $(seq 1 $nr_dents); do
+			last=${srcdir}/$(uuidgen)
+			touch $last || break
+		done
+
+		_scratch_unmount >> $seqres.full
+
+		nextents=$(_scratch_get_iext_count $dirino data || \
+				_fail "Unable to obtain inode fork's extent count")
+
+		_scratch_mount >> $seqres.full
+	done
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Move an entry from \$srcdir to trigger -EFBIG"
+	mv $last $dstdir >> $seqres.full 2>&1
+	if [[ $? == 0 ]]; then
+		echo "Moving from \$srcdir to \$dstdir succeeded; Should have failed"
+	fi
+
+	_scratch_unmount >> $seqres.full
+}
+
+dir_entry_create_hard_links()
+{
+	echo "* Create multiple hard links to a single file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dirbsize * 20 / dent_len))
+
+	echo "Create multiple hardlinks"
+	for i in $(seq 1 $nr_dents); do
+		ln $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break
+	done
+
+	dirino=$(stat -c "%i" $SCRATCH_MNT)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify directory's extent count"
+
+	nextents=$(_scratch_get_iext_count $dirino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+dir_entry_create_symlinks()
+{
+	echo "* Create multiple symbolic links to a single file"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Inject bmap_alloc_minlen_extent error tag"
+	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dirbsize * 20 / dent_len))
+
+	echo "Create multiple symbolic links"
+	for i in $(seq 1 $nr_dents); do
+		ln -s $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break;
+	done
+
+	dirino=$(stat -c "%i" $SCRATCH_MNT)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify directory's extent count"
+
+	nextents=$(_scratch_get_iext_count $dirino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+dir_entry_remove()
+{
+	echo "* Populate a directory and remove one entry"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	testfile=$SCRATCH_MNT/testfile
+
+	echo "Consume free space"
+	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
+	sync
+
+	echo "Create fragmented filesystem"
+	$here/src/punch-alternating $testfile >> $seqres.full
+	sync
+
+	dirino=$(stat -c "%i" $SCRATCH_MNT)
+
+	dent_len=$(uuidgen | wc -c)
+	nr_dents=$((dirbsize / dent_len))
+	nextents=0
+	last=""
+
+	echo "Populate directory with atleast 4 extents"
+	while (( $nextents < 4 )); do
+		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+		for i in $(seq 1 $nr_dents); do
+			last=${SCRATCH_MNT}/$(uuidgen)
+			touch $last || break
+		done
+
+		_scratch_unmount >> $seqres.full
+
+		nextents=$(_scratch_get_iext_count $dirino data || \
+				_fail "Unable to obtain inode fork's extent count")
+
+		_scratch_mount >> $seqres.full
+	done
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+	echo "Remove an entry from directory to trigger -EFBIG"
+	rm $last >> $seqres.full 2>&1
+	if [[ $? == 0 ]]; then
+		echo "Removing file succeeded; Should have failed"
+	fi
+
+	_scratch_unmount >> $seqres.full
+}
+
+# Filesystems with directory block size greater than one FSB will not be tested,
+# since "7 (i.e. XFS_DA_NODE_MAXDEPTH + 1 data block + 1 free block) * 2 (fsb
+# count) = 14" is greater than the pseudo max extent count limit of 10.
+# Extending the pseudo max limit won't help either.  Consider the case where 1
+# FSB is 1k in size and 1 dir block is 64k in size (i.e. fsb count = 64). In
+# this case, the pseudo max limit has to be greater than 7 * 64 = 448 extents.
+if (( $dbsize != $dirbsize )); then
+	_notrun "FSB size ($dbsize) and directory block size ($dirbsize) do not match"
+fi
+
+dir_entry_create
+dir_entry_rename_dst
+dir_entry_rename_src
+dir_entry_create_hard_links
+dir_entry_create_symlinks
+dir_entry_remove
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/526.out b/tests/xfs/526.out
new file mode 100644
index 00000000..21f77cd8
--- /dev/null
+++ b/tests/xfs/526.out
@@ -0,0 +1,47 @@
+QA output created by 526
+* Create directory entries
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Create directory entries
+Verify directory's extent count
+* Rename: Populate destination directory
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Populate $dstdir by mv-ing new directory entries
+Verify $dstdir's extent count
+* Rename: Populate source directory and mv one entry to destination directory
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Populate $srcdir with atleast 4 extents
+Inject reduce_max_iextents error tag
+Move an entry from $srcdir to trigger -EFBIG
+* Create multiple hard links to a single file
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Create multiple hardlinks
+Verify directory's extent count
+* Create multiple symbolic links to a single file
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject reduce_max_iextents error tag
+Inject bmap_alloc_minlen_extent error tag
+Create multiple symbolic links
+Verify directory's extent count
+* Populate a directory and remove one entry
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Populate directory with atleast 4 extents
+Inject reduce_max_iextents error tag
+Remove an entry from directory to trigger -EFBIG
diff --git a/tests/xfs/group b/tests/xfs/group
index bd38aff0..d089797b 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -523,3 +523,4 @@
 523 auto quick realtime growfs
 524 auto quick punch zero insert collapse
 525 auto quick attr
+526 auto quick dir hardlink symlink
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (5 preceding siblings ...)
  2020-11-13 11:26 ` [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries Chandan Babu R
@ 2020-11-13 11:26 ` Chandan Babu R
  2020-11-14  0:39   ` Darrick J. Wong
  2020-11-13 11:27 ` [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork Chandan Babu R
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:26 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when writing to an unwritten extent.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/527     | 125 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/527.out |  13 +++++
 tests/xfs/group   |   1 +
 3 files changed, 139 insertions(+)
 create mode 100755 tests/xfs/527
 create mode 100644 tests/xfs/527.out

diff --git a/tests/xfs/527 b/tests/xfs/527
new file mode 100755
index 00000000..f040aee4
--- /dev/null
+++ b/tests/xfs/527
@@ -0,0 +1,125 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 527
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# writing to an unwritten extent.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_debug
+_require_xfs_io_command "falloc"
+_require_xfs_io_error_injection "reduce_max_iextents"
+
+buffered_write_to_unwritten_extent()
+{
+	echo "* Buffered write to unwritten extent"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	testfile=${SCRATCH_MNT}/testfile
+
+	nr_blks=15
+
+	echo "Fallocate $nr_blks blocks"
+	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
+
+	echo "Buffered write to every other block of fallocated space"
+	for i in $(seq 1 2 $((nr_blks - 1))); do
+		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile \
+		       >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+direct_write_to_unwritten_extent()
+{
+	echo "* Direct I/O write to unwritten extent"
+
+	echo "Format and mount fs"
+	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+	_scratch_mount >> $seqres.full
+
+	bsize=$(_get_block_size $SCRATCH_MNT)
+
+	testfile=${SCRATCH_MNT}/testfile
+
+	nr_blks=15
+
+	echo "Fallocate $nr_blks blocks"
+	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
+
+	echo "Inject reduce_max_iextents error tag"
+	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
+
+	echo "Direct I/O write to every other block of fallocated space"
+	for i in $(seq 1 2 $((nr_blks - 1))); do
+		xfs_io -f -d -c "pwrite $((i * bsize)) $bsize" $testfile \
+		       >> $seqres.full 2>&1
+		[[ $? != 0 ]] && break
+	done
+
+	testino=$(stat -c "%i" $testfile)
+
+	_scratch_unmount >> $seqres.full
+
+	echo "Verify \$testfile's extent count"
+
+	nextents=$(_scratch_get_iext_count $testino data || \
+			_fail "Unable to obtain inode fork's extent count")
+	if (( $nextents > 10 )); then
+		echo "Extent count overflow check failed: nextents = $nextents"
+	fi
+}
+
+buffered_write_to_unwritten_extent
+direct_write_to_unwritten_extent
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/527.out b/tests/xfs/527.out
new file mode 100644
index 00000000..6aa5e9ed
--- /dev/null
+++ b/tests/xfs/527.out
@@ -0,0 +1,13 @@
+QA output created by 527
+* Buffered write to unwritten extent
+Format and mount fs
+Fallocate 15 blocks
+Inject reduce_max_iextents error tag
+Buffered write to every other block of fallocated space
+Verify $testfile's extent count
+* Direct I/O write to unwritten extent
+Format and mount fs
+Fallocate 15 blocks
+Inject reduce_max_iextents error tag
+Direct I/O write to every other block of fallocated space
+Verify $testfile's extent count
diff --git a/tests/xfs/group b/tests/xfs/group
index d089797b..627813fe 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -524,3 +524,4 @@
 524 auto quick punch zero insert collapse
 525 auto quick attr
 526 auto quick dir hardlink symlink
+527 auto quick
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (6 preceding siblings ...)
  2020-11-13 11:26 ` [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent Chandan Babu R
@ 2020-11-13 11:27 ` Chandan Babu R
  2020-11-14  0:42   ` Darrick J. Wong
  2020-11-13 11:27 ` [PATCH 09/11] xfs: Check for extent overflow when remapping an extent Chandan Babu R
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:27 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when writing to a shared extent.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/528     | 87 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/528.out |  8 +++++
 tests/xfs/group   |  1 +
 3 files changed, 96 insertions(+)
 create mode 100755 tests/xfs/528
 create mode 100644 tests/xfs/528.out

diff --git a/tests/xfs/528 b/tests/xfs/528
new file mode 100755
index 00000000..0d39f05e
--- /dev/null
+++ b/tests/xfs/528
@@ -0,0 +1,87 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 528
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# writing to a shared extent.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/reflink
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_scratch_reflink
+_require_xfs_debug
+_require_xfs_io_command "reflink"
+_require_xfs_io_error_injection "reduce_max_iextents"
+
+echo "* Write to shared extent"
+
+echo "Format and mount fs"
+_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+_scratch_mount >> $seqres.full
+
+bsize=$(_get_block_size $SCRATCH_MNT)
+
+srcfile=${SCRATCH_MNT}/srcfile
+dstfile=${SCRATCH_MNT}/dstfile
+
+nr_blks=15
+
+echo "Create a \$srcfile having an extent of length $nr_blks blocks"
+xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
+       -c fsync $srcfile  >> $seqres.full
+
+echo "Share the extent with \$dstfile"
+xfs_io -f -c "reflink $srcfile" $dstfile >> $seqres.full
+
+echo "Inject reduce_max_iextents error tag"
+xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+echo "Buffered write to every other block of \$dstfile's shared extent"
+for i in $(seq 1 2 $((nr_blks - 1))); do
+	xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $dstfile \
+	       >> $seqres.full 2>&1
+	[[ $? != 0 ]] && break
+done
+
+ino=$(stat -c "%i" $dstfile)
+
+_scratch_unmount >> $seqres.full
+
+echo "Verify \$dstfile's extent count"
+
+nextents=$(_scratch_get_iext_count $ino data || \
+		_fail "Unable to obtain inode fork's extent count")
+if (( $nextents > 10 )); then
+	echo "Extent count overflow check failed: nextents = $nextents"
+fi
+
+# success, all done
+status=0
+exit
+ 
diff --git a/tests/xfs/528.out b/tests/xfs/528.out
new file mode 100644
index 00000000..8666488b
--- /dev/null
+++ b/tests/xfs/528.out
@@ -0,0 +1,8 @@
+QA output created by 528
+* Write to shared extent
+Format and mount fs
+Create a $srcfile having an extent of length 15 blocks
+Share the extent with $dstfile
+Inject reduce_max_iextents error tag
+Buffered write to every other block of $dstfile's shared extent
+Verify $dstfile's extent count
diff --git a/tests/xfs/group b/tests/xfs/group
index 627813fe..c85aac6b 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -525,3 +525,4 @@
 525 auto quick attr
 526 auto quick dir hardlink symlink
 527 auto quick
+528 auto quick reflink
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/11] xfs: Check for extent overflow when remapping an extent
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (7 preceding siblings ...)
  2020-11-13 11:27 ` [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork Chandan Babu R
@ 2020-11-13 11:27 ` Chandan Babu R
  2020-11-14  0:43   ` Darrick J. Wong
  2020-11-13 11:27 ` [PATCH 10/11] xfs: Check for extent overflow when swapping extents Chandan Babu R
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:27 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when remapping extents from one file's inode fork to another.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/529     | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/529.out |  8 +++++
 tests/xfs/group   |  1 +
 3 files changed, 95 insertions(+)
 create mode 100755 tests/xfs/529
 create mode 100644 tests/xfs/529.out

diff --git a/tests/xfs/529 b/tests/xfs/529
new file mode 100755
index 00000000..a44ce199
--- /dev/null
+++ b/tests/xfs/529
@@ -0,0 +1,86 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 529
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# remapping extents from one file's inode fork to another.
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/reflink
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_scratch_reflink
+_require_xfs_debug
+_require_xfs_io_command "reflink"
+_require_xfs_io_error_injection "reduce_max_iextents"
+
+echo "* Reflink remap extents"
+
+echo "Format and mount fs"
+_scratch_mkfs >> $seqres.full
+_scratch_mount >> $seqres.full
+
+bsize=$(_get_block_size $SCRATCH_MNT)
+
+srcfile=${SCRATCH_MNT}/srcfile
+dstfile=${SCRATCH_MNT}/dstfile
+
+nr_blks=15
+
+echo "Create \$srcfile having an extent of length $nr_blks blocks"
+xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
+       -c fsync $srcfile >> $seqres.full
+
+echo "Create \$dstfile having an extent of length $nr_blks blocks"
+xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
+       -c fsync $dstfile >> $seqres.full
+
+echo "Inject reduce_max_iextents error tag"
+xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+echo "Reflink every other block from \$srcfile into \$dstfile"
+for i in $(seq 1 2 $((nr_blks - 1))); do
+	xfs_io -f -c "reflink $srcfile $((i * bsize)) $((i * bsize)) $bsize" \
+	       $dstfile >> $seqres.full 2>&1
+done
+
+ino=$(stat -c "%i" $dstfile)
+
+_scratch_unmount >> $seqres.full
+
+echo "Verify \$dstfile's extent count"
+
+nextents=$(_scratch_get_iext_count $ino data ||
+		_fail "Unable to obtain inode fork's extent count")
+if (( $nextents > 10 )); then
+	echo "Extent count overflow check failed: nextents = $nextents"
+fi
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/529.out b/tests/xfs/529.out
new file mode 100644
index 00000000..687a8bd2
--- /dev/null
+++ b/tests/xfs/529.out
@@ -0,0 +1,8 @@
+QA output created by 529
+* Reflink remap extents
+Format and mount fs
+Create $srcfile having an extent of length 15 blocks
+Create $dstfile having an extent of length 15 blocks
+Inject reduce_max_iextents error tag
+Reflink every other block from $srcfile into $dstfile
+Verify $dstfile's extent count
diff --git a/tests/xfs/group b/tests/xfs/group
index c85aac6b..bc3958b3 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -526,3 +526,4 @@
 526 auto quick dir hardlink symlink
 527 auto quick
 528 auto quick reflink
+529 auto quick reflink
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/11] xfs: Check for extent overflow when swapping extents
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (8 preceding siblings ...)
  2020-11-13 11:27 ` [PATCH 09/11] xfs: Check for extent overflow when remapping an extent Chandan Babu R
@ 2020-11-13 11:27 ` Chandan Babu R
  2020-11-14  0:08   ` Darrick J. Wong
  2020-11-13 11:27 ` [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled Chandan Babu R
  2020-11-13 11:29 ` [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:27 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This test verifies that XFS does not cause inode fork's extent count to
overflow when swapping forks across two files.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/530     | 115 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/530.out |  13 ++++++
 tests/xfs/group   |   1 +
 3 files changed, 129 insertions(+)
 create mode 100755 tests/xfs/530
 create mode 100644 tests/xfs/530.out

diff --git a/tests/xfs/530 b/tests/xfs/530
new file mode 100755
index 00000000..fccc6de7
--- /dev/null
+++ b/tests/xfs/530
@@ -0,0 +1,115 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 530
+#
+# Verify that XFS does not cause inode fork's extent count to overflow when
+# swapping forks between files
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_debug
+_require_xfs_scratch_rmapbt
+_require_xfs_io_command "fcollapse"
+_require_xfs_io_command "swapext"
+_require_xfs_io_error_injection "reduce_max_iextents"
+
+echo "* Swap extent forks"
+
+echo "Format and mount fs"
+_scratch_mkfs >> $seqres.full
+_scratch_mount >> $seqres.full
+
+bsize=$(_get_block_size $SCRATCH_MNT)
+
+srcfile=${SCRATCH_MNT}/srcfile
+donorfile=${SCRATCH_MNT}/donorfile
+
+echo "Create \$donorfile having an extent of length 17 blocks"
+xfs_io -f -c "pwrite -b $((17 * bsize)) 0 $((17 * bsize))" -c fsync $donorfile \
+       >> $seqres.full
+
+# After the for loop the donor file will have the following extent layout
+# | 0-4 | 5 | 6 | 7 | 8 | 9 | 10 |
+echo "Fragment \$donorfile"
+for i in $(seq 5 10); do
+	start_offset=$((i * bsize))
+	xfs_io -f -c "fcollapse $start_offset $bsize" $donorfile >> $seqres.full
+done
+donorino=$(stat -c "%i" $donorfile)
+
+echo "Create \$srcfile having an extent of length 18 blocks"
+xfs_io -f -c "pwrite -b $((18 * bsize)) 0 $((18 * bsize))" -c fsync $srcfile \
+       >> $seqres.full
+
+echo "Fragment \$srcfile"
+# After the for loop the src file will have the following extent layout
+# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7-10 |
+for i in $(seq 1 7); do
+	start_offset=$((i * bsize))
+	xfs_io -f -c "fcollapse $start_offset $bsize" $srcfile >> $seqres.full
+done
+srcino=$(stat -c "%i" $srcfile)
+
+_scratch_unmount >> $seqres.full
+
+echo "Collect \$donorfile's extent count"
+donor_nr_exts=$(_scratch_get_iext_count $donorino data || \
+		_fail "Unable to obtain inode fork's extent count")
+
+echo "Collect \$srcfile's extent count"
+src_nr_exts=$(_scratch_get_iext_count $srcino data || \
+		_fail "Unable to obtain inode fork's extent count")
+
+_scratch_mount >> $seqres.full
+
+echo "Inject reduce_max_iextents error tag"
+xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
+
+echo "Swap \$srcfile's and \$donorfile's extent forks"
+xfs_io -f -c "swapext $donorfile" $srcfile >> $seqres.full 2>&1
+
+_scratch_unmount >> $seqres.full
+
+echo "Check for \$donorfile's extent count overflow"
+nextents=$(_scratch_get_iext_count $donorino data || \
+		_fail "Unable to obtain inode fork's extent count")
+if (( $nextents == $src_nr_exts )); then
+	echo "\$donorfile: Extent count overflow check failed"
+fi
+
+echo "Check for \$srcfile's extent count overflow"
+nextents=$(_scratch_get_iext_count $srcino data || \
+		_fail "Unable to obtain inode fork's extent count")
+if (( $nextents == $donor_nr_exts )); then
+	echo "\$srcfile: Extent count overflow check failed"
+fi
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/530.out b/tests/xfs/530.out
new file mode 100644
index 00000000..996af959
--- /dev/null
+++ b/tests/xfs/530.out
@@ -0,0 +1,13 @@
+QA output created by 530
+* Swap extent forks
+Format and mount fs
+Create $donorfile having an extent of length 17 blocks
+Fragment $donorfile
+Create $srcfile having an extent of length 18 blocks
+Fragment $srcfile
+Collect $donorfile's extent count
+Collect $srcfile's extent count
+Inject reduce_max_iextents error tag
+Swap $srcfile's and $donorfile's extent forks
+Check for $donorfile's extent count overflow
+Check for $srcfile's extent count overflow
diff --git a/tests/xfs/group b/tests/xfs/group
index bc3958b3..81a15582 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -527,3 +527,4 @@
 527 auto quick
 528 auto quick reflink
 529 auto quick reflink
+530 auto quick
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (9 preceding siblings ...)
  2020-11-13 11:27 ` [PATCH 10/11] xfs: Check for extent overflow when swapping extents Chandan Babu R
@ 2020-11-13 11:27 ` Chandan Babu R
  2020-11-14  0:06   ` Darrick J. Wong
  2020-11-13 11:29 ` [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
  11 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:27 UTC (permalink / raw)
  To: fstests; +Cc: Chandan Babu R, linux-xfs, darrick.wong

This commit adds a stress test that executes fsstress with
bmap_alloc_minlen_extent error tag enabled.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 tests/xfs/531     | 85 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/xfs/531.out |  6 ++++
 tests/xfs/group   |  1 +
 3 files changed, 92 insertions(+)
 create mode 100755 tests/xfs/531
 create mode 100644 tests/xfs/531.out

diff --git a/tests/xfs/531 b/tests/xfs/531
new file mode 100755
index 00000000..e846cc0e
--- /dev/null
+++ b/tests/xfs/531
@@ -0,0 +1,85 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
+#
+# FS QA Test 531
+#
+# Execute fsstress with bmap_alloc_minlen_extent error tag enabled.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/inject
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+_supported_fs xfs
+_require_scratch
+_require_xfs_debug
+_require_test_program "punch-alternating"
+_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
+
+echo "Format and mount fs"
+_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
+_scratch_mount >> $seqres.full
+
+bsize=$(_get_block_size $SCRATCH_MNT)
+
+testfile=$SCRATCH_MNT/testfile
+
+echo "Consume free space"
+dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
+sync
+
+echo "Create fragmented filesystem"
+$here/src/punch-alternating $testfile >> $seqres.full
+sync
+
+echo "Inject bmap_alloc_minlen_extent error tag"
+xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
+
+echo "Execute fsstress in background"
+$FSSTRESS_PROG -d $SCRATCH_MNT -p128 -n999999999 \
+		 -f bulkstat=0 \
+		 -f bulkstat1=0 \
+		 -f fiemap=0 \
+		 -f getattr=0 \
+		 -f getdents=0 \
+		 -f getfattr=0 \
+		 -f listfattr=0 \
+		 -f mread=0 \
+		 -f read=0 \
+		 -f readlink=0 \
+		 -f readv=0 \
+		 -f stat=0 \
+		 -f aread=0 \
+		 -f dread=0 > /dev/null 2>&1 &
+
+fsstress_pid=$!
+sleep 2m
+
+echo "Killing fsstress process $fsstress_pid ..." >> $seqres.full
+kill $fsstress_pid >> $seqres.full
+wait $fsstress_pid
+
+# success, all done
+status=0
+exit
diff --git a/tests/xfs/531.out b/tests/xfs/531.out
new file mode 100644
index 00000000..e0a419c2
--- /dev/null
+++ b/tests/xfs/531.out
@@ -0,0 +1,6 @@
+QA output created by 531
+Format and mount fs
+Consume free space
+Create fragmented filesystem
+Inject bmap_alloc_minlen_extent error tag
+Execute fsstress in background
diff --git a/tests/xfs/group b/tests/xfs/group
index 81a15582..f4cb5af6 100644
--- a/tests/xfs/group
+++ b/tests/xfs/group
@@ -528,3 +528,4 @@
 528 auto quick reflink
 529 auto quick reflink
 530 auto quick
+531 auto stress
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection
  2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
                   ` (10 preceding siblings ...)
  2020-11-13 11:27 ` [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled Chandan Babu R
@ 2020-11-13 11:29 ` Chandan Babu R
  11 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-13 11:29 UTC (permalink / raw)
  To: fstests; +Cc: linux-xfs, darrick.wong

On Friday 13 November 2020 4:56:52 PM IST Chandan Babu R wrote:
> The patchset at
> https://lore.kernel.org/linux-xfs/20201103150642.2032284-1-chandanrlinux@gmail.com/T/#m90a8754df516bbd0c36830904a2e31c37983792c  
> added support to XFS to detect inode extent count overflow when
> performing various filesystem operations. The patchset also added
> new error injection tags for,
> 1. Reducing maximum extent count to 10.
> 2. Allocating only single block sized extents.
> 
> The corresponding code for xfsprogs can be obtained from
> https://lore.kernel.org/linux-xfs/20201104114900.172147-1-chandanrlinux@gmail.com/.
> 
> The patches posted along with this cover letter add tests to verify if
> the in-kernel inode extent count overflow detection mechanism works
> correctly.
> 
> These patches can also be obtained from
> https://github.com/chandanr/xfsprogs-dev.git at branch
> extent-overflow-tests.

Sorry, the correct git repository URL is
https://github.com/chandanr/xfstests.git.

> 
> Chandan Babu R (11):
>   common/xfs: Add a helper to get an inode fork's extent count
>   xfs: Check for extent overflow when trivally adding a new extent
>   xfs: Check for extent overflow when trivally adding a new extent
>   xfs: Check for extent overflow when punching a hole
>   xfs: Check for extent overflow when adding/removing xattrs
>   xfs: Check for extent overflow when adding/removing dir entries
>   xfs: Check for extent overflow when writing to unwritten extent
>   xfs: Check for extent overflow when moving extent from cow to data
>     fork
>   xfs: Check for extent overflow when remapping an extent
>   xfs: Check for extent overflow when swapping extents
>   xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled
> 
>  common/xfs        |  22 +++
>  tests/xfs/522     | 214 +++++++++++++++++++++++++++
>  tests/xfs/522.out |  24 ++++
>  tests/xfs/523     | 176 +++++++++++++++++++++++
>  tests/xfs/523.out |  18 +++
>  tests/xfs/524     | 210 +++++++++++++++++++++++++++
>  tests/xfs/524.out |  25 ++++
>  tests/xfs/525     | 154 ++++++++++++++++++++
>  tests/xfs/525.out |  16 +++
>  tests/xfs/526     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/526.out |  47 ++++++
>  tests/xfs/527     | 125 ++++++++++++++++
>  tests/xfs/527.out |  13 ++
>  tests/xfs/528     |  87 +++++++++++
>  tests/xfs/528.out |   8 ++
>  tests/xfs/529     |  86 +++++++++++
>  tests/xfs/529.out |   8 ++
>  tests/xfs/530     | 115 +++++++++++++++
>  tests/xfs/530.out |  13 ++
>  tests/xfs/531     |  85 +++++++++++
>  tests/xfs/531.out |   6 +
>  tests/xfs/group   |  10 ++
>  22 files changed, 1822 insertions(+)
>  create mode 100755 tests/xfs/522
>  create mode 100644 tests/xfs/522.out
>  create mode 100755 tests/xfs/523
>  create mode 100644 tests/xfs/523.out
>  create mode 100755 tests/xfs/524
>  create mode 100644 tests/xfs/524.out
>  create mode 100755 tests/xfs/525
>  create mode 100644 tests/xfs/525.out
>  create mode 100755 tests/xfs/526
>  create mode 100644 tests/xfs/526.out
>  create mode 100755 tests/xfs/527
>  create mode 100644 tests/xfs/527.out
>  create mode 100755 tests/xfs/528
>  create mode 100644 tests/xfs/528.out
>  create mode 100755 tests/xfs/529
>  create mode 100644 tests/xfs/529.out
>  create mode 100755 tests/xfs/530
>  create mode 100644 tests/xfs/530.out
>  create mode 100755 tests/xfs/531
>  create mode 100644 tests/xfs/531.out
> 
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled
  2020-11-13 11:27 ` [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled Chandan Babu R
@ 2020-11-14  0:06   ` Darrick J. Wong
  2020-11-17 15:24     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:06 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:57:03PM +0530, Chandan Babu R wrote:
> This commit adds a stress test that executes fsstress with
> bmap_alloc_minlen_extent error tag enabled.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/531     | 85 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/531.out |  6 ++++
>  tests/xfs/group   |  1 +
>  3 files changed, 92 insertions(+)
>  create mode 100755 tests/xfs/531
>  create mode 100644 tests/xfs/531.out
> 
> diff --git a/tests/xfs/531 b/tests/xfs/531
> new file mode 100755
> index 00000000..e846cc0e
> --- /dev/null
> +++ b/tests/xfs/531
> @@ -0,0 +1,85 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 531
> +#
> +# Execute fsstress with bmap_alloc_minlen_extent error tag enabled.
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_debug
> +_require_test_program "punch-alternating"
> +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> +
> +echo "Format and mount fs"
> +_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full

Why is a 1G fs required?

> +_scratch_mount >> $seqres.full
> +
> +bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +testfile=$SCRATCH_MNT/testfile
> +
> +echo "Consume free space"
> +dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> +sync
> +
> +echo "Create fragmented filesystem"
> +$here/src/punch-alternating $testfile >> $seqres.full
> +sync
> +
> +echo "Inject bmap_alloc_minlen_extent error tag"
> +xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +echo "Execute fsstress in background"
> +$FSSTRESS_PROG -d $SCRATCH_MNT -p128 -n999999999 \

-n and -p ought to be computed from TIME_FACTOR and LOAD_FACTOR.

--D

> +		 -f bulkstat=0 \
> +		 -f bulkstat1=0 \
> +		 -f fiemap=0 \
> +		 -f getattr=0 \
> +		 -f getdents=0 \
> +		 -f getfattr=0 \
> +		 -f listfattr=0 \
> +		 -f mread=0 \
> +		 -f read=0 \
> +		 -f readlink=0 \
> +		 -f readv=0 \
> +		 -f stat=0 \
> +		 -f aread=0 \
> +		 -f dread=0 > /dev/null 2>&1 &
> +
> +fsstress_pid=$!
> +sleep 2m
> +
> +echo "Killing fsstress process $fsstress_pid ..." >> $seqres.full
> +kill $fsstress_pid >> $seqres.full
> +wait $fsstress_pid
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/531.out b/tests/xfs/531.out
> new file mode 100644
> index 00000000..e0a419c2
> --- /dev/null
> +++ b/tests/xfs/531.out
> @@ -0,0 +1,6 @@
> +QA output created by 531
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject bmap_alloc_minlen_extent error tag
> +Execute fsstress in background
> diff --git a/tests/xfs/group b/tests/xfs/group
> index 81a15582..f4cb5af6 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -528,3 +528,4 @@
>  528 auto quick reflink
>  529 auto quick reflink
>  530 auto quick
> +531 auto stress
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 10/11] xfs: Check for extent overflow when swapping extents
  2020-11-13 11:27 ` [PATCH 10/11] xfs: Check for extent overflow when swapping extents Chandan Babu R
@ 2020-11-14  0:08   ` Darrick J. Wong
  2020-11-17 15:35     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:08 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:57:02PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when swapping forks across two files.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/530     | 115 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/530.out |  13 ++++++
>  tests/xfs/group   |   1 +
>  3 files changed, 129 insertions(+)
>  create mode 100755 tests/xfs/530
>  create mode 100644 tests/xfs/530.out
> 
> diff --git a/tests/xfs/530 b/tests/xfs/530
> new file mode 100755
> index 00000000..fccc6de7
> --- /dev/null
> +++ b/tests/xfs/530
> @@ -0,0 +1,115 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 530
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# swapping forks between files
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_debug
> +_require_xfs_scratch_rmapbt
> +_require_xfs_io_command "fcollapse"
> +_require_xfs_io_command "swapext"

FWIW it's going to be a while before the swapext command goes upstream.
Right now it's a part of the atomic file range exchange patchset.

Do you want me to try to speed that up?

--D

> +_require_xfs_io_error_injection "reduce_max_iextents"
> +
> +echo "* Swap extent forks"
> +
> +echo "Format and mount fs"
> +_scratch_mkfs >> $seqres.full
> +_scratch_mount >> $seqres.full
> +
> +bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +srcfile=${SCRATCH_MNT}/srcfile
> +donorfile=${SCRATCH_MNT}/donorfile
> +
> +echo "Create \$donorfile having an extent of length 17 blocks"
> +xfs_io -f -c "pwrite -b $((17 * bsize)) 0 $((17 * bsize))" -c fsync $donorfile \
> +       >> $seqres.full
> +
> +# After the for loop the donor file will have the following extent layout
> +# | 0-4 | 5 | 6 | 7 | 8 | 9 | 10 |
> +echo "Fragment \$donorfile"
> +for i in $(seq 5 10); do
> +	start_offset=$((i * bsize))
> +	xfs_io -f -c "fcollapse $start_offset $bsize" $donorfile >> $seqres.full
> +done
> +donorino=$(stat -c "%i" $donorfile)
> +
> +echo "Create \$srcfile having an extent of length 18 blocks"
> +xfs_io -f -c "pwrite -b $((18 * bsize)) 0 $((18 * bsize))" -c fsync $srcfile \
> +       >> $seqres.full
> +
> +echo "Fragment \$srcfile"
> +# After the for loop the src file will have the following extent layout
> +# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7-10 |
> +for i in $(seq 1 7); do
> +	start_offset=$((i * bsize))
> +	xfs_io -f -c "fcollapse $start_offset $bsize" $srcfile >> $seqres.full
> +done
> +srcino=$(stat -c "%i" $srcfile)
> +
> +_scratch_unmount >> $seqres.full
> +
> +echo "Collect \$donorfile's extent count"
> +donor_nr_exts=$(_scratch_get_iext_count $donorino data || \
> +		_fail "Unable to obtain inode fork's extent count")
> +
> +echo "Collect \$srcfile's extent count"
> +src_nr_exts=$(_scratch_get_iext_count $srcino data || \
> +		_fail "Unable to obtain inode fork's extent count")
> +
> +_scratch_mount >> $seqres.full
> +
> +echo "Inject reduce_max_iextents error tag"
> +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +echo "Swap \$srcfile's and \$donorfile's extent forks"
> +xfs_io -f -c "swapext $donorfile" $srcfile >> $seqres.full 2>&1
> +
> +_scratch_unmount >> $seqres.full
> +
> +echo "Check for \$donorfile's extent count overflow"
> +nextents=$(_scratch_get_iext_count $donorino data || \
> +		_fail "Unable to obtain inode fork's extent count")
> +if (( $nextents == $src_nr_exts )); then
> +	echo "\$donorfile: Extent count overflow check failed"
> +fi
> +
> +echo "Check for \$srcfile's extent count overflow"
> +nextents=$(_scratch_get_iext_count $srcino data || \
> +		_fail "Unable to obtain inode fork's extent count")
> +if (( $nextents == $donor_nr_exts )); then
> +	echo "\$srcfile: Extent count overflow check failed"
> +fi
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/530.out b/tests/xfs/530.out
> new file mode 100644
> index 00000000..996af959
> --- /dev/null
> +++ b/tests/xfs/530.out
> @@ -0,0 +1,13 @@
> +QA output created by 530
> +* Swap extent forks
> +Format and mount fs
> +Create $donorfile having an extent of length 17 blocks
> +Fragment $donorfile
> +Create $srcfile having an extent of length 18 blocks
> +Fragment $srcfile
> +Collect $donorfile's extent count
> +Collect $srcfile's extent count
> +Inject reduce_max_iextents error tag
> +Swap $srcfile's and $donorfile's extent forks
> +Check for $donorfile's extent count overflow
> +Check for $srcfile's extent count overflow
> diff --git a/tests/xfs/group b/tests/xfs/group
> index bc3958b3..81a15582 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -527,3 +527,4 @@
>  527 auto quick
>  528 auto quick reflink
>  529 auto quick reflink
> +530 auto quick
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count
  2020-11-13 11:26 ` [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count Chandan Babu R
@ 2020-11-14  0:10   ` Darrick J. Wong
  0 siblings, 0 replies; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:10 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:53PM +0530, Chandan Babu R wrote:
> This commit adds the helper _scratch_get_iext_count() which returns an
> inode fork's extent count.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  common/xfs | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/common/xfs b/common/xfs
> index 79dab058..45cd329c 100644
> --- a/common/xfs
> +++ b/common/xfs
> @@ -883,6 +883,28 @@ _scratch_get_bmx_prefix() {
>  	return 1
>  }
>  
> +_scratch_get_iext_count()
> +{
> +	ino=$1
> +	whichfork=$2
> +
> +	case $whichfork in
> +		"attr")
> +			field=core.naextents
> +			;;
> +		"data")
> +			field=core.nextents
> +			;;
> +		*)
> +			return 1
> +	esac
> +
> +	nextents=$(_scratch_xfs_db  -c "inode $ino" -c "print $field")
> +	nextents=${nextents##${field} = }

This helper looks fine, but looking at the callers spread over the next
10 patches, I notice that you unmount to call this helper and
immediately remount the fs.

I wonder, is there a specific reason for grabbing the extent count that
way?  You can extract the same info online with `xfs_io -c 'stat' /moo',
right?

--D

> +
> +	echo $nextents
> +}
> +
>  #
>  # Ensures that we don't pass any mount options incompatible with XFS v4
>  #
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-13 11:26 ` [PATCH 03/11] " Chandan Babu R
@ 2020-11-14  0:18   ` Darrick J. Wong
  2020-11-17 14:22     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:18 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

> Subject: xfs: Check for extent overflow when trivally adding a new extent

Why does patch 3 have the same subject as patch 2?  This confused
my quiltish scripts. :(

On Fri, Nov 13, 2020 at 04:56:55PM +0530, Chandan Babu R wrote:
> Verify that XFS does not cause inode fork's extent count to overflow
> when adding a single extent while there's no possibility of splitting an
> existing mapping (limited to realtime files only).
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/523     | 176 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/523.out |  18 +++++
>  tests/xfs/group   |   1 +
>  3 files changed, 195 insertions(+)
>  create mode 100755 tests/xfs/523
>  create mode 100644 tests/xfs/523.out
> 
> diff --git a/tests/xfs/523 b/tests/xfs/523
> new file mode 100755
> index 00000000..4f5b3584
> --- /dev/null
> +++ b/tests/xfs/523
> @@ -0,0 +1,176 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 523
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# adding a single extent while there's no possibility of splitting an existing
> +# mapping (limited to realtime files only).
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	_scratch_unmount >> $seqres.full 2>&1
> +	test -e "$rtdev" && losetup -d $rtdev >> $seqres.full 2>&1
> +	rm -f $tmp.* $TEST_DIR/$seq.rtvol
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_test
> +_require_xfs_debug
> +_require_test_program "punch-alternating"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> +_require_scratch_nocheck
> +
> +grow_rtinodes()
> +{
> +	echo "* Test extending rt inodes"
> +
> +	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> +	. $tmp.mkfs
> +
> +	echo "Create fake rt volume"
> +	nr_bitmap_blks=25
> +	nr_bits=$((nr_bitmap_blks * dbsize * 8))
> +	rtextsz=$dbsize
> +	rtdevsz=$((nr_bits * rtextsz))
> +	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
> +	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
> +
> +	echo "Format and mount rt volume"
> +	export USE_EXTERNAL=yes
> +	export SCRATCH_RTDEV=$rtdev

I'm frankly wondering if it's time to just turn this into a
_scratch_synthesize_rtvol helper or something.

> +	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
> +		      -r size=2M,extsize=${rtextsz} >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1

Can you accomplish this with fallocate?  Or better yet _fill_fs()?

> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	echo "Grow realtime volume"
> +	xfs_growfs -r $SCRATCH_MNT >> $seqres.full 2>&1

$XFS_GROWFS_PROG, not xfs_growfs

> +	if [[ $? == 0 ]]; then
> +		echo "Growfs succeeded; should have failed."
> +		exit 1
> +	fi
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify rbmino's and rsumino's extent count"
> +	for rtino in rbmino rsumino; do
> +		ino=$(_scratch_xfs_db -c sb -c "print $rtino")
> +		ino=${ino##${rtino} = }
> +		echo "$rtino = $ino" >> $seqres.full
> +
> +		nextents=$(_scratch_get_iext_count $ino data || \
> +				_fail "Unable to obtain inode fork's extent count")

Aha, you use this helper for the rt inodes too.  Ok, disregard my
comments for patch 1.

> +		if (( $nextents > 10 )); then
> +			echo "Extent count overflow check failed: nextents = $nextents"
> +			exit 1
> +		fi
> +	done
> +
> +	echo "Check filesystem"
> +	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
> +
> +	losetup -d $rtdev
> +	rm -f $TEST_DIR/$seq.rtvol
> +
> +	export USE_EXTERNAL=""
> +	export SCRATCH_RTDEV=""
> +}
> +
> +rtfile_extend()
> +{
> +	echo "* Test extending an rt file"
> +
> +	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> +	. $tmp.mkfs

Are these separate functionality tests?  If so, should they be in
separate test files?

> +
> +	echo "Create fake rt volume"
> +	nr_blks=$((15 * 2))
> +	rtextsz=$dbsize
> +	rtdevsz=$((2 * nr_blks * rtextsz))
> +	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
> +	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
> +
> +	echo "Format and mount rt volume"
> +	export USE_EXTERNAL=yes
> +	export SCRATCH_RTDEV=$rtdev
> +	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
> +		      -r size=$rtdevsz >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT

$XFS_IO_PROG, not xfs_io.

--D

> +
> +	echo "Create fragmented file on rt volume"
> +	testfile=$SCRATCH_MNT/testfile
> +	for i in $(seq 0 2 $((nr_blks - 1))); do
> +		xfs_io -Rf -c "pwrite $((i * dbsize)) $dbsize" -c fsync \
> +		       $testfile >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +
> +	echo "Check filesystem"
> +	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
> +
> +	losetup -d $rtdev
> +	rm -f $TEST_DIR/$seq.rtvol
> +
> +	export USE_EXTERNAL=""
> +	export SCRATCH_RTDEV=""
> +}
> +
> +grow_rtinodes
> +rtfile_extend
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/523.out b/tests/xfs/523.out
> new file mode 100644
> index 00000000..16b4e0ad
> --- /dev/null
> +++ b/tests/xfs/523.out
> @@ -0,0 +1,18 @@
> +QA output created by 523
> +* Test extending rt inodes
> +Create fake rt volume
> +Format and mount rt volume
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Grow realtime volume
> +Verify rbmino's and rsumino's extent count
> +Check filesystem
> +* Test extending an rt file
> +Create fake rt volume
> +Format and mount rt volume
> +Inject reduce_max_iextents error tag
> +Create fragmented file on rt volume
> +Verify $testfile's extent count
> +Check filesystem
> diff --git a/tests/xfs/group b/tests/xfs/group
> index 1831f0b5..018c70ef 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -520,3 +520,4 @@
>  520 auto quick reflink
>  521 auto quick realtime growfs
>  522 auto quick quota
> +523 auto quick realtime growfs
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-13 11:26 ` [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent Chandan Babu R
@ 2020-11-14  0:24   ` Darrick J. Wong
  2020-11-17 14:12     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:24 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:54PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when adding a single extent while there's no possibility of
> splitting an existing mapping (limited to non-realtime files).
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/522     | 214 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/522.out |  24 ++++++
>  tests/xfs/group   |   1 +
>  3 files changed, 239 insertions(+)
>  create mode 100755 tests/xfs/522
>  create mode 100644 tests/xfs/522.out
> 
> diff --git a/tests/xfs/522 b/tests/xfs/522
> new file mode 100755
> index 00000000..a54fe136
> --- /dev/null
> +++ b/tests/xfs/522
> @@ -0,0 +1,214 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 522
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# adding a single extent while there's no possibility of splitting an existing
> +# mapping (limited to non-realtime files).
> +
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/quota
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_quota
> +_require_xfs_debug
> +_require_xfs_io_command "falloc"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> +
> +delalloc_to_written_extent()
> +{
> +	echo "* Delalloc to written extent conversion"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	nr_blks=$((15 * 2))
> +
> +	echo "Create fragmented file"
> +	for i in $(seq 0 2 $((nr_blks - 1))); do
> +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			   _fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +falloc_unwritten_extent()
> +{
> +	echo "* Fallocate of unwritten extents"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	nr_blks=$((15 * 2))
> +
> +	echo "Fallocate fragmented file"
> +	for i in $(seq 0 2 $((nr_blks - 1))); do
> +		xfs_io -f -c "falloc $((i * bsize)) $bsize" $testfile >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			   _fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +quota_inode_extend()
> +{
> +	echo "* Extend quota inodes"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount -o uquota >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	nr_blks=20
> +
> +	# This is a rough calculation; It doesn't take block headers into
> +	# consideration.
> +	# gdb -batch vmlinux -ex 'print sizeof(struct xfs_disk_dquot)'
> +	# $1 = 104
> +	nr_quotas_per_block=$((bsize / 104))

That's sizeof(xfs_dqblk_t) you want, and it's 136 bytes long.

> +	nr_quotas=$((nr_quotas_per_block * nr_blks))
> +
> +	echo "Extend uquota file"
> +	for i in $(seq 0 $nr_quotas); do

You only have to initialize the first dquot in a dquot file block in
order to allocate the whole block, so you could speed this up with
"seq 0 $nr_quotas_per_block $nr_quotas".

> +		chown $i $testfile >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify uquota inode's extent count"
> +	uquotino=$(_scratch_xfs_db -c sb -c "print uquotino")
> +	uquotino=${uquotino##uquotino = }
> +
> +	nextents=$(_scratch_get_iext_count $uquotino data || \
> +			   _fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +directio_write()
> +{
> +	echo "* Directio write"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	nr_blks=$((15 * 2))
> +
> +	echo "Create fragmented file via directio writes"
> +	for i in $(seq 0 2 $((nr_blks - 1))); do
> +		xfs_io -d -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1

$XFS_IO_PROG -d -f -s -c "pwrite ..." $testfile

"-s" is an undocumented flag that makes the writes synchronous.

> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \

$XFS_IO_PROG -c 'stat' $testfile | grep nextents ?

> +			   _fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +delalloc_to_written_extent
> +falloc_unwritten_extent
> +quota_inode_extend
> +directio_write

I wonder if these should be separate tests, since they each format the
scratch fs?  Or could you format the scratch fs once and test four
different files?

--D

> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/522.out b/tests/xfs/522.out
> new file mode 100644
> index 00000000..98791aae
> --- /dev/null
> +++ b/tests/xfs/522.out
> @@ -0,0 +1,24 @@
> +QA output created by 522
> +* Delalloc to written extent conversion
> +Format and mount fs
> +Inject reduce_max_iextents error tag
> +Create fragmented file
> +Verify $testfile's extent count
> +* Fallocate of unwritten extents
> +Format and mount fs
> +Inject reduce_max_iextents error tag
> +Fallocate fragmented file
> +Verify $testfile's extent count
> +* Extend quota inodes
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Extend uquota file
> +Verify uquota inode's extent count
> +* Directio write
> +Format and mount fs
> +Inject reduce_max_iextents error tag
> +Create fragmented file via directio writes
> +Verify $testfile's extent count
> diff --git a/tests/xfs/group b/tests/xfs/group
> index b89c0a4e..1831f0b5 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -519,3 +519,4 @@
>  519 auto quick reflink
>  520 auto quick reflink
>  521 auto quick realtime growfs
> +522 auto quick quota
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/11] xfs: Check for extent overflow when punching a hole
  2020-11-13 11:26 ` [PATCH 04/11] xfs: Check for extent overflow when punching a hole Chandan Babu R
@ 2020-11-14  0:28   ` Darrick J. Wong
  2020-11-17 14:26     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:28 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:56PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when punching out an extent.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/524     | 210 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/524.out |  25 ++++++
>  tests/xfs/group   |   1 +
>  3 files changed, 236 insertions(+)
>  create mode 100755 tests/xfs/524
>  create mode 100644 tests/xfs/524.out
> 
> diff --git a/tests/xfs/524 b/tests/xfs/524
> new file mode 100755
> index 00000000..9e140c99
> --- /dev/null
> +++ b/tests/xfs/524
> @@ -0,0 +1,210 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 524
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# punching out an extent.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_debug
> +_require_xfs_io_command "finsert"
> +_require_xfs_io_command "fcollapse"
> +_require_xfs_io_command "fzero"

For completeness, should this also be testing funshare?

> +_require_test_program "punch-alternating"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +
> +punch_range()
> +{
> +	echo "* Fpunch regular file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full

I don't think you need a fresh format for each functional test.

> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	nr_blks=30
> +
> +	echo "Create \$testfile"
> +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> +	       -c sync $testfile  >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "fpunch alternating blocks"
> +	$here/src/punch-alternating $testfile >> $seqres.full 2>&1
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data ||

...and now that I keep seeing this unmount-getiextcount-mount dance, you
probably should convert these to grab the extent count info online.

--D

> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +finsert_range()
> +{
> +	echo "* Finsert regular file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)	
> +
> +	nr_blks=30
> +
> +	echo "Create \$testfile"
> +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> +	       -c sync $testfile  >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Finsert at every other block offset"
> +	for i in $(seq 1 2 $((nr_blks - 1))); do
> +		xfs_io -f -c "finsert $((i * bsize)) $bsize" $testfile \
> +		       >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = ${nextents}"
> +		exit 1
> +	fi
> +}
> +
> +fcollapse_range()
> +{
> +	echo "* Fcollapse regular file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)	
> +
> +	nr_blks=30
> +
> +	echo "Create \$testfile"
> +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> +	       -c sync $testfile  >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Fcollapse at every other block offset"
> +	for i in $(seq 1 $((nr_blks / 2 - 1))); do
> +		xfs_io -f -c "fcollapse $((i * bsize)) $bsize" $testfile \
> +		       >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = ${nextents}"
> +		exit 1
> +	fi
> +}
> +
> +fzero_range()
> +{
> +	echo "* Fzero regular file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +	bsize=$(_get_block_size $SCRATCH_MNT)	
> +
> +	nr_blks=30
> +
> +	echo "Create \$testfile"
> +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> +	       -c sync $testfile  >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Fzero at every other block offset"
> +	for i in $(seq 1 2 $((nr_blks - 1))); do
> +		xfs_io -f -c "fzero $((i * bsize)) $bsize" $testfile \
> +		       >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = ${nextents}"
> +		exit 1
> +	fi
> +}
> +
> +punch_range
> +finsert_range
> +fcollapse_range
> +fzero_range
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/524.out b/tests/xfs/524.out
> new file mode 100644
> index 00000000..58f7d7ae
> --- /dev/null
> +++ b/tests/xfs/524.out
> @@ -0,0 +1,25 @@
> +QA output created by 524
> +* Fpunch regular file
> +Format and mount fs
> +Create $testfile
> +Inject reduce_max_iextents error tag
> +fpunch alternating blocks
> +Verify $testfile's extent count
> +* Finsert regular file
> +Format and mount fs
> +Create $testfile
> +Inject reduce_max_iextents error tag
> +Finsert at every other block offset
> +Verify $testfile's extent count
> +* Fcollapse regular file
> +Format and mount fs
> +Create $testfile
> +Inject reduce_max_iextents error tag
> +Fcollapse at every other block offset
> +Verify $testfile's extent count
> +* Fzero regular file
> +Format and mount fs
> +Create $testfile
> +Inject reduce_max_iextents error tag
> +Fzero at every other block offset
> +Verify $testfile's extent count
> diff --git a/tests/xfs/group b/tests/xfs/group
> index 018c70ef..3fa38c36 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -521,3 +521,4 @@
>  521 auto quick realtime growfs
>  522 auto quick quota
>  523 auto quick realtime growfs
> +524 auto quick punch zero insert collapse
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs
  2020-11-13 11:26 ` [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs Chandan Babu R
@ 2020-11-14  0:34   ` Darrick J. Wong
  2020-11-17 14:30     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:34 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:57PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when adding/removing xattrs.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/525     | 154 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/525.out |  16 +++++
>  tests/xfs/group   |   1 +
>  3 files changed, 171 insertions(+)
>  create mode 100755 tests/xfs/525
>  create mode 100644 tests/xfs/525.out
> 
> diff --git a/tests/xfs/525 b/tests/xfs/525
> new file mode 100755
> index 00000000..1d5d6e7c
> --- /dev/null
> +++ b/tests/xfs/525
> @@ -0,0 +1,154 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 525
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# Adding/removing xattrs.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/attr
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_attrs
> +_require_xfs_debug
> +_require_test_program "punch-alternating"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> +
> +attr_set()
> +{
> +	echo "* Set xattrs"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	echo "Create xattrs"
> +
> +	attr_len=$(uuidgen | wc -c)
> +	nr_attrs=$((bsize * 20 / attr_len))
> +	for i in $(seq 1 $nr_attrs); do
> +		$SETFATTR_PROG -n "trusted.""$(uuidgen)" $testfile \

Does this test require UUIDs in the attr names?  Why wouldn't
$(printf "%037d" $i) suffice for this purpose?

Though if you insist upon using uuids, please call $UUIDGEN_PROG per
fstest custom.

> +			 >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify uquota inode's extent count"

Huh?  I thought we were testing file attrs?

> +	nextents=$(_scratch_get_iext_count $testino attr || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +		exit 1
> +	fi
> +}
> +
> +attr_remove()
> +{
> +	echo "* Remove xattrs"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	naextents=0
> +	last=""
> +
> +	attr_len=$(uuidgen | wc -c)
> +	nr_attrs=$((bsize / attr_len))
> +
> +	echo "Create initial xattr extents"
> +	while (( $naextents < 4 )); do
> +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +		for i in $(seq 1 $nr_attrs); do
> +			last="trusted.""$(uuidgen)"
> +			$SETFATTR_PROG -n $last $testfile
> +		done
> +
> +		_scratch_unmount >> $seqres.full
> +
> +		naextents=$(_scratch_get_iext_count $testino attr || \
> +				_fail "Unable to obtain inode fork's extent count")
> +
> +		_scratch_mount >> $seqres.full
> +	done
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Remove xattr to trigger -EFBIG"
> +	$SETFATTR_PROG -x "$last" $testfile >> $seqres.full 2>&1
> +	if [[ $? == 0 ]]; then
> +		echo "Xattr removal succeeded; Should have failed "

So at this point the user has a file for which he can't ever remove the
xattrs for fear of overflowing naextents.  The only way to clear this is
to delete the file, so shouldn't you be testing that this succeeds?

--D

> +		exit 1
> +	fi
> +}
> +
> +attr_set
> +attr_remove
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/525.out b/tests/xfs/525.out
> new file mode 100644
> index 00000000..cc40e6e2
> --- /dev/null
> +++ b/tests/xfs/525.out
> @@ -0,0 +1,16 @@
> +QA output created by 525
> +* Set xattrs
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Create xattrs
> +Verify uquota inode's extent count
> +* Remove xattrs
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Create initial xattr extents
> +Inject reduce_max_iextents error tag
> +Remove xattr to trigger -EFBIG
> diff --git a/tests/xfs/group b/tests/xfs/group
> index 3fa38c36..bd38aff0 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -522,3 +522,4 @@
>  522 auto quick quota
>  523 auto quick realtime growfs
>  524 auto quick punch zero insert collapse
> +525 auto quick attr
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries
  2020-11-13 11:26 ` [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries Chandan Babu R
@ 2020-11-14  0:37   ` Darrick J. Wong
  2020-11-17 14:50     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:37 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:58PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when adding/removing directory entries.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/526     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/526.out |  47 ++++++
>  tests/xfs/group   |   1 +
>  3 files changed, 408 insertions(+)
>  create mode 100755 tests/xfs/526
>  create mode 100644 tests/xfs/526.out
> 
> diff --git a/tests/xfs/526 b/tests/xfs/526
> new file mode 100755
> index 00000000..39cfbcf8
> --- /dev/null
> +++ b/tests/xfs/526
> @@ -0,0 +1,360 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 526
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# adding/removing directory entries.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_debug
> +_require_test_program "punch-alternating"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> +
> +_scratch_mkfs_sized $((1024 * 1024 * 1024)) | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> +. $tmp.mkfs
> +
> +dir_entry_create()
> +{
> +	echo "* Create directory entries"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full

Same questions as I've had for all the other tests -- why is it critical to
reformat between each test?  Why is it necessary to encode uuids in the
attr/dir names?

> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	echo "Create directory entries"
> +	dent_len=$(uuidgen | wc -c)

Also, it'll explode the directories faster if you use maximal length
names (255) instead of uuids (37).

The same applies to the xattr tests in the previous patch.

> +	nr_dents=$((dbsize * 20 / dent_len))
> +	for i in $(seq 1 $nr_dents); do
> +		touch $SCRATCH_MNT/$(uuidgen) >> $seqres.full 2>&1 || break
> +	done
> +
> +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify directory's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $dirino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +dir_entry_rename_dst()
> +{
> +	echo "* Rename: Populate destination directory"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	dstdir=$SCRATCH_MNT/dstdir
> +	mkdir $dstdir
> +
> +	dent_len=$(uuidgen | wc -c)
> +	nr_dents=$((dirbsize * 20 / dent_len))
> +
> +	echo "Populate \$dstdir by mv-ing new directory entries"
> +	for i in $(seq 1 $nr_dents); do
> +		file=${SCRATCH_MNT}/$(uuidgen)
> +		touch $file || break
> +		mv $file $dstdir >> $seqres.full 2>&1 || break
> +	done
> +
> +	dirino=$(stat -c "%i" $dstdir)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$dstdir's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $dirino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +dir_entry_rename_src()
> +{
> +	echo "* Rename: Populate source directory and mv one entry to destination directory"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	srcdir=${SCRATCH_MNT}/srcdir
> +	dstdir=${SCRATCH_MNT}/dstdir
> +
> +	mkdir $srcdir $dstdir
> +
> +	dirino=$(stat -c "%i" $srcdir)
> +
> +	dent_len=$(uuidgen | wc -c)
> +	nr_dents=$((dirbsize / dent_len))
> +	nextents=0
> +	last=""
> +
> +	echo "Populate \$srcdir with atleast 4 extents"
> +	while (( $nextents < 4 )); do
> +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +		for i in $(seq 1 $nr_dents); do
> +			last=${srcdir}/$(uuidgen)
> +			touch $last || break
> +		done
> +
> +		_scratch_unmount >> $seqres.full
> +
> +		nextents=$(_scratch_get_iext_count $dirino data || \
> +				_fail "Unable to obtain inode fork's extent count")
> +
> +		_scratch_mount >> $seqres.full
> +	done
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Move an entry from \$srcdir to trigger -EFBIG"
> +	mv $last $dstdir >> $seqres.full 2>&1
> +	if [[ $? == 0 ]]; then
> +		echo "Moving from \$srcdir to \$dstdir succeeded; Should have failed"
> +	fi
> +
> +	_scratch_unmount >> $seqres.full
> +}
> +
> +dir_entry_create_hard_links()
> +{
> +	echo "* Create multiple hard links to a single file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	dent_len=$(uuidgen | wc -c)
> +	nr_dents=$((dirbsize * 20 / dent_len))
> +
> +	echo "Create multiple hardlinks"
> +	for i in $(seq 1 $nr_dents); do
> +		ln $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break
> +	done
> +
> +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify directory's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $dirino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +dir_entry_create_symlinks()
> +{
> +	echo "* Create multiple symbolic links to a single file"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Inject bmap_alloc_minlen_extent error tag"
> +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +	dent_len=$(uuidgen | wc -c)
> +	nr_dents=$((dirbsize * 20 / dent_len))
> +
> +	echo "Create multiple symbolic links"
> +	for i in $(seq 1 $nr_dents); do
> +		ln -s $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break;
> +	done
> +
> +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify directory's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $dirino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +dir_entry_remove()
> +{
> +	echo "* Populate a directory and remove one entry"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	testfile=$SCRATCH_MNT/testfile
> +
> +	echo "Consume free space"
> +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> +	sync
> +
> +	echo "Create fragmented filesystem"
> +	$here/src/punch-alternating $testfile >> $seqres.full
> +	sync
> +
> +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> +
> +	dent_len=$(uuidgen | wc -c)
> +	nr_dents=$((dirbsize / dent_len))
> +	nextents=0
> +	last=""
> +
> +	echo "Populate directory with atleast 4 extents"
> +	while (( $nextents < 4 )); do
> +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> +
> +		for i in $(seq 1 $nr_dents); do
> +			last=${SCRATCH_MNT}/$(uuidgen)
> +			touch $last || break
> +		done
> +
> +		_scratch_unmount >> $seqres.full
> +
> +		nextents=$(_scratch_get_iext_count $dirino data || \
> +				_fail "Unable to obtain inode fork's extent count")
> +
> +		_scratch_mount >> $seqres.full
> +	done
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +	echo "Remove an entry from directory to trigger -EFBIG"
> +	rm $last >> $seqres.full 2>&1
> +	if [[ $? == 0 ]]; then
> +		echo "Removing file succeeded; Should have failed"
> +	fi
> +
> +	_scratch_unmount >> $seqres.full
> +}
> +
> +# Filesystems with directory block size greater than one FSB will not be tested,
> +# since "7 (i.e. XFS_DA_NODE_MAXDEPTH + 1 data block + 1 free block) * 2 (fsb
> +# count) = 14" is greater than the pseudo max extent count limit of 10.
> +# Extending the pseudo max limit won't help either.  Consider the case where 1
> +# FSB is 1k in size and 1 dir block is 64k in size (i.e. fsb count = 64). In
> +# this case, the pseudo max limit has to be greater than 7 * 64 = 448 extents.
> +if (( $dbsize != $dirbsize )); then
> +	_notrun "FSB size ($dbsize) and directory block size ($dirbsize) do not match"

Heh, I had wondered about that.  Good that you caught this here!

--D

> +fi
> +
> +dir_entry_create
> +dir_entry_rename_dst
> +dir_entry_rename_src
> +dir_entry_create_hard_links
> +dir_entry_create_symlinks
> +dir_entry_remove
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/526.out b/tests/xfs/526.out
> new file mode 100644
> index 00000000..21f77cd8
> --- /dev/null
> +++ b/tests/xfs/526.out
> @@ -0,0 +1,47 @@
> +QA output created by 526
> +* Create directory entries
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Create directory entries
> +Verify directory's extent count
> +* Rename: Populate destination directory
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Populate $dstdir by mv-ing new directory entries
> +Verify $dstdir's extent count
> +* Rename: Populate source directory and mv one entry to destination directory
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Populate $srcdir with atleast 4 extents
> +Inject reduce_max_iextents error tag
> +Move an entry from $srcdir to trigger -EFBIG
> +* Create multiple hard links to a single file
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Create multiple hardlinks
> +Verify directory's extent count
> +* Create multiple symbolic links to a single file
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Inject reduce_max_iextents error tag
> +Inject bmap_alloc_minlen_extent error tag
> +Create multiple symbolic links
> +Verify directory's extent count
> +* Populate a directory and remove one entry
> +Format and mount fs
> +Consume free space
> +Create fragmented filesystem
> +Populate directory with atleast 4 extents
> +Inject reduce_max_iextents error tag
> +Remove an entry from directory to trigger -EFBIG
> diff --git a/tests/xfs/group b/tests/xfs/group
> index bd38aff0..d089797b 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -523,3 +523,4 @@
>  523 auto quick realtime growfs
>  524 auto quick punch zero insert collapse
>  525 auto quick attr
> +526 auto quick dir hardlink symlink
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent
  2020-11-13 11:26 ` [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent Chandan Babu R
@ 2020-11-14  0:39   ` Darrick J. Wong
  2020-11-17 15:15     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:39 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:56:59PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when writing to an unwritten extent.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/527     | 125 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/527.out |  13 +++++
>  tests/xfs/group   |   1 +
>  3 files changed, 139 insertions(+)
>  create mode 100755 tests/xfs/527
>  create mode 100644 tests/xfs/527.out
> 
> diff --git a/tests/xfs/527 b/tests/xfs/527
> new file mode 100755
> index 00000000..f040aee4
> --- /dev/null
> +++ b/tests/xfs/527
> @@ -0,0 +1,125 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 527
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# writing to an unwritten extent.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_xfs_debug
> +_require_xfs_io_command "falloc"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +
> +buffered_write_to_unwritten_extent()

This is nearly the same as the directio write test; could you combine
them into a single function so we have fewer functions to maintain?

--D

> +{
> +	echo "* Buffered write to unwritten extent"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	testfile=${SCRATCH_MNT}/testfile
> +
> +	nr_blks=15
> +
> +	echo "Fallocate $nr_blks blocks"
> +	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
> +
> +	echo "Buffered write to every other block of fallocated space"
> +	for i in $(seq 1 2 $((nr_blks - 1))); do
> +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile \
> +		       >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +direct_write_to_unwritten_extent()
> +{
> +	echo "* Direct I/O write to unwritten extent"
> +
> +	echo "Format and mount fs"
> +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> +	_scratch_mount >> $seqres.full
> +
> +	bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +	testfile=${SCRATCH_MNT}/testfile
> +
> +	nr_blks=15
> +
> +	echo "Fallocate $nr_blks blocks"
> +	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
> +
> +	echo "Inject reduce_max_iextents error tag"
> +	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
> +
> +	echo "Direct I/O write to every other block of fallocated space"
> +	for i in $(seq 1 2 $((nr_blks - 1))); do
> +		xfs_io -f -d -c "pwrite $((i * bsize)) $bsize" $testfile \
> +		       >> $seqres.full 2>&1
> +		[[ $? != 0 ]] && break
> +	done
> +
> +	testino=$(stat -c "%i" $testfile)
> +
> +	_scratch_unmount >> $seqres.full
> +
> +	echo "Verify \$testfile's extent count"
> +
> +	nextents=$(_scratch_get_iext_count $testino data || \
> +			_fail "Unable to obtain inode fork's extent count")
> +	if (( $nextents > 10 )); then
> +		echo "Extent count overflow check failed: nextents = $nextents"
> +	fi
> +}
> +
> +buffered_write_to_unwritten_extent
> +direct_write_to_unwritten_extent
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/527.out b/tests/xfs/527.out
> new file mode 100644
> index 00000000..6aa5e9ed
> --- /dev/null
> +++ b/tests/xfs/527.out
> @@ -0,0 +1,13 @@
> +QA output created by 527
> +* Buffered write to unwritten extent
> +Format and mount fs
> +Fallocate 15 blocks
> +Inject reduce_max_iextents error tag
> +Buffered write to every other block of fallocated space
> +Verify $testfile's extent count
> +* Direct I/O write to unwritten extent
> +Format and mount fs
> +Fallocate 15 blocks
> +Inject reduce_max_iextents error tag
> +Direct I/O write to every other block of fallocated space
> +Verify $testfile's extent count
> diff --git a/tests/xfs/group b/tests/xfs/group
> index d089797b..627813fe 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -524,3 +524,4 @@
>  524 auto quick punch zero insert collapse
>  525 auto quick attr
>  526 auto quick dir hardlink symlink
> +527 auto quick
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork
  2020-11-13 11:27 ` [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork Chandan Babu R
@ 2020-11-14  0:42   ` Darrick J. Wong
  2020-11-18  5:20     ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:42 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:57:00PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when writing to a shared extent.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/528     | 87 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/528.out |  8 +++++
>  tests/xfs/group   |  1 +
>  3 files changed, 96 insertions(+)
>  create mode 100755 tests/xfs/528
>  create mode 100644 tests/xfs/528.out
> 
> diff --git a/tests/xfs/528 b/tests/xfs/528
> new file mode 100755
> index 00000000..0d39f05e
> --- /dev/null
> +++ b/tests/xfs/528
> @@ -0,0 +1,87 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 528
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# writing to a shared extent.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/reflink
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_scratch_reflink
> +_require_xfs_debug
> +_require_xfs_io_command "reflink"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +
> +echo "* Write to shared extent"
> +
> +echo "Format and mount fs"
> +_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> +_scratch_mount >> $seqres.full
> +
> +bsize=$(_get_block_size $SCRATCH_MNT)

Now that we're playing with regular files again -- should this be
_get_file_block_size ?  I think the same question applies to patches 2,
3, and 4, and perhaps the next one too.

(Note that regular files can have cluster sizes that aren't the same as
the fs block size if I set MKFS_OPTIONS="-d rtinherit=1 -r extsize=64k".)

--D

> +
> +srcfile=${SCRATCH_MNT}/srcfile
> +dstfile=${SCRATCH_MNT}/dstfile
> +
> +nr_blks=15
> +
> +echo "Create a \$srcfile having an extent of length $nr_blks blocks"
> +xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
> +       -c fsync $srcfile  >> $seqres.full
> +
> +echo "Share the extent with \$dstfile"
> +xfs_io -f -c "reflink $srcfile" $dstfile >> $seqres.full
> +
> +echo "Inject reduce_max_iextents error tag"
> +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +echo "Buffered write to every other block of \$dstfile's shared extent"
> +for i in $(seq 1 2 $((nr_blks - 1))); do
> +	xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $dstfile \
> +	       >> $seqres.full 2>&1
> +	[[ $? != 0 ]] && break
> +done
> +
> +ino=$(stat -c "%i" $dstfile)
> +
> +_scratch_unmount >> $seqres.full
> +
> +echo "Verify \$dstfile's extent count"
> +
> +nextents=$(_scratch_get_iext_count $ino data || \
> +		_fail "Unable to obtain inode fork's extent count")
> +if (( $nextents > 10 )); then
> +	echo "Extent count overflow check failed: nextents = $nextents"
> +fi
> +
> +# success, all done
> +status=0
> +exit
> + 
> diff --git a/tests/xfs/528.out b/tests/xfs/528.out
> new file mode 100644
> index 00000000..8666488b
> --- /dev/null
> +++ b/tests/xfs/528.out
> @@ -0,0 +1,8 @@
> +QA output created by 528
> +* Write to shared extent
> +Format and mount fs
> +Create a $srcfile having an extent of length 15 blocks
> +Share the extent with $dstfile
> +Inject reduce_max_iextents error tag
> +Buffered write to every other block of $dstfile's shared extent
> +Verify $dstfile's extent count
> diff --git a/tests/xfs/group b/tests/xfs/group
> index 627813fe..c85aac6b 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -525,3 +525,4 @@
>  525 auto quick attr
>  526 auto quick dir hardlink symlink
>  527 auto quick
> +528 auto quick reflink
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 09/11] xfs: Check for extent overflow when remapping an extent
  2020-11-13 11:27 ` [PATCH 09/11] xfs: Check for extent overflow when remapping an extent Chandan Babu R
@ 2020-11-14  0:43   ` Darrick J. Wong
  0 siblings, 0 replies; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-14  0:43 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Fri, Nov 13, 2020 at 04:57:01PM +0530, Chandan Babu R wrote:
> This test verifies that XFS does not cause inode fork's extent count to
> overflow when remapping extents from one file's inode fork to another.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  tests/xfs/529     | 86 +++++++++++++++++++++++++++++++++++++++++++++++
>  tests/xfs/529.out |  8 +++++
>  tests/xfs/group   |  1 +
>  3 files changed, 95 insertions(+)
>  create mode 100755 tests/xfs/529
>  create mode 100644 tests/xfs/529.out
> 
> diff --git a/tests/xfs/529 b/tests/xfs/529
> new file mode 100755
> index 00000000..a44ce199
> --- /dev/null
> +++ b/tests/xfs/529
> @@ -0,0 +1,86 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> +#
> +# FS QA Test 529
> +#
> +# Verify that XFS does not cause inode fork's extent count to overflow when
> +# remapping extents from one file's inode fork to another.
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/reflink
> +. ./common/inject
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +_supported_fs xfs
> +_require_scratch
> +_require_scratch_reflink
> +_require_xfs_debug
> +_require_xfs_io_command "reflink"
> +_require_xfs_io_error_injection "reduce_max_iextents"
> +
> +echo "* Reflink remap extents"
> +
> +echo "Format and mount fs"
> +_scratch_mkfs >> $seqres.full
> +_scratch_mount >> $seqres.full
> +
> +bsize=$(_get_block_size $SCRATCH_MNT)
> +
> +srcfile=${SCRATCH_MNT}/srcfile
> +dstfile=${SCRATCH_MNT}/dstfile
> +
> +nr_blks=15
> +
> +echo "Create \$srcfile having an extent of length $nr_blks blocks"
> +xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
> +       -c fsync $srcfile >> $seqres.full
> +
> +echo "Create \$dstfile having an extent of length $nr_blks blocks"
> +xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
> +       -c fsync $dstfile >> $seqres.full
> +
> +echo "Inject reduce_max_iextents error tag"
> +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> +
> +echo "Reflink every other block from \$srcfile into \$dstfile"
> +for i in $(seq 1 2 $((nr_blks - 1))); do
> +	xfs_io -f -c "reflink $srcfile $((i * bsize)) $((i * bsize)) $bsize" \
> +	       $dstfile >> $seqres.full 2>&1
> +done
> +
> +ino=$(stat -c "%i" $dstfile)
> +
> +_scratch_unmount >> $seqres.full
> +
> +echo "Verify \$dstfile's extent count"
> +
> +nextents=$(_scratch_get_iext_count $ino data ||
> +		_fail "Unable to obtain inode fork's extent count")
> +if (( $nextents > 10 )); then
> +	echo "Extent count overflow check failed: nextents = $nextents"
> +fi

Generally looks fine, though many of the comments I've made about the
other patches (mkfs size, _get_file_block_size usage, etc.) apply here
too.

--D

> +# success, all done
> +status=0
> +exit
> diff --git a/tests/xfs/529.out b/tests/xfs/529.out
> new file mode 100644
> index 00000000..687a8bd2
> --- /dev/null
> +++ b/tests/xfs/529.out
> @@ -0,0 +1,8 @@
> +QA output created by 529
> +* Reflink remap extents
> +Format and mount fs
> +Create $srcfile having an extent of length 15 blocks
> +Create $dstfile having an extent of length 15 blocks
> +Inject reduce_max_iextents error tag
> +Reflink every other block from $srcfile into $dstfile
> +Verify $dstfile's extent count
> diff --git a/tests/xfs/group b/tests/xfs/group
> index c85aac6b..bc3958b3 100644
> --- a/tests/xfs/group
> +++ b/tests/xfs/group
> @@ -526,3 +526,4 @@
>  526 auto quick dir hardlink symlink
>  527 auto quick
>  528 auto quick reflink
> +529 auto quick reflink
> -- 
> 2.28.0
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-14  0:24   ` Darrick J. Wong
@ 2020-11-17 14:12     ` Chandan Babu R
  2020-11-18  2:30       ` Darrick J. Wong
  0 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 14:12 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 5:54:20 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:56:54PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when adding a single extent while there's no possibility of
> > splitting an existing mapping (limited to non-realtime files).
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/522     | 214 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/522.out |  24 ++++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 239 insertions(+)
> >  create mode 100755 tests/xfs/522
> >  create mode 100644 tests/xfs/522.out
> > 
> > diff --git a/tests/xfs/522 b/tests/xfs/522
> > new file mode 100755
> > index 00000000..a54fe136
> > --- /dev/null
> > +++ b/tests/xfs/522
> > @@ -0,0 +1,214 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 522
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# adding a single extent while there's no possibility of splitting an existing
> > +# mapping (limited to non-realtime files).
> > +
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/quota
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_quota
> > +_require_xfs_debug
> > +_require_xfs_io_command "falloc"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > +
> > +delalloc_to_written_extent()
> > +{
> > +	echo "* Delalloc to written extent conversion"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	nr_blks=$((15 * 2))
> > +
> > +	echo "Create fragmented file"
> > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			   _fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +falloc_unwritten_extent()
> > +{
> > +	echo "* Fallocate of unwritten extents"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	nr_blks=$((15 * 2))
> > +
> > +	echo "Fallocate fragmented file"
> > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > +		xfs_io -f -c "falloc $((i * bsize)) $bsize" $testfile >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			   _fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +quota_inode_extend()
> > +{
> > +	echo "* Extend quota inodes"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount -o uquota >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	nr_blks=20
> > +
> > +	# This is a rough calculation; It doesn't take block headers into
> > +	# consideration.
> > +	# gdb -batch vmlinux -ex 'print sizeof(struct xfs_disk_dquot)'
> > +	# $1 = 104
> > +	nr_quotas_per_block=$((bsize / 104))
> 
> That's sizeof(xfs_dqblk_t) you want, and it's 136 bytes long.

Ah ok. I had missed that. Thanks for pointing that out.

> 
> > +	nr_quotas=$((nr_quotas_per_block * nr_blks))
> > +
> > +	echo "Extend uquota file"
> > +	for i in $(seq 0 $nr_quotas); do
> 
> You only have to initialize the first dquot in a dquot file block in
> order to allocate the whole block, so you could speed this up with
> "seq 0 $nr_quotas_per_block $nr_quotas".

Ok. Thanks for the suggestion.

> 
> > +		chown $i $testfile >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify uquota inode's extent count"
> > +	uquotino=$(_scratch_xfs_db -c sb -c "print uquotino")
> > +	uquotino=${uquotino##uquotino = }
> > +
> > +	nextents=$(_scratch_get_iext_count $uquotino data || \
> > +			   _fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +directio_write()
> > +{
> > +	echo "* Directio write"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	nr_blks=$((15 * 2))
> > +
> > +	echo "Create fragmented file via directio writes"
> > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > +		xfs_io -d -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> 
> $XFS_IO_PROG -d -f -s -c "pwrite ..." $testfile
> 
> "-s" is an undocumented flag that makes the writes synchronous.

Ok. I will fix that.

> 
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> 
> $XFS_IO_PROG -c 'stat' $testfile | grep nextents ?

I agree. I will replace the above with xfs_io's stat command. But for special
inodes like quota and realtime bitmap and summary inodes we would still
require the helper function to obtain the extent count.

> 
> > +			   _fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +delalloc_to_written_extent
> > +falloc_unwritten_extent
> > +quota_inode_extend
> > +directio_write
> 
> I wonder if these should be separate tests, since they each format the
> scratch fs?  Or could you format the scratch fs once and test four
> different files?

Quota inode test is the only one which requires bmap_alloc_minlen_extent
 error tag. Other tests here have the following pattern,
 - mkfs and mount fs
 - Fragment fs space
 - Inject reduce_max_iextents error tag
 - Work on a test file
   Here we allocate individual blocks.
 - Umount
 - Check inode fork extent count.
So we can have just one mkfs/mount overall by removing the testfile created by
each test and also quota inode test can be moved to the last so that
bmap_alloc_minlen_extent error tag can be applied only to that test.
 
> 
> --D
> 
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/522.out b/tests/xfs/522.out
> > new file mode 100644
> > index 00000000..98791aae
> > --- /dev/null
> > +++ b/tests/xfs/522.out
> > @@ -0,0 +1,24 @@
> > +QA output created by 522
> > +* Delalloc to written extent conversion
> > +Format and mount fs
> > +Inject reduce_max_iextents error tag
> > +Create fragmented file
> > +Verify $testfile's extent count
> > +* Fallocate of unwritten extents
> > +Format and mount fs
> > +Inject reduce_max_iextents error tag
> > +Fallocate fragmented file
> > +Verify $testfile's extent count
> > +* Extend quota inodes
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Extend uquota file
> > +Verify uquota inode's extent count
> > +* Directio write
> > +Format and mount fs
> > +Inject reduce_max_iextents error tag
> > +Create fragmented file via directio writes
> > +Verify $testfile's extent count
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index b89c0a4e..1831f0b5 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -519,3 +519,4 @@
> >  519 auto quick reflink
> >  520 auto quick reflink
> >  521 auto quick realtime growfs
> > +522 auto quick quota
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-14  0:18   ` Darrick J. Wong
@ 2020-11-17 14:22     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 14:22 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 5:48:13 AM IST Darrick J. Wong wrote:
> > Subject: xfs: Check for extent overflow when trivally adding a new extent
> 
> Why does patch 3 have the same subject as patch 2?  This confused
> my quiltish scripts. :(

Sorry, The tests in patch 2 and 3 test the functionality associated with
XFS_IEXT_ADD_NOSPLIT_CNT. I had decided to separate these tests from those in
patch 2 since the tests here required creating an RT volume. I will fix the
subject line before posting the next version.

> 
> On Fri, Nov 13, 2020 at 04:56:55PM +0530, Chandan Babu R wrote:
> > Verify that XFS does not cause inode fork's extent count to overflow
> > when adding a single extent while there's no possibility of splitting an
> > existing mapping (limited to realtime files only).
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/523     | 176 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/523.out |  18 +++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 195 insertions(+)
> >  create mode 100755 tests/xfs/523
> >  create mode 100644 tests/xfs/523.out
> > 
> > diff --git a/tests/xfs/523 b/tests/xfs/523
> > new file mode 100755
> > index 00000000..4f5b3584
> > --- /dev/null
> > +++ b/tests/xfs/523
> > @@ -0,0 +1,176 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 523
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# adding a single extent while there's no possibility of splitting an existing
> > +# mapping (limited to realtime files only).
> > +#
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	_scratch_unmount >> $seqres.full 2>&1
> > +	test -e "$rtdev" && losetup -d $rtdev >> $seqres.full 2>&1
> > +	rm -f $tmp.* $TEST_DIR/$seq.rtvol
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_test
> > +_require_xfs_debug
> > +_require_test_program "punch-alternating"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > +_require_scratch_nocheck
> > +
> > +grow_rtinodes()
> > +{
> > +	echo "* Test extending rt inodes"
> > +
> > +	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> > +	. $tmp.mkfs
> > +
> > +	echo "Create fake rt volume"
> > +	nr_bitmap_blks=25
> > +	nr_bits=$((nr_bitmap_blks * dbsize * 8))
> > +	rtextsz=$dbsize
> > +	rtdevsz=$((nr_bits * rtextsz))
> > +	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
> > +	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
> > +
> > +	echo "Format and mount rt volume"
> > +	export USE_EXTERNAL=yes
> > +	export SCRATCH_RTDEV=$rtdev
> 
> I'm frankly wondering if it's time to just turn this into a
> _scratch_synthesize_rtvol helper or something.

Ok. I will write the helper and invoke it from appropriate places in xfstests.

> 
> > +	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
> > +		      -r size=2M,extsize=${rtextsz} >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> 
> Can you accomplish this with fallocate?  Or better yet _fill_fs()?

Hmm. _fill_fs() would be a better candidate. I can then invoke
punch-alternating on all the files in the directory (passed as 2nd argument to
_fill_fs()) to create a fragmented filesystem. Thanks for the suggestion.

> 
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	echo "Grow realtime volume"
> > +	xfs_growfs -r $SCRATCH_MNT >> $seqres.full 2>&1
> 
> $XFS_GROWFS_PROG, not xfs_growfs

Ok. I will fix this.

> 
> > +	if [[ $? == 0 ]]; then
> > +		echo "Growfs succeeded; should have failed."
> > +		exit 1
> > +	fi
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify rbmino's and rsumino's extent count"
> > +	for rtino in rbmino rsumino; do
> > +		ino=$(_scratch_xfs_db -c sb -c "print $rtino")
> > +		ino=${ino##${rtino} = }
> > +		echo "$rtino = $ino" >> $seqres.full
> > +
> > +		nextents=$(_scratch_get_iext_count $ino data || \
> > +				_fail "Unable to obtain inode fork's extent count")
> 
> Aha, you use this helper for the rt inodes too.  Ok, disregard my
> comments for patch 1.
> 
> > +		if (( $nextents > 10 )); then
> > +			echo "Extent count overflow check failed: nextents = $nextents"
> > +			exit 1
> > +		fi
> > +	done
> > +
> > +	echo "Check filesystem"
> > +	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
> > +
> > +	losetup -d $rtdev
> > +	rm -f $TEST_DIR/$seq.rtvol
> > +
> > +	export USE_EXTERNAL=""
> > +	export SCRATCH_RTDEV=""
> > +}
> > +
> > +rtfile_extend()
> > +{
> > +	echo "* Test extending an rt file"
> > +
> > +	_scratch_mkfs | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> > +	. $tmp.mkfs
> 
> Are these separate functionality tests?  If so, should they be in
> separate test files?

Actually I will drop the rtfile_extend() test functionality since it takes the
same code path as the direct IO file operation tested in patch 2.

> 
> > +
> > +	echo "Create fake rt volume"
> > +	nr_blks=$((15 * 2))
> > +	rtextsz=$dbsize
> > +	rtdevsz=$((2 * nr_blks * rtextsz))
> > +	truncate -s $rtdevsz $TEST_DIR/$seq.rtvol
> > +	rtdev=$(_create_loop_device $TEST_DIR/$seq.rtvol)
> > +
> > +	echo "Format and mount rt volume"
> > +	export USE_EXTERNAL=yes
> > +	export SCRATCH_RTDEV=$rtdev
> > +	_scratch_mkfs -d size=$((1024 * 1024 * 1024)) \
> > +		      -r size=$rtdevsz >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> 
> $XFS_IO_PROG, not xfs_io.

Ok. I will fix this in all the test scripts in this patchset.

> 
> --D
> 
> > +
> > +	echo "Create fragmented file on rt volume"
> > +	testfile=$SCRATCH_MNT/testfile
> > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > +		xfs_io -Rf -c "pwrite $((i * dbsize)) $dbsize" -c fsync \
> > +		       $testfile >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +
> > +	echo "Check filesystem"
> > +	_check_xfs_filesystem $SCRATCH_DEV none $rtdev
> > +
> > +	losetup -d $rtdev
> > +	rm -f $TEST_DIR/$seq.rtvol
> > +
> > +	export USE_EXTERNAL=""
> > +	export SCRATCH_RTDEV=""
> > +}
> > +
> > +grow_rtinodes
> > +rtfile_extend
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/523.out b/tests/xfs/523.out
> > new file mode 100644
> > index 00000000..16b4e0ad
> > --- /dev/null
> > +++ b/tests/xfs/523.out
> > @@ -0,0 +1,18 @@
> > +QA output created by 523
> > +* Test extending rt inodes
> > +Create fake rt volume
> > +Format and mount rt volume
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Grow realtime volume
> > +Verify rbmino's and rsumino's extent count
> > +Check filesystem
> > +* Test extending an rt file
> > +Create fake rt volume
> > +Format and mount rt volume
> > +Inject reduce_max_iextents error tag
> > +Create fragmented file on rt volume
> > +Verify $testfile's extent count
> > +Check filesystem
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index 1831f0b5..018c70ef 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -520,3 +520,4 @@
> >  520 auto quick reflink
> >  521 auto quick realtime growfs
> >  522 auto quick quota
> > +523 auto quick realtime growfs
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/11] xfs: Check for extent overflow when punching a hole
  2020-11-14  0:28   ` Darrick J. Wong
@ 2020-11-17 14:26     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 14:26 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 5:58:12 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:56:56PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when punching out an extent.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/524     | 210 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/524.out |  25 ++++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 236 insertions(+)
> >  create mode 100755 tests/xfs/524
> >  create mode 100644 tests/xfs/524.out
> > 
> > diff --git a/tests/xfs/524 b/tests/xfs/524
> > new file mode 100755
> > index 00000000..9e140c99
> > --- /dev/null
> > +++ b/tests/xfs/524
> > @@ -0,0 +1,210 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 524
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# punching out an extent.
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_debug
> > +_require_xfs_io_command "finsert"
> > +_require_xfs_io_command "fcollapse"
> > +_require_xfs_io_command "fzero"
> 
> For completeness, should this also be testing funshare?

This script tests the limits imposed by XFS_IEXT_PUNCH_HOLE_CNT. funshare
causes xfs_reflink_end_cow_extent() to be invoked. Hence I will add that to
the script testing XFS_IEXT_REFLINK_END_COW_CNT.

> 
> > +_require_test_program "punch-alternating"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +
> > +punch_range()
> > +{
> > +	echo "* Fpunch regular file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> 
> I don't think you need a fresh format for each functional test.

Yes, you are right. We could have just one mkfs and mount followed by all test
operations.

> 
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	nr_blks=30
> > +
> > +	echo "Create \$testfile"
> > +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> > +	       -c sync $testfile  >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "fpunch alternating blocks"
> > +	$here/src/punch-alternating $testfile >> $seqres.full 2>&1
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data ||
> 
> ...and now that I keep seeing this unmount-getiextcount-mount dance, you
> probably should convert these to grab the extent count info online.

I agree. I will fix this up.

> 
> --D
> 
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +finsert_range()
> > +{
> > +	echo "* Finsert regular file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)	
> > +
> > +	nr_blks=30
> > +
> > +	echo "Create \$testfile"
> > +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> > +	       -c sync $testfile  >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Finsert at every other block offset"
> > +	for i in $(seq 1 2 $((nr_blks - 1))); do
> > +		xfs_io -f -c "finsert $((i * bsize)) $bsize" $testfile \
> > +		       >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = ${nextents}"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +fcollapse_range()
> > +{
> > +	echo "* Fcollapse regular file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)	
> > +
> > +	nr_blks=30
> > +
> > +	echo "Create \$testfile"
> > +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> > +	       -c sync $testfile  >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Fcollapse at every other block offset"
> > +	for i in $(seq 1 $((nr_blks / 2 - 1))); do
> > +		xfs_io -f -c "fcollapse $((i * bsize)) $bsize" $testfile \
> > +		       >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = ${nextents}"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +fzero_range()
> > +{
> > +	echo "* Fzero regular file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +	bsize=$(_get_block_size $SCRATCH_MNT)	
> > +
> > +	nr_blks=30
> > +
> > +	echo "Create \$testfile"
> > +	xfs_io -f -c "pwrite -b $((nr_blks * bsize)) 0 $((nr_blks * bsize))" \
> > +	       -c sync $testfile  >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Fzero at every other block offset"
> > +	for i in $(seq 1 2 $((nr_blks - 1))); do
> > +		xfs_io -f -c "fzero $((i * bsize)) $bsize" $testfile \
> > +		       >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = ${nextents}"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +punch_range
> > +finsert_range
> > +fcollapse_range
> > +fzero_range
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/524.out b/tests/xfs/524.out
> > new file mode 100644
> > index 00000000..58f7d7ae
> > --- /dev/null
> > +++ b/tests/xfs/524.out
> > @@ -0,0 +1,25 @@
> > +QA output created by 524
> > +* Fpunch regular file
> > +Format and mount fs
> > +Create $testfile
> > +Inject reduce_max_iextents error tag
> > +fpunch alternating blocks
> > +Verify $testfile's extent count
> > +* Finsert regular file
> > +Format and mount fs
> > +Create $testfile
> > +Inject reduce_max_iextents error tag
> > +Finsert at every other block offset
> > +Verify $testfile's extent count
> > +* Fcollapse regular file
> > +Format and mount fs
> > +Create $testfile
> > +Inject reduce_max_iextents error tag
> > +Fcollapse at every other block offset
> > +Verify $testfile's extent count
> > +* Fzero regular file
> > +Format and mount fs
> > +Create $testfile
> > +Inject reduce_max_iextents error tag
> > +Fzero at every other block offset
> > +Verify $testfile's extent count
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index 018c70ef..3fa38c36 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -521,3 +521,4 @@
> >  521 auto quick realtime growfs
> >  522 auto quick quota
> >  523 auto quick realtime growfs
> > +524 auto quick punch zero insert collapse
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs
  2020-11-14  0:34   ` Darrick J. Wong
@ 2020-11-17 14:30     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 14:30 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 6:04:40 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:56:57PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when adding/removing xattrs.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/525     | 154 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/525.out |  16 +++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 171 insertions(+)
> >  create mode 100755 tests/xfs/525
> >  create mode 100644 tests/xfs/525.out
> > 
> > diff --git a/tests/xfs/525 b/tests/xfs/525
> > new file mode 100755
> > index 00000000..1d5d6e7c
> > --- /dev/null
> > +++ b/tests/xfs/525
> > @@ -0,0 +1,154 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 525
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# Adding/removing xattrs.
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/attr
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_attrs
> > +_require_xfs_debug
> > +_require_test_program "punch-alternating"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > +
> > +attr_set()
> > +{
> > +	echo "* Set xattrs"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	echo "Create xattrs"
> > +
> > +	attr_len=$(uuidgen | wc -c)
> > +	nr_attrs=$((bsize * 20 / attr_len))
> > +	for i in $(seq 1 $nr_attrs); do
> > +		$SETFATTR_PROG -n "trusted.""$(uuidgen)" $testfile \
> 
> Does this test require UUIDs in the attr names?  Why wouldn't
> $(printf "%037d" $i) suffice for this purpose?

You are right. I can replace executing uuidgen with calls to printf.

> 
> Though if you insist upon using uuids, please call $UUIDGEN_PROG per
> fstest custom.
> 
> > +			 >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify uquota inode's extent count"
> 
> Huh?  I thought we were testing file attrs?

Sorry, I will fix that.

> 
> > +	nextents=$(_scratch_get_iext_count $testino attr || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +		exit 1
> > +	fi
> > +}
> > +
> > +attr_remove()
> > +{
> > +	echo "* Remove xattrs"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	naextents=0
> > +	last=""
> > +
> > +	attr_len=$(uuidgen | wc -c)
> > +	nr_attrs=$((bsize / attr_len))
> > +
> > +	echo "Create initial xattr extents"
> > +	while (( $naextents < 4 )); do
> > +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +		for i in $(seq 1 $nr_attrs); do
> > +			last="trusted.""$(uuidgen)"
> > +			$SETFATTR_PROG -n $last $testfile
> > +		done
> > +
> > +		_scratch_unmount >> $seqres.full
> > +
> > +		naextents=$(_scratch_get_iext_count $testino attr || \
> > +				_fail "Unable to obtain inode fork's extent count")
> > +
> > +		_scratch_mount >> $seqres.full
> > +	done
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Remove xattr to trigger -EFBIG"
> > +	$SETFATTR_PROG -x "$last" $testfile >> $seqres.full 2>&1
> > +	if [[ $? == 0 ]]; then
> > +		echo "Xattr removal succeeded; Should have failed "
> 
> So at this point the user has a file for which he can't ever remove the
> xattrs for fear of overflowing naextents.  The only way to clear this is
> to delete the file, so shouldn't you be testing that this succeeds?

Ok. I will add that. However there is another issue here. I think it would better
suited to discuss that w.r.t XFS_IEXT_DIR_MANIP_CNT tests (i.e. patch 6).

> 
> --D
> 
> > +		exit 1
> > +	fi
> > +}
> > +
> > +attr_set
> > +attr_remove
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/525.out b/tests/xfs/525.out
> > new file mode 100644
> > index 00000000..cc40e6e2
> > --- /dev/null
> > +++ b/tests/xfs/525.out
> > @@ -0,0 +1,16 @@
> > +QA output created by 525
> > +* Set xattrs
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Create xattrs
> > +Verify uquota inode's extent count
> > +* Remove xattrs
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Create initial xattr extents
> > +Inject reduce_max_iextents error tag
> > +Remove xattr to trigger -EFBIG
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index 3fa38c36..bd38aff0 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -522,3 +522,4 @@
> >  522 auto quick quota
> >  523 auto quick realtime growfs
> >  524 auto quick punch zero insert collapse
> > +525 auto quick attr
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries
  2020-11-14  0:37   ` Darrick J. Wong
@ 2020-11-17 14:50     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 14:50 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 6:07:54 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:56:58PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when adding/removing directory entries.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/526     | 360 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/526.out |  47 ++++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 408 insertions(+)
> >  create mode 100755 tests/xfs/526
> >  create mode 100644 tests/xfs/526.out
> > 
> > diff --git a/tests/xfs/526 b/tests/xfs/526
> > new file mode 100755
> > index 00000000..39cfbcf8
> > --- /dev/null
> > +++ b/tests/xfs/526
> > @@ -0,0 +1,360 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 526
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# adding/removing directory entries.
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_debug
> > +_require_test_program "punch-alternating"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > +
> > +_scratch_mkfs_sized $((1024 * 1024 * 1024)) | _filter_mkfs >> $seqres.full 2> $tmp.mkfs
> > +. $tmp.mkfs
> > +
> > +dir_entry_create()
> > +{
> > +	echo "* Create directory entries"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> 
> Same questions as I've had for all the other tests -- why is it critical to
> reformat between each test?  Why is it necessary to encode uuids in the
> attr/dir names?

I will replace uuids with output from printf.

However w.r.t not reformatting the filesystem between each test, we need to
look into one issue that occurs when executing either of dir_entry_rename_src
and dir_entry_remove tests. Please see dir_entry_remove below for an
explanation.

> 
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	echo "Create directory entries"
> > +	dent_len=$(uuidgen | wc -c)
> 
> Also, it'll explode the directories faster if you use maximal length
> names (255) instead of uuids (37).
> 
> The same applies to the xattr tests in the previous patch.

Thanks for the suggestion. I will implement it in the next version of the
patchset.

> 
> > +	nr_dents=$((dbsize * 20 / dent_len))
> > +	for i in $(seq 1 $nr_dents); do
> > +		touch $SCRATCH_MNT/$(uuidgen) >> $seqres.full 2>&1 || break
> > +	done
> > +
> > +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify directory's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $dirino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +dir_entry_rename_dst()
> > +{
> > +	echo "* Rename: Populate destination directory"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	dstdir=$SCRATCH_MNT/dstdir
> > +	mkdir $dstdir
> > +
> > +	dent_len=$(uuidgen | wc -c)
> > +	nr_dents=$((dirbsize * 20 / dent_len))
> > +
> > +	echo "Populate \$dstdir by mv-ing new directory entries"
> > +	for i in $(seq 1 $nr_dents); do
> > +		file=${SCRATCH_MNT}/$(uuidgen)
> > +		touch $file || break
> > +		mv $file $dstdir >> $seqres.full 2>&1 || break
> > +	done
> > +
> > +	dirino=$(stat -c "%i" $dstdir)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$dstdir's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $dirino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +dir_entry_rename_src()
> > +{
> > +	echo "* Rename: Populate source directory and mv one entry to destination directory"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	srcdir=${SCRATCH_MNT}/srcdir
> > +	dstdir=${SCRATCH_MNT}/dstdir
> > +
> > +	mkdir $srcdir $dstdir
> > +
> > +	dirino=$(stat -c "%i" $srcdir)
> > +
> > +	dent_len=$(uuidgen | wc -c)
> > +	nr_dents=$((dirbsize / dent_len))
> > +	nextents=0
> > +	last=""
> > +
> > +	echo "Populate \$srcdir with atleast 4 extents"
> > +	while (( $nextents < 4 )); do
> > +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +		for i in $(seq 1 $nr_dents); do
> > +			last=${srcdir}/$(uuidgen)
> > +			touch $last || break
> > +		done
> > +
> > +		_scratch_unmount >> $seqres.full
> > +
> > +		nextents=$(_scratch_get_iext_count $dirino data || \
> > +				_fail "Unable to obtain inode fork's extent count")
> > +
> > +		_scratch_mount >> $seqres.full
> > +	done
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Move an entry from \$srcdir to trigger -EFBIG"
> > +	mv $last $dstdir >> $seqres.full 2>&1
> > +	if [[ $? == 0 ]]; then
> > +		echo "Moving from \$srcdir to \$dstdir succeeded; Should have failed"
> > +	fi
> > +
> > +	_scratch_unmount >> $seqres.full
> > +}
> > +
> > +dir_entry_create_hard_links()
> > +{
> > +	echo "* Create multiple hard links to a single file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	dent_len=$(uuidgen | wc -c)
> > +	nr_dents=$((dirbsize * 20 / dent_len))
> > +
> > +	echo "Create multiple hardlinks"
> > +	for i in $(seq 1 $nr_dents); do
> > +		ln $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break
> > +	done
> > +
> > +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify directory's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $dirino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +dir_entry_create_symlinks()
> > +{
> > +	echo "* Create multiple symbolic links to a single file"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +	dent_len=$(uuidgen | wc -c)
> > +	nr_dents=$((dirbsize * 20 / dent_len))
> > +
> > +	echo "Create multiple symbolic links"
> > +	for i in $(seq 1 $nr_dents); do
> > +		ln -s $testfile ${SCRATCH_MNT}/$(uuidgen) >> $seqres.full 2>&1 || break;
> > +	done
> > +
> > +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify directory's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $dirino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +dir_entry_remove()
> > +{
> > +	echo "* Populate a directory and remove one entry"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	testfile=$SCRATCH_MNT/testfile
> > +
> > +	echo "Consume free space"
> > +	dd if=/dev/zero of=${testfile} bs=${dbsize} >> $seqres.full 2>&1
> > +	sync
> > +
> > +	echo "Create fragmented filesystem"
> > +	$here/src/punch-alternating $testfile >> $seqres.full
> > +	sync
> > +
> > +	dirino=$(stat -c "%i" $SCRATCH_MNT)
> > +
> > +	dent_len=$(uuidgen | wc -c)
> > +	nr_dents=$((dirbsize / dent_len))
> > +	nextents=0
> > +	last=""
> > +
> > +	echo "Populate directory with atleast 4 extents"
> > +	while (( $nextents < 4 )); do
> > +		xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +		for i in $(seq 1 $nr_dents); do
> > +			last=${SCRATCH_MNT}/$(uuidgen)
> > +			touch $last || break
> > +		done
> > +
> > +		_scratch_unmount >> $seqres.full
> > +
> > +		nextents=$(_scratch_get_iext_count $dirino data || \
> > +				_fail "Unable to obtain inode fork's extent count")
> > +
> > +		_scratch_mount >> $seqres.full
> > +	done
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +	echo "Remove an entry from directory to trigger -EFBIG"
> > +	rm $last >> $seqres.full 2>&1
> > +	if [[ $? == 0 ]]; then
> > +		echo "Removing file succeeded; Should have failed"
> > +	fi
> > +
> > +	_scratch_unmount >> $seqres.full
> > +}

In the above function we create a directory with atleast 4 extents and this is
executed without the pseudo max extent limits enabled. Later the function
injects reduce_max_iextents error tag and since 4 + (XFS_DA_NODE_MAXDEPTH + 1
+ 1) = 4 + (5 + 1 + 1) = 11 > 10 (pseudo max limit) the directory entry remove
operation execute later would fail. This also would mean that the parent
directory cannot be deleted with the error tag enabled. This scenario would
not occur in production work load since the extent count limit is always
enabled as against enabling it at a later stage as is being done in this test.

This is different from the attr_remove() test from patch 5 where it is
possible to remove the file even though the corresponding xattr cannot be
removed.

Hence, I could either unmount and mount the filesystem so that the parent
directory can be removed or I could create the filesystem anew.

> > +
> > +# Filesystems with directory block size greater than one FSB will not be tested,
> > +# since "7 (i.e. XFS_DA_NODE_MAXDEPTH + 1 data block + 1 free block) * 2 (fsb
> > +# count) = 14" is greater than the pseudo max extent count limit of 10.
> > +# Extending the pseudo max limit won't help either.  Consider the case where 1
> > +# FSB is 1k in size and 1 dir block is 64k in size (i.e. fsb count = 64). In
> > +# this case, the pseudo max limit has to be greater than 7 * 64 = 448 extents.
> > +if (( $dbsize != $dirbsize )); then
> > +	_notrun "FSB size ($dbsize) and directory block size ($dirbsize) do not match"
> 
> Heh, I had wondered about that.  Good that you caught this here!
> 
> --D
> 
> > +fi
> > +
> > +dir_entry_create
> > +dir_entry_rename_dst
> > +dir_entry_rename_src
> > +dir_entry_create_hard_links
> > +dir_entry_create_symlinks
> > +dir_entry_remove
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/526.out b/tests/xfs/526.out
> > new file mode 100644
> > index 00000000..21f77cd8
> > --- /dev/null
> > +++ b/tests/xfs/526.out
> > @@ -0,0 +1,47 @@
> > +QA output created by 526
> > +* Create directory entries
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Create directory entries
> > +Verify directory's extent count
> > +* Rename: Populate destination directory
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Populate $dstdir by mv-ing new directory entries
> > +Verify $dstdir's extent count
> > +* Rename: Populate source directory and mv one entry to destination directory
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Populate $srcdir with atleast 4 extents
> > +Inject reduce_max_iextents error tag
> > +Move an entry from $srcdir to trigger -EFBIG
> > +* Create multiple hard links to a single file
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Create multiple hardlinks
> > +Verify directory's extent count
> > +* Create multiple symbolic links to a single file
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject reduce_max_iextents error tag
> > +Inject bmap_alloc_minlen_extent error tag
> > +Create multiple symbolic links
> > +Verify directory's extent count
> > +* Populate a directory and remove one entry
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Populate directory with atleast 4 extents
> > +Inject reduce_max_iextents error tag
> > +Remove an entry from directory to trigger -EFBIG
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index bd38aff0..d089797b 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -523,3 +523,4 @@
> >  523 auto quick realtime growfs
> >  524 auto quick punch zero insert collapse
> >  525 auto quick attr
> > +526 auto quick dir hardlink symlink
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent
  2020-11-14  0:39   ` Darrick J. Wong
@ 2020-11-17 15:15     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 15:15 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 6:09:18 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:56:59PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when writing to an unwritten extent.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/527     | 125 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/527.out |  13 +++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 139 insertions(+)
> >  create mode 100755 tests/xfs/527
> >  create mode 100644 tests/xfs/527.out
> > 
> > diff --git a/tests/xfs/527 b/tests/xfs/527
> > new file mode 100755
> > index 00000000..f040aee4
> > --- /dev/null
> > +++ b/tests/xfs/527
> > @@ -0,0 +1,125 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 527
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# writing to an unwritten extent.
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_debug
> > +_require_xfs_io_command "falloc"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +
> > +buffered_write_to_unwritten_extent()
> 
> This is nearly the same as the directio write test; could you combine
> them into a single function so we have fewer functions to maintain?

Ok. I will do that.

> 
> --D
> 
> > +{
> > +	echo "* Buffered write to unwritten extent"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	testfile=${SCRATCH_MNT}/testfile
> > +
> > +	nr_blks=15
> > +
> > +	echo "Fallocate $nr_blks blocks"
> > +	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
> > +
> > +	echo "Buffered write to every other block of fallocated space"
> > +	for i in $(seq 1 2 $((nr_blks - 1))); do
> > +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile \
> > +		       >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +direct_write_to_unwritten_extent()
> > +{
> > +	echo "* Direct I/O write to unwritten extent"
> > +
> > +	echo "Format and mount fs"
> > +	_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> > +	_scratch_mount >> $seqres.full
> > +
> > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +	testfile=${SCRATCH_MNT}/testfile
> > +
> > +	nr_blks=15
> > +
> > +	echo "Fallocate $nr_blks blocks"
> > +	xfs_io -f -c "falloc 0 $((nr_blks * bsize))" $testfile >> $seqres.full
> > +
> > +	echo "Inject reduce_max_iextents error tag"
> > +	xfs_io -x -c "inject reduce_max_iextents" $SCRATCH_MNT
> > +
> > +	echo "Direct I/O write to every other block of fallocated space"
> > +	for i in $(seq 1 2 $((nr_blks - 1))); do
> > +		xfs_io -f -d -c "pwrite $((i * bsize)) $bsize" $testfile \
> > +		       >> $seqres.full 2>&1
> > +		[[ $? != 0 ]] && break
> > +	done
> > +
> > +	testino=$(stat -c "%i" $testfile)
> > +
> > +	_scratch_unmount >> $seqres.full
> > +
> > +	echo "Verify \$testfile's extent count"
> > +
> > +	nextents=$(_scratch_get_iext_count $testino data || \
> > +			_fail "Unable to obtain inode fork's extent count")
> > +	if (( $nextents > 10 )); then
> > +		echo "Extent count overflow check failed: nextents = $nextents"
> > +	fi
> > +}
> > +
> > +buffered_write_to_unwritten_extent
> > +direct_write_to_unwritten_extent
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/527.out b/tests/xfs/527.out
> > new file mode 100644
> > index 00000000..6aa5e9ed
> > --- /dev/null
> > +++ b/tests/xfs/527.out
> > @@ -0,0 +1,13 @@
> > +QA output created by 527
> > +* Buffered write to unwritten extent
> > +Format and mount fs
> > +Fallocate 15 blocks
> > +Inject reduce_max_iextents error tag
> > +Buffered write to every other block of fallocated space
> > +Verify $testfile's extent count
> > +* Direct I/O write to unwritten extent
> > +Format and mount fs
> > +Fallocate 15 blocks
> > +Inject reduce_max_iextents error tag
> > +Direct I/O write to every other block of fallocated space
> > +Verify $testfile's extent count
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index d089797b..627813fe 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -524,3 +524,4 @@
> >  524 auto quick punch zero insert collapse
> >  525 auto quick attr
> >  526 auto quick dir hardlink symlink
> > +527 auto quick
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled
  2020-11-14  0:06   ` Darrick J. Wong
@ 2020-11-17 15:24     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 15:24 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 5:36:02 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:57:03PM +0530, Chandan Babu R wrote:
> > This commit adds a stress test that executes fsstress with
> > bmap_alloc_minlen_extent error tag enabled.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/531     | 85 +++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/531.out |  6 ++++
> >  tests/xfs/group   |  1 +
> >  3 files changed, 92 insertions(+)
> >  create mode 100755 tests/xfs/531
> >  create mode 100644 tests/xfs/531.out
> > 
> > diff --git a/tests/xfs/531 b/tests/xfs/531
> > new file mode 100755
> > index 00000000..e846cc0e
> > --- /dev/null
> > +++ b/tests/xfs/531
> > @@ -0,0 +1,85 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 531
> > +#
> > +# Execute fsstress with bmap_alloc_minlen_extent error tag enabled.
> > +#
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_debug
> > +_require_test_program "punch-alternating"
> > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > +
> > +echo "Format and mount fs"
> > +_scratch_mkfs_sized $((1024 * 1024 * 1024)) >> $seqres.full
> 
> Why is a 1G fs required?

With the sparse file occupying almost half of the filesystem space, fsstress
will have only remaining half of the space to work with. With 1GiB sized
filesystem, fsstress can have ~512MiB of free space.

> 
> > +_scratch_mount >> $seqres.full
> > +
> > +bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +testfile=$SCRATCH_MNT/testfile
> > +
> > +echo "Consume free space"
> > +dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > +sync
> > +
> > +echo "Create fragmented filesystem"
> > +$here/src/punch-alternating $testfile >> $seqres.full
> > +sync
> > +
> > +echo "Inject bmap_alloc_minlen_extent error tag"
> > +xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > +
> > +echo "Execute fsstress in background"
> > +$FSSTRESS_PROG -d $SCRATCH_MNT -p128 -n999999999 \
> 
> -n and -p ought to be computed from TIME_FACTOR and LOAD_FACTOR.

Ok. I will fix that.

> 
> --D
> 
> > +		 -f bulkstat=0 \
> > +		 -f bulkstat1=0 \
> > +		 -f fiemap=0 \
> > +		 -f getattr=0 \
> > +		 -f getdents=0 \
> > +		 -f getfattr=0 \
> > +		 -f listfattr=0 \
> > +		 -f mread=0 \
> > +		 -f read=0 \
> > +		 -f readlink=0 \
> > +		 -f readv=0 \
> > +		 -f stat=0 \
> > +		 -f aread=0 \
> > +		 -f dread=0 > /dev/null 2>&1 &
> > +
> > +fsstress_pid=$!
> > +sleep 2m
> > +
> > +echo "Killing fsstress process $fsstress_pid ..." >> $seqres.full
> > +kill $fsstress_pid >> $seqres.full
> > +wait $fsstress_pid
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/531.out b/tests/xfs/531.out
> > new file mode 100644
> > index 00000000..e0a419c2
> > --- /dev/null
> > +++ b/tests/xfs/531.out
> > @@ -0,0 +1,6 @@
> > +QA output created by 531
> > +Format and mount fs
> > +Consume free space
> > +Create fragmented filesystem
> > +Inject bmap_alloc_minlen_extent error tag
> > +Execute fsstress in background
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index 81a15582..f4cb5af6 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -528,3 +528,4 @@
> >  528 auto quick reflink
> >  529 auto quick reflink
> >  530 auto quick
> > +531 auto stress
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 10/11] xfs: Check for extent overflow when swapping extents
  2020-11-14  0:08   ` Darrick J. Wong
@ 2020-11-17 15:35     ` Chandan Babu R
  2020-11-18  2:23       ` Darrick J. Wong
  0 siblings, 1 reply; 36+ messages in thread
From: Chandan Babu R @ 2020-11-17 15:35 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 5:38:35 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:57:02PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when swapping forks across two files.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/530     | 115 ++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/530.out |  13 ++++++
> >  tests/xfs/group   |   1 +
> >  3 files changed, 129 insertions(+)
> >  create mode 100755 tests/xfs/530
> >  create mode 100644 tests/xfs/530.out
> > 
> > diff --git a/tests/xfs/530 b/tests/xfs/530
> > new file mode 100755
> > index 00000000..fccc6de7
> > --- /dev/null
> > +++ b/tests/xfs/530
> > @@ -0,0 +1,115 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 530
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# swapping forks between files
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_xfs_debug
> > +_require_xfs_scratch_rmapbt
> > +_require_xfs_io_command "fcollapse"
> > +_require_xfs_io_command "swapext"
> 
> FWIW it's going to be a while before the swapext command goes upstream.
> Right now it's a part of the atomic file range exchange patchset.

Sorry, I didn't understand your statement. I have the following from my Linux
machine,

root@debian-guest:~# /sbin/xfs_io 
xfs_io> help swapext
swapext <donorfile> -- Swap extents between files.

 Swaps extents between the open file descriptor and the supplied filename.

The above command causes the following code path to be invoked inside the
kernel (assuming rmapbt feature is enabled),
xfs_ioc_swapext() => xfs_swap_extents() => xfs_swap_extent_rmap().

> 
> Do you want me to try to speed that up?
> 
> --D
> 
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +
> > +echo "* Swap extent forks"
> > +
> > +echo "Format and mount fs"
> > +_scratch_mkfs >> $seqres.full
> > +_scratch_mount >> $seqres.full
> > +
> > +bsize=$(_get_block_size $SCRATCH_MNT)
> > +
> > +srcfile=${SCRATCH_MNT}/srcfile
> > +donorfile=${SCRATCH_MNT}/donorfile
> > +
> > +echo "Create \$donorfile having an extent of length 17 blocks"
> > +xfs_io -f -c "pwrite -b $((17 * bsize)) 0 $((17 * bsize))" -c fsync $donorfile \
> > +       >> $seqres.full
> > +
> > +# After the for loop the donor file will have the following extent layout
> > +# | 0-4 | 5 | 6 | 7 | 8 | 9 | 10 |
> > +echo "Fragment \$donorfile"
> > +for i in $(seq 5 10); do
> > +	start_offset=$((i * bsize))
> > +	xfs_io -f -c "fcollapse $start_offset $bsize" $donorfile >> $seqres.full
> > +done
> > +donorino=$(stat -c "%i" $donorfile)
> > +
> > +echo "Create \$srcfile having an extent of length 18 blocks"
> > +xfs_io -f -c "pwrite -b $((18 * bsize)) 0 $((18 * bsize))" -c fsync $srcfile \
> > +       >> $seqres.full
> > +
> > +echo "Fragment \$srcfile"
> > +# After the for loop the src file will have the following extent layout
> > +# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7-10 |
> > +for i in $(seq 1 7); do
> > +	start_offset=$((i * bsize))
> > +	xfs_io -f -c "fcollapse $start_offset $bsize" $srcfile >> $seqres.full
> > +done
> > +srcino=$(stat -c "%i" $srcfile)
> > +
> > +_scratch_unmount >> $seqres.full
> > +
> > +echo "Collect \$donorfile's extent count"
> > +donor_nr_exts=$(_scratch_get_iext_count $donorino data || \
> > +		_fail "Unable to obtain inode fork's extent count")
> > +
> > +echo "Collect \$srcfile's extent count"
> > +src_nr_exts=$(_scratch_get_iext_count $srcino data || \
> > +		_fail "Unable to obtain inode fork's extent count")
> > +
> > +_scratch_mount >> $seqres.full
> > +
> > +echo "Inject reduce_max_iextents error tag"
> > +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +echo "Swap \$srcfile's and \$donorfile's extent forks"
> > +xfs_io -f -c "swapext $donorfile" $srcfile >> $seqres.full 2>&1
> > +
> > +_scratch_unmount >> $seqres.full
> > +
> > +echo "Check for \$donorfile's extent count overflow"
> > +nextents=$(_scratch_get_iext_count $donorino data || \
> > +		_fail "Unable to obtain inode fork's extent count")
> > +if (( $nextents == $src_nr_exts )); then
> > +	echo "\$donorfile: Extent count overflow check failed"
> > +fi
> > +
> > +echo "Check for \$srcfile's extent count overflow"
> > +nextents=$(_scratch_get_iext_count $srcino data || \
> > +		_fail "Unable to obtain inode fork's extent count")
> > +if (( $nextents == $donor_nr_exts )); then
> > +	echo "\$srcfile: Extent count overflow check failed"
> > +fi
> > +
> > +# success, all done
> > +status=0
> > +exit
> > diff --git a/tests/xfs/530.out b/tests/xfs/530.out
> > new file mode 100644
> > index 00000000..996af959
> > --- /dev/null
> > +++ b/tests/xfs/530.out
> > @@ -0,0 +1,13 @@
> > +QA output created by 530
> > +* Swap extent forks
> > +Format and mount fs
> > +Create $donorfile having an extent of length 17 blocks
> > +Fragment $donorfile
> > +Create $srcfile having an extent of length 18 blocks
> > +Fragment $srcfile
> > +Collect $donorfile's extent count
> > +Collect $srcfile's extent count
> > +Inject reduce_max_iextents error tag
> > +Swap $srcfile's and $donorfile's extent forks
> > +Check for $donorfile's extent count overflow
> > +Check for $srcfile's extent count overflow
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index bc3958b3..81a15582 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -527,3 +527,4 @@
> >  527 auto quick
> >  528 auto quick reflink
> >  529 auto quick reflink
> > +530 auto quick
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 10/11] xfs: Check for extent overflow when swapping extents
  2020-11-17 15:35     ` Chandan Babu R
@ 2020-11-18  2:23       ` Darrick J. Wong
  0 siblings, 0 replies; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-18  2:23 UTC (permalink / raw)
  To: Chandan Babu R, t; +Cc: fstests, linux-xfs

On Tue, Nov 17, 2020 at 09:05:25PM +0530, Chandan Babu R wrote:
> On Saturday 14 November 2020 5:38:35 AM IST Darrick J. Wong wrote:
> > On Fri, Nov 13, 2020 at 04:57:02PM +0530, Chandan Babu R wrote:
> > > This test verifies that XFS does not cause inode fork's extent count to
> > > overflow when swapping forks across two files.
> > > 
> > > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > > ---
> > >  tests/xfs/530     | 115 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  tests/xfs/530.out |  13 ++++++
> > >  tests/xfs/group   |   1 +
> > >  3 files changed, 129 insertions(+)
> > >  create mode 100755 tests/xfs/530
> > >  create mode 100644 tests/xfs/530.out
> > > 
> > > diff --git a/tests/xfs/530 b/tests/xfs/530
> > > new file mode 100755
> > > index 00000000..fccc6de7
> > > --- /dev/null
> > > +++ b/tests/xfs/530
> > > @@ -0,0 +1,115 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > > +#
> > > +# FS QA Test 530
> > > +#
> > > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > > +# swapping forks between files
> > > +seq=`basename $0`
> > > +seqres=$RESULT_DIR/$seq
> > > +echo "QA output created by $seq"
> > > +
> > > +here=`pwd`
> > > +tmp=/tmp/$$
> > > +status=1	# failure is the default!
> > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > +
> > > +_cleanup()
> > > +{
> > > +	cd /
> > > +	rm -f $tmp.*
> > > +}
> > > +
> > > +# get standard environment, filters and checks
> > > +. ./common/rc
> > > +. ./common/filter
> > > +. ./common/inject
> > > +
> > > +# remove previous $seqres.full before test
> > > +rm -f $seqres.full
> > > +
> > > +# real QA test starts here
> > > +
> > > +_supported_fs xfs
> > > +_require_scratch
> > > +_require_xfs_debug
> > > +_require_xfs_scratch_rmapbt
> > > +_require_xfs_io_command "fcollapse"
> > > +_require_xfs_io_command "swapext"
> > 
> > FWIW it's going to be a while before the swapext command goes upstream.
> > Right now it's a part of the atomic file range exchange patchset.
> 
> Sorry, I didn't understand your statement. I have the following from my Linux
> machine,
> 
> root@debian-guest:~# /sbin/xfs_io 
> xfs_io> help swapext
> swapext <donorfile> -- Swap extents between files.
> 
>  Swaps extents between the open file descriptor and the supplied filename.
> 
> The above command causes the following code path to be invoked inside the
> kernel (assuming rmapbt feature is enabled),
> xfs_ioc_swapext() => xfs_swap_extents() => xfs_swap_extent_rmap().

Oops.  I forgot that my atomic extent swap series *enhances* that
command.  Please disregard the above. :/

--D

> > 
> > Do you want me to try to speed that up?
> > 
> > --D
> > 
> > > +_require_xfs_io_error_injection "reduce_max_iextents"
> > > +
> > > +echo "* Swap extent forks"
> > > +
> > > +echo "Format and mount fs"
> > > +_scratch_mkfs >> $seqres.full
> > > +_scratch_mount >> $seqres.full
> > > +
> > > +bsize=$(_get_block_size $SCRATCH_MNT)
> > > +
> > > +srcfile=${SCRATCH_MNT}/srcfile
> > > +donorfile=${SCRATCH_MNT}/donorfile
> > > +
> > > +echo "Create \$donorfile having an extent of length 17 blocks"
> > > +xfs_io -f -c "pwrite -b $((17 * bsize)) 0 $((17 * bsize))" -c fsync $donorfile \
> > > +       >> $seqres.full
> > > +
> > > +# After the for loop the donor file will have the following extent layout
> > > +# | 0-4 | 5 | 6 | 7 | 8 | 9 | 10 |
> > > +echo "Fragment \$donorfile"
> > > +for i in $(seq 5 10); do
> > > +	start_offset=$((i * bsize))
> > > +	xfs_io -f -c "fcollapse $start_offset $bsize" $donorfile >> $seqres.full
> > > +done
> > > +donorino=$(stat -c "%i" $donorfile)
> > > +
> > > +echo "Create \$srcfile having an extent of length 18 blocks"
> > > +xfs_io -f -c "pwrite -b $((18 * bsize)) 0 $((18 * bsize))" -c fsync $srcfile \
> > > +       >> $seqres.full
> > > +
> > > +echo "Fragment \$srcfile"
> > > +# After the for loop the src file will have the following extent layout
> > > +# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7-10 |
> > > +for i in $(seq 1 7); do
> > > +	start_offset=$((i * bsize))
> > > +	xfs_io -f -c "fcollapse $start_offset $bsize" $srcfile >> $seqres.full
> > > +done
> > > +srcino=$(stat -c "%i" $srcfile)
> > > +
> > > +_scratch_unmount >> $seqres.full
> > > +
> > > +echo "Collect \$donorfile's extent count"
> > > +donor_nr_exts=$(_scratch_get_iext_count $donorino data || \
> > > +		_fail "Unable to obtain inode fork's extent count")
> > > +
> > > +echo "Collect \$srcfile's extent count"
> > > +src_nr_exts=$(_scratch_get_iext_count $srcino data || \
> > > +		_fail "Unable to obtain inode fork's extent count")
> > > +
> > > +_scratch_mount >> $seqres.full
> > > +
> > > +echo "Inject reduce_max_iextents error tag"
> > > +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > +
> > > +echo "Swap \$srcfile's and \$donorfile's extent forks"
> > > +xfs_io -f -c "swapext $donorfile" $srcfile >> $seqres.full 2>&1
> > > +
> > > +_scratch_unmount >> $seqres.full
> > > +
> > > +echo "Check for \$donorfile's extent count overflow"
> > > +nextents=$(_scratch_get_iext_count $donorino data || \
> > > +		_fail "Unable to obtain inode fork's extent count")
> > > +if (( $nextents == $src_nr_exts )); then
> > > +	echo "\$donorfile: Extent count overflow check failed"
> > > +fi
> > > +
> > > +echo "Check for \$srcfile's extent count overflow"
> > > +nextents=$(_scratch_get_iext_count $srcino data || \
> > > +		_fail "Unable to obtain inode fork's extent count")
> > > +if (( $nextents == $donor_nr_exts )); then
> > > +	echo "\$srcfile: Extent count overflow check failed"
> > > +fi
> > > +
> > > +# success, all done
> > > +status=0
> > > +exit
> > > diff --git a/tests/xfs/530.out b/tests/xfs/530.out
> > > new file mode 100644
> > > index 00000000..996af959
> > > --- /dev/null
> > > +++ b/tests/xfs/530.out
> > > @@ -0,0 +1,13 @@
> > > +QA output created by 530
> > > +* Swap extent forks
> > > +Format and mount fs
> > > +Create $donorfile having an extent of length 17 blocks
> > > +Fragment $donorfile
> > > +Create $srcfile having an extent of length 18 blocks
> > > +Fragment $srcfile
> > > +Collect $donorfile's extent count
> > > +Collect $srcfile's extent count
> > > +Inject reduce_max_iextents error tag
> > > +Swap $srcfile's and $donorfile's extent forks
> > > +Check for $donorfile's extent count overflow
> > > +Check for $srcfile's extent count overflow
> > > diff --git a/tests/xfs/group b/tests/xfs/group
> > > index bc3958b3..81a15582 100644
> > > --- a/tests/xfs/group
> > > +++ b/tests/xfs/group
> > > @@ -527,3 +527,4 @@
> > >  527 auto quick
> > >  528 auto quick reflink
> > >  529 auto quick reflink
> > > +530 auto quick
> > 
> 
> 
> -- 
> chandan
> 
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-17 14:12     ` Chandan Babu R
@ 2020-11-18  2:30       ` Darrick J. Wong
  2020-11-18  4:09         ` Chandan Babu R
  0 siblings, 1 reply; 36+ messages in thread
From: Darrick J. Wong @ 2020-11-18  2:30 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: fstests, linux-xfs

On Tue, Nov 17, 2020 at 07:42:45PM +0530, Chandan Babu R wrote:
> On Saturday 14 November 2020 5:54:20 AM IST Darrick J. Wong wrote:
> > On Fri, Nov 13, 2020 at 04:56:54PM +0530, Chandan Babu R wrote:
> > > This test verifies that XFS does not cause inode fork's extent count to
> > > overflow when adding a single extent while there's no possibility of
> > > splitting an existing mapping (limited to non-realtime files).
> > > 
> > > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > > ---
> > >  tests/xfs/522     | 214 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  tests/xfs/522.out |  24 ++++++
> > >  tests/xfs/group   |   1 +
> > >  3 files changed, 239 insertions(+)
> > >  create mode 100755 tests/xfs/522
> > >  create mode 100644 tests/xfs/522.out
> > > 
> > > diff --git a/tests/xfs/522 b/tests/xfs/522
> > > new file mode 100755
> > > index 00000000..a54fe136
> > > --- /dev/null
> > > +++ b/tests/xfs/522
> > > @@ -0,0 +1,214 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > > +#
> > > +# FS QA Test 522
> > > +#
> > > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > > +# adding a single extent while there's no possibility of splitting an existing
> > > +# mapping (limited to non-realtime files).
> > > +
> > > +seq=`basename $0`
> > > +seqres=$RESULT_DIR/$seq
> > > +echo "QA output created by $seq"
> > > +
> > > +here=`pwd`
> > > +tmp=/tmp/$$
> > > +status=1	# failure is the default!
> > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > +
> > > +_cleanup()
> > > +{
> > > +	cd /
> > > +	rm -f $tmp.*
> > > +}
> > > +
> > > +# get standard environment, filters and checks
> > > +. ./common/rc
> > > +. ./common/filter
> > > +. ./common/quota
> > > +. ./common/inject
> > > +
> > > +# remove previous $seqres.full before test
> > > +rm -f $seqres.full
> > > +
> > > +# real QA test starts here
> > > +
> > > +_supported_fs xfs
> > > +_require_scratch
> > > +_require_xfs_quota
> > > +_require_xfs_debug
> > > +_require_xfs_io_command "falloc"
> > > +_require_xfs_io_error_injection "reduce_max_iextents"
> > > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > > +
> > > +delalloc_to_written_extent()
> > > +{
> > > +	echo "* Delalloc to written extent conversion"
> > > +
> > > +	echo "Format and mount fs"
> > > +	_scratch_mkfs >> $seqres.full
> > > +	_scratch_mount >> $seqres.full
> > > +
> > > +	testfile=$SCRATCH_MNT/testfile
> > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > +
> > > +	echo "Inject reduce_max_iextents error tag"
> > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > +
> > > +	nr_blks=$((15 * 2))
> > > +
> > > +	echo "Create fragmented file"
> > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> > > +		[[ $? != 0 ]] && break
> > > +	done
> > > +
> > > +	testino=$(stat -c "%i" $testfile)
> > > +
> > > +	_scratch_unmount >> $seqres.full
> > > +
> > > +	echo "Verify \$testfile's extent count"
> > > +
> > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > > +			   _fail "Unable to obtain inode fork's extent count")
> > > +	if (( $nextents > 10 )); then
> > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > +		exit 1
> > > +	fi
> > > +}
> > > +
> > > +falloc_unwritten_extent()
> > > +{
> > > +	echo "* Fallocate of unwritten extents"
> > > +
> > > +	echo "Format and mount fs"
> > > +	_scratch_mkfs >> $seqres.full
> > > +	_scratch_mount >> $seqres.full
> > > +
> > > +	testfile=$SCRATCH_MNT/testfile
> > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > +
> > > +	echo "Inject reduce_max_iextents error tag"
> > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > +
> > > +	nr_blks=$((15 * 2))
> > > +
> > > +	echo "Fallocate fragmented file"
> > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > +		xfs_io -f -c "falloc $((i * bsize)) $bsize" $testfile >> $seqres.full 2>&1
> > > +		[[ $? != 0 ]] && break
> > > +	done
> > > +
> > > +	testino=$(stat -c "%i" $testfile)
> > > +
> > > +	_scratch_unmount >> $seqres.full
> > > +
> > > +	echo "Verify \$testfile's extent count"
> > > +
> > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > > +			   _fail "Unable to obtain inode fork's extent count")
> > > +	if (( $nextents > 10 )); then
> > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > +		exit 1
> > > +	fi
> > > +}
> > > +
> > > +quota_inode_extend()
> > > +{
> > > +	echo "* Extend quota inodes"
> > > +
> > > +	echo "Format and mount fs"
> > > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > > +	_scratch_mount -o uquota >> $seqres.full
> > > +
> > > +	testfile=$SCRATCH_MNT/testfile
> > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > +
> > > +	echo "Consume free space"
> > > +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > > +	sync
> > > +
> > > +	echo "Create fragmented filesystem"
> > > +	$here/src/punch-alternating $testfile >> $seqres.full
> > > +	sync
> > > +
> > > +	echo "Inject reduce_max_iextents error tag"
> > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > +
> > > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > > +
> > > +	nr_blks=20
> > > +
> > > +	# This is a rough calculation; It doesn't take block headers into
> > > +	# consideration.
> > > +	# gdb -batch vmlinux -ex 'print sizeof(struct xfs_disk_dquot)'
> > > +	# $1 = 104
> > > +	nr_quotas_per_block=$((bsize / 104))
> > 
> > That's sizeof(xfs_dqblk_t) you want, and it's 136 bytes long.
> 
> Ah ok. I had missed that. Thanks for pointing that out.
> 
> > 
> > > +	nr_quotas=$((nr_quotas_per_block * nr_blks))
> > > +
> > > +	echo "Extend uquota file"
> > > +	for i in $(seq 0 $nr_quotas); do
> > 
> > You only have to initialize the first dquot in a dquot file block in
> > order to allocate the whole block, so you could speed this up with
> > "seq 0 $nr_quotas_per_block $nr_quotas".
> 
> Ok. Thanks for the suggestion.
> 
> > 
> > > +		chown $i $testfile >> $seqres.full 2>&1
> > > +		[[ $? != 0 ]] && break
> > > +	done
> > > +
> > > +	_scratch_unmount >> $seqres.full
> > > +
> > > +	echo "Verify uquota inode's extent count"
> > > +	uquotino=$(_scratch_xfs_db -c sb -c "print uquotino")
> > > +	uquotino=${uquotino##uquotino = }
> > > +
> > > +	nextents=$(_scratch_get_iext_count $uquotino data || \
> > > +			   _fail "Unable to obtain inode fork's extent count")
> > > +	if (( $nextents > 10 )); then
> > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > +		exit 1
> > > +	fi
> > > +}
> > > +
> > > +directio_write()
> > > +{
> > > +	echo "* Directio write"
> > > +
> > > +	echo "Format and mount fs"
> > > +	_scratch_mkfs >> $seqres.full
> > > +	_scratch_mount >> $seqres.full
> > > +
> > > +	testfile=$SCRATCH_MNT/testfile
> > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > +
> > > +	echo "Inject reduce_max_iextents error tag"
> > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > +
> > > +	nr_blks=$((15 * 2))
> > > +
> > > +	echo "Create fragmented file via directio writes"
> > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > +		xfs_io -d -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> > 
> > $XFS_IO_PROG -d -f -s -c "pwrite ..." $testfile
> > 
> > "-s" is an undocumented flag that makes the writes synchronous.
> 
> Ok. I will fix that.
> 
> > 
> > > +		[[ $? != 0 ]] && break
> > > +	done
> > > +
> > > +	testino=$(stat -c "%i" $testfile)
> > > +
> > > +	_scratch_unmount >> $seqres.full
> > > +
> > > +	echo "Verify \$testfile's extent count"
> > > +
> > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > 
> > $XFS_IO_PROG -c 'stat' $testfile | grep nextents ?
> 
> I agree. I will replace the above with xfs_io's stat command. But for special
> inodes like quota and realtime bitmap and summary inodes we would still
> require the helper function to obtain the extent count.

<nod>

> > 
> > > +			   _fail "Unable to obtain inode fork's extent count")
> > > +	if (( $nextents > 10 )); then
> > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > +		exit 1
> > > +	fi
> > > +}
> > > +
> > > +delalloc_to_written_extent
> > > +falloc_unwritten_extent
> > > +quota_inode_extend
> > > +directio_write
> > 
> > I wonder if these should be separate tests, since they each format the
> > scratch fs?  Or could you format the scratch fs once and test four
> > different files?
> 
> Quota inode test is the only one which requires bmap_alloc_minlen_extent
>  error tag. Other tests here have the following pattern,
>  - mkfs and mount fs
>  - Fragment fs space
>  - Inject reduce_max_iextents error tag
>  - Work on a test file
>    Here we allocate individual blocks.
>  - Umount
>  - Check inode fork extent count.
> So we can have just one mkfs/mount overall by removing the testfile created by
> each test and also quota inode test can be moved to the last so that
> bmap_alloc_minlen_extent error tag can be applied only to that test.

<nod> sounds good to me.

I think you can disable errortags too, so the quota inode extend test
doesn't necessarily have to go last.

--D

> > 
> > --D
> > 
> > > +
> > > +# success, all done
> > > +status=0
> > > +exit
> > > diff --git a/tests/xfs/522.out b/tests/xfs/522.out
> > > new file mode 100644
> > > index 00000000..98791aae
> > > --- /dev/null
> > > +++ b/tests/xfs/522.out
> > > @@ -0,0 +1,24 @@
> > > +QA output created by 522
> > > +* Delalloc to written extent conversion
> > > +Format and mount fs
> > > +Inject reduce_max_iextents error tag
> > > +Create fragmented file
> > > +Verify $testfile's extent count
> > > +* Fallocate of unwritten extents
> > > +Format and mount fs
> > > +Inject reduce_max_iextents error tag
> > > +Fallocate fragmented file
> > > +Verify $testfile's extent count
> > > +* Extend quota inodes
> > > +Format and mount fs
> > > +Consume free space
> > > +Create fragmented filesystem
> > > +Inject reduce_max_iextents error tag
> > > +Inject bmap_alloc_minlen_extent error tag
> > > +Extend uquota file
> > > +Verify uquota inode's extent count
> > > +* Directio write
> > > +Format and mount fs
> > > +Inject reduce_max_iextents error tag
> > > +Create fragmented file via directio writes
> > > +Verify $testfile's extent count
> > > diff --git a/tests/xfs/group b/tests/xfs/group
> > > index b89c0a4e..1831f0b5 100644
> > > --- a/tests/xfs/group
> > > +++ b/tests/xfs/group
> > > @@ -519,3 +519,4 @@
> > >  519 auto quick reflink
> > >  520 auto quick reflink
> > >  521 auto quick realtime growfs
> > > +522 auto quick quota
> > 
> 
> 
> -- 
> chandan
> 
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent
  2020-11-18  2:30       ` Darrick J. Wong
@ 2020-11-18  4:09         ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-18  4:09 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Wednesday 18 November 2020 8:00:39 AM IST Darrick J. Wong wrote:
> On Tue, Nov 17, 2020 at 07:42:45PM +0530, Chandan Babu R wrote:
> > On Saturday 14 November 2020 5:54:20 AM IST Darrick J. Wong wrote:
> > > On Fri, Nov 13, 2020 at 04:56:54PM +0530, Chandan Babu R wrote:
> > > > This test verifies that XFS does not cause inode fork's extent count to
> > > > overflow when adding a single extent while there's no possibility of
> > > > splitting an existing mapping (limited to non-realtime files).
> > > > 
> > > > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > > > ---
> > > >  tests/xfs/522     | 214 ++++++++++++++++++++++++++++++++++++++++++++++
> > > >  tests/xfs/522.out |  24 ++++++
> > > >  tests/xfs/group   |   1 +
> > > >  3 files changed, 239 insertions(+)
> > > >  create mode 100755 tests/xfs/522
> > > >  create mode 100644 tests/xfs/522.out
> > > > 
> > > > diff --git a/tests/xfs/522 b/tests/xfs/522
> > > > new file mode 100755
> > > > index 00000000..a54fe136
> > > > --- /dev/null
> > > > +++ b/tests/xfs/522
> > > > @@ -0,0 +1,214 @@
> > > > +#! /bin/bash
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > > > +#
> > > > +# FS QA Test 522
> > > > +#
> > > > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > > > +# adding a single extent while there's no possibility of splitting an existing
> > > > +# mapping (limited to non-realtime files).
> > > > +
> > > > +seq=`basename $0`
> > > > +seqres=$RESULT_DIR/$seq
> > > > +echo "QA output created by $seq"
> > > > +
> > > > +here=`pwd`
> > > > +tmp=/tmp/$$
> > > > +status=1	# failure is the default!
> > > > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > > > +
> > > > +_cleanup()
> > > > +{
> > > > +	cd /
> > > > +	rm -f $tmp.*
> > > > +}
> > > > +
> > > > +# get standard environment, filters and checks
> > > > +. ./common/rc
> > > > +. ./common/filter
> > > > +. ./common/quota
> > > > +. ./common/inject
> > > > +
> > > > +# remove previous $seqres.full before test
> > > > +rm -f $seqres.full
> > > > +
> > > > +# real QA test starts here
> > > > +
> > > > +_supported_fs xfs
> > > > +_require_scratch
> > > > +_require_xfs_quota
> > > > +_require_xfs_debug
> > > > +_require_xfs_io_command "falloc"
> > > > +_require_xfs_io_error_injection "reduce_max_iextents"
> > > > +_require_xfs_io_error_injection "bmap_alloc_minlen_extent"
> > > > +
> > > > +delalloc_to_written_extent()
> > > > +{
> > > > +	echo "* Delalloc to written extent conversion"
> > > > +
> > > > +	echo "Format and mount fs"
> > > > +	_scratch_mkfs >> $seqres.full
> > > > +	_scratch_mount >> $seqres.full
> > > > +
> > > > +	testfile=$SCRATCH_MNT/testfile
> > > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > > +
> > > > +	echo "Inject reduce_max_iextents error tag"
> > > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > > +
> > > > +	nr_blks=$((15 * 2))
> > > > +
> > > > +	echo "Create fragmented file"
> > > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > > +		xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> > > > +		[[ $? != 0 ]] && break
> > > > +	done
> > > > +
> > > > +	testino=$(stat -c "%i" $testfile)
> > > > +
> > > > +	_scratch_unmount >> $seqres.full
> > > > +
> > > > +	echo "Verify \$testfile's extent count"
> > > > +
> > > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > > > +			   _fail "Unable to obtain inode fork's extent count")
> > > > +	if (( $nextents > 10 )); then
> > > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > > +		exit 1
> > > > +	fi
> > > > +}
> > > > +
> > > > +falloc_unwritten_extent()
> > > > +{
> > > > +	echo "* Fallocate of unwritten extents"
> > > > +
> > > > +	echo "Format and mount fs"
> > > > +	_scratch_mkfs >> $seqres.full
> > > > +	_scratch_mount >> $seqres.full
> > > > +
> > > > +	testfile=$SCRATCH_MNT/testfile
> > > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > > +
> > > > +	echo "Inject reduce_max_iextents error tag"
> > > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > > +
> > > > +	nr_blks=$((15 * 2))
> > > > +
> > > > +	echo "Fallocate fragmented file"
> > > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > > +		xfs_io -f -c "falloc $((i * bsize)) $bsize" $testfile >> $seqres.full 2>&1
> > > > +		[[ $? != 0 ]] && break
> > > > +	done
> > > > +
> > > > +	testino=$(stat -c "%i" $testfile)
> > > > +
> > > > +	_scratch_unmount >> $seqres.full
> > > > +
> > > > +	echo "Verify \$testfile's extent count"
> > > > +
> > > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > > > +			   _fail "Unable to obtain inode fork's extent count")
> > > > +	if (( $nextents > 10 )); then
> > > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > > +		exit 1
> > > > +	fi
> > > > +}
> > > > +
> > > > +quota_inode_extend()
> > > > +{
> > > > +	echo "* Extend quota inodes"
> > > > +
> > > > +	echo "Format and mount fs"
> > > > +	_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > > > +	_scratch_mount -o uquota >> $seqres.full
> > > > +
> > > > +	testfile=$SCRATCH_MNT/testfile
> > > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > > +
> > > > +	echo "Consume free space"
> > > > +	dd if=/dev/zero of=${testfile} bs=${bsize} >> $seqres.full 2>&1
> > > > +	sync
> > > > +
> > > > +	echo "Create fragmented filesystem"
> > > > +	$here/src/punch-alternating $testfile >> $seqres.full
> > > > +	sync
> > > > +
> > > > +	echo "Inject reduce_max_iextents error tag"
> > > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > > +
> > > > +	echo "Inject bmap_alloc_minlen_extent error tag"
> > > > +	xfs_io -x -c 'inject bmap_alloc_minlen_extent' $SCRATCH_MNT
> > > > +
> > > > +	nr_blks=20
> > > > +
> > > > +	# This is a rough calculation; It doesn't take block headers into
> > > > +	# consideration.
> > > > +	# gdb -batch vmlinux -ex 'print sizeof(struct xfs_disk_dquot)'
> > > > +	# $1 = 104
> > > > +	nr_quotas_per_block=$((bsize / 104))
> > > 
> > > That's sizeof(xfs_dqblk_t) you want, and it's 136 bytes long.
> > 
> > Ah ok. I had missed that. Thanks for pointing that out.
> > 
> > > 
> > > > +	nr_quotas=$((nr_quotas_per_block * nr_blks))
> > > > +
> > > > +	echo "Extend uquota file"
> > > > +	for i in $(seq 0 $nr_quotas); do
> > > 
> > > You only have to initialize the first dquot in a dquot file block in
> > > order to allocate the whole block, so you could speed this up with
> > > "seq 0 $nr_quotas_per_block $nr_quotas".
> > 
> > Ok. Thanks for the suggestion.
> > 
> > > 
> > > > +		chown $i $testfile >> $seqres.full 2>&1
> > > > +		[[ $? != 0 ]] && break
> > > > +	done
> > > > +
> > > > +	_scratch_unmount >> $seqres.full
> > > > +
> > > > +	echo "Verify uquota inode's extent count"
> > > > +	uquotino=$(_scratch_xfs_db -c sb -c "print uquotino")
> > > > +	uquotino=${uquotino##uquotino = }
> > > > +
> > > > +	nextents=$(_scratch_get_iext_count $uquotino data || \
> > > > +			   _fail "Unable to obtain inode fork's extent count")
> > > > +	if (( $nextents > 10 )); then
> > > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > > +		exit 1
> > > > +	fi
> > > > +}
> > > > +
> > > > +directio_write()
> > > > +{
> > > > +	echo "* Directio write"
> > > > +
> > > > +	echo "Format and mount fs"
> > > > +	_scratch_mkfs >> $seqres.full
> > > > +	_scratch_mount >> $seqres.full
> > > > +
> > > > +	testfile=$SCRATCH_MNT/testfile
> > > > +	bsize=$(_get_block_size $SCRATCH_MNT)
> > > > +
> > > > +	echo "Inject reduce_max_iextents error tag"
> > > > +	xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > > > +
> > > > +	nr_blks=$((15 * 2))
> > > > +
> > > > +	echo "Create fragmented file via directio writes"
> > > > +	for i in $(seq 0 2 $((nr_blks - 1))); do
> > > > +		xfs_io -d -f -c "pwrite $((i * bsize)) $bsize" -c fsync $testfile >> $seqres.full 2>&1
> > > 
> > > $XFS_IO_PROG -d -f -s -c "pwrite ..." $testfile
> > > 
> > > "-s" is an undocumented flag that makes the writes synchronous.
> > 
> > Ok. I will fix that.
> > 
> > > 
> > > > +		[[ $? != 0 ]] && break
> > > > +	done
> > > > +
> > > > +	testino=$(stat -c "%i" $testfile)
> > > > +
> > > > +	_scratch_unmount >> $seqres.full
> > > > +
> > > > +	echo "Verify \$testfile's extent count"
> > > > +
> > > > +	nextents=$(_scratch_get_iext_count $testino data || \
> > > 
> > > $XFS_IO_PROG -c 'stat' $testfile | grep nextents ?
> > 
> > I agree. I will replace the above with xfs_io's stat command. But for special
> > inodes like quota and realtime bitmap and summary inodes we would still
> > require the helper function to obtain the extent count.
> 
> <nod>
> 
> > > 
> > > > +			   _fail "Unable to obtain inode fork's extent count")
> > > > +	if (( $nextents > 10 )); then
> > > > +		echo "Extent count overflow check failed: nextents = $nextents"
> > > > +		exit 1
> > > > +	fi
> > > > +}
> > > > +
> > > > +delalloc_to_written_extent
> > > > +falloc_unwritten_extent
> > > > +quota_inode_extend
> > > > +directio_write
> > > 
> > > I wonder if these should be separate tests, since they each format the
> > > scratch fs?  Or could you format the scratch fs once and test four
> > > different files?
> > 
> > Quota inode test is the only one which requires bmap_alloc_minlen_extent
> >  error tag. Other tests here have the following pattern,
> >  - mkfs and mount fs
> >  - Fragment fs space
> >  - Inject reduce_max_iextents error tag
> >  - Work on a test file
> >    Here we allocate individual blocks.
> >  - Umount
> >  - Check inode fork extent count.
> > So we can have just one mkfs/mount overall by removing the testfile created by
> > each test and also quota inode test can be moved to the last so that
> > bmap_alloc_minlen_extent error tag can be applied only to that test.
> 
> <nod> sounds good to me.
> 
> I think you can disable errortags too, so the quota inode extend test
> doesn't necessarily have to go last.

True. I just noticed that error tags can accessed via a sysfs interface and
that common/inject provides helpers for working with them.

> > > 
> > > > +
> > > > +# success, all done
> > > > +status=0
> > > > +exit
> > > > diff --git a/tests/xfs/522.out b/tests/xfs/522.out
> > > > new file mode 100644
> > > > index 00000000..98791aae
> > > > --- /dev/null
> > > > +++ b/tests/xfs/522.out
> > > > @@ -0,0 +1,24 @@
> > > > +QA output created by 522
> > > > +* Delalloc to written extent conversion
> > > > +Format and mount fs
> > > > +Inject reduce_max_iextents error tag
> > > > +Create fragmented file
> > > > +Verify $testfile's extent count
> > > > +* Fallocate of unwritten extents
> > > > +Format and mount fs
> > > > +Inject reduce_max_iextents error tag
> > > > +Fallocate fragmented file
> > > > +Verify $testfile's extent count
> > > > +* Extend quota inodes
> > > > +Format and mount fs
> > > > +Consume free space
> > > > +Create fragmented filesystem
> > > > +Inject reduce_max_iextents error tag
> > > > +Inject bmap_alloc_minlen_extent error tag
> > > > +Extend uquota file
> > > > +Verify uquota inode's extent count
> > > > +* Directio write
> > > > +Format and mount fs
> > > > +Inject reduce_max_iextents error tag
> > > > +Create fragmented file via directio writes
> > > > +Verify $testfile's extent count
> > > > diff --git a/tests/xfs/group b/tests/xfs/group
> > > > index b89c0a4e..1831f0b5 100644
> > > > --- a/tests/xfs/group
> > > > +++ b/tests/xfs/group
> > > > @@ -519,3 +519,4 @@
> > > >  519 auto quick reflink
> > > >  520 auto quick reflink
> > > >  521 auto quick realtime growfs
> > > > +522 auto quick quota
> > > 
> > 
> > 
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork
  2020-11-14  0:42   ` Darrick J. Wong
@ 2020-11-18  5:20     ` Chandan Babu R
  0 siblings, 0 replies; 36+ messages in thread
From: Chandan Babu R @ 2020-11-18  5:20 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: fstests, linux-xfs

On Saturday 14 November 2020 6:12:32 AM IST Darrick J. Wong wrote:
> On Fri, Nov 13, 2020 at 04:57:00PM +0530, Chandan Babu R wrote:
> > This test verifies that XFS does not cause inode fork's extent count to
> > overflow when writing to a shared extent.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  tests/xfs/528     | 87 +++++++++++++++++++++++++++++++++++++++++++++++
> >  tests/xfs/528.out |  8 +++++
> >  tests/xfs/group   |  1 +
> >  3 files changed, 96 insertions(+)
> >  create mode 100755 tests/xfs/528
> >  create mode 100644 tests/xfs/528.out
> > 
> > diff --git a/tests/xfs/528 b/tests/xfs/528
> > new file mode 100755
> > index 00000000..0d39f05e
> > --- /dev/null
> > +++ b/tests/xfs/528
> > @@ -0,0 +1,87 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2020 Chandan Babu R.  All Rights Reserved.
> > +#
> > +# FS QA Test 528
> > +#
> > +# Verify that XFS does not cause inode fork's extent count to overflow when
> > +# writing to a shared extent.
> > +seq=`basename $0`
> > +seqres=$RESULT_DIR/$seq
> > +echo "QA output created by $seq"
> > +
> > +here=`pwd`
> > +tmp=/tmp/$$
> > +status=1	# failure is the default!
> > +trap "_cleanup; exit \$status" 0 1 2 3 15
> > +
> > +_cleanup()
> > +{
> > +	cd /
> > +	rm -f $tmp.*
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
> > +. ./common/reflink
> > +. ./common/inject
> > +
> > +# remove previous $seqres.full before test
> > +rm -f $seqres.full
> > +
> > +# real QA test starts here
> > +
> > +_supported_fs xfs
> > +_require_scratch
> > +_require_scratch_reflink
> > +_require_xfs_debug
> > +_require_xfs_io_command "reflink"
> > +_require_xfs_io_error_injection "reduce_max_iextents"
> > +
> > +echo "* Write to shared extent"
> > +
> > +echo "Format and mount fs"
> > +_scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
> > +_scratch_mount >> $seqres.full
> > +
> > +bsize=$(_get_block_size $SCRATCH_MNT)
> 
> Now that we're playing with regular files again -- should this be
> _get_file_block_size ?  I think the same question applies to patches 2,
> 3, and 4, and perhaps the next one too.
> 
> (Note that regular files can have cluster sizes that aren't the same as
> the fs block size if I set MKFS_OPTIONS="-d rtinherit=1 -r extsize=64k".)

Patch 2 computes the size of the rt volume as a function of the bitmap
inode. The data associated with bitmap inode is stored in the regular
filesystem space. Hence filesystem block size is the appropriate choice here.
The same applies to quota inode extent count overflow test.

The test included in the next patch requires reflink to be enabled. Hence
filesystem block size is the correct choice.

For the other tests that you have mentioned and also for the fstress test I
will use _get_file_block_size().

> 
> --D
> 
> > +
> > +srcfile=${SCRATCH_MNT}/srcfile
> > +dstfile=${SCRATCH_MNT}/dstfile
> > +
> > +nr_blks=15
> > +
> > +echo "Create a \$srcfile having an extent of length $nr_blks blocks"
> > +xfs_io -f -c "pwrite -b $((nr_blks * bsize))  0 $((nr_blks * bsize))" \
> > +       -c fsync $srcfile  >> $seqres.full
> > +
> > +echo "Share the extent with \$dstfile"
> > +xfs_io -f -c "reflink $srcfile" $dstfile >> $seqres.full
> > +
> > +echo "Inject reduce_max_iextents error tag"
> > +xfs_io -x -c 'inject reduce_max_iextents' $SCRATCH_MNT
> > +
> > +echo "Buffered write to every other block of \$dstfile's shared extent"
> > +for i in $(seq 1 2 $((nr_blks - 1))); do
> > +	xfs_io -f -c "pwrite $((i * bsize)) $bsize" -c fsync $dstfile \
> > +	       >> $seqres.full 2>&1
> > +	[[ $? != 0 ]] && break
> > +done
> > +
> > +ino=$(stat -c "%i" $dstfile)
> > +
> > +_scratch_unmount >> $seqres.full
> > +
> > +echo "Verify \$dstfile's extent count"
> > +
> > +nextents=$(_scratch_get_iext_count $ino data || \
> > +		_fail "Unable to obtain inode fork's extent count")
> > +if (( $nextents > 10 )); then
> > +	echo "Extent count overflow check failed: nextents = $nextents"
> > +fi
> > +
> > +# success, all done
> > +status=0
> > +exit
> > + 
> > diff --git a/tests/xfs/528.out b/tests/xfs/528.out
> > new file mode 100644
> > index 00000000..8666488b
> > --- /dev/null
> > +++ b/tests/xfs/528.out
> > @@ -0,0 +1,8 @@
> > +QA output created by 528
> > +* Write to shared extent
> > +Format and mount fs
> > +Create a $srcfile having an extent of length 15 blocks
> > +Share the extent with $dstfile
> > +Inject reduce_max_iextents error tag
> > +Buffered write to every other block of $dstfile's shared extent
> > +Verify $dstfile's extent count
> > diff --git a/tests/xfs/group b/tests/xfs/group
> > index 627813fe..c85aac6b 100644
> > --- a/tests/xfs/group
> > +++ b/tests/xfs/group
> > @@ -525,3 +525,4 @@
> >  525 auto quick attr
> >  526 auto quick dir hardlink symlink
> >  527 auto quick
> > +528 auto quick reflink
> 


-- 
chandan




^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2020-11-18  5:20 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-13 11:26 [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R
2020-11-13 11:26 ` [PATCH 01/11] common/xfs: Add a helper to get an inode fork's extent count Chandan Babu R
2020-11-14  0:10   ` Darrick J. Wong
2020-11-13 11:26 ` [PATCH 02/11] xfs: Check for extent overflow when trivally adding a new extent Chandan Babu R
2020-11-14  0:24   ` Darrick J. Wong
2020-11-17 14:12     ` Chandan Babu R
2020-11-18  2:30       ` Darrick J. Wong
2020-11-18  4:09         ` Chandan Babu R
2020-11-13 11:26 ` [PATCH 03/11] " Chandan Babu R
2020-11-14  0:18   ` Darrick J. Wong
2020-11-17 14:22     ` Chandan Babu R
2020-11-13 11:26 ` [PATCH 04/11] xfs: Check for extent overflow when punching a hole Chandan Babu R
2020-11-14  0:28   ` Darrick J. Wong
2020-11-17 14:26     ` Chandan Babu R
2020-11-13 11:26 ` [PATCH 05/11] xfs: Check for extent overflow when adding/removing xattrs Chandan Babu R
2020-11-14  0:34   ` Darrick J. Wong
2020-11-17 14:30     ` Chandan Babu R
2020-11-13 11:26 ` [PATCH 06/11] xfs: Check for extent overflow when adding/removing dir entries Chandan Babu R
2020-11-14  0:37   ` Darrick J. Wong
2020-11-17 14:50     ` Chandan Babu R
2020-11-13 11:26 ` [PATCH 07/11] xfs: Check for extent overflow when writing to unwritten extent Chandan Babu R
2020-11-14  0:39   ` Darrick J. Wong
2020-11-17 15:15     ` Chandan Babu R
2020-11-13 11:27 ` [PATCH 08/11] xfs: Check for extent overflow when moving extent from cow to data fork Chandan Babu R
2020-11-14  0:42   ` Darrick J. Wong
2020-11-18  5:20     ` Chandan Babu R
2020-11-13 11:27 ` [PATCH 09/11] xfs: Check for extent overflow when remapping an extent Chandan Babu R
2020-11-14  0:43   ` Darrick J. Wong
2020-11-13 11:27 ` [PATCH 10/11] xfs: Check for extent overflow when swapping extents Chandan Babu R
2020-11-14  0:08   ` Darrick J. Wong
2020-11-17 15:35     ` Chandan Babu R
2020-11-18  2:23       ` Darrick J. Wong
2020-11-13 11:27 ` [PATCH 11/11] xfs: Stress test with with bmap_alloc_minlen_extent error tag enabled Chandan Babu R
2020-11-14  0:06   ` Darrick J. Wong
2020-11-17 15:24     ` Chandan Babu R
2020-11-13 11:29 ` [PATCH 00/11] xfs: Tests to check for inode fork extent count overflow detection Chandan Babu R

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).