new file mode 100755
@@ -0,0 +1,173 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 SUSE Linux Products GmbH. All Rights Reserved.
+#
+# FSQA Test No. 205
+#
+# Test several scenarios of cloning operations where the source range includes
+# inline extents. They used to not be supported on btrfs because their
+# implementation was not straightforward, and therefore these operations used
+# to fail with errno EOPNOTSUPP on older kernels.
+#
+# Support for this was added by a patch with the following subject:
+#
+# "Btrfs: implement full reflink support for inline extents"
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+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
+
+# real QA test starts here
+_supported_fs btrfs
+_supported_os Linux
+_require_scratch_reflink
+_require_xfs_io_command "falloc" "-k"
+_require_command "$CHATTR_PROG" chattr
+_require_btrfs_fs_feature "no_holes"
+_require_btrfs_mkfs_feature "no-holes"
+
+run_tests()
+{
+ rm -f $SCRATCH_MNT/foo* $SCRATCH_MNT/bar*
+
+ # File foo1 has an inline extent encoding 4K of data followed by a regular
+ # extent. It has a file size of 128K.
+ echo "Creating file foo1"
+ touch $SCRATCH_MNT/foo1
+ $CHATTR_PROG +c $SCRATCH_MNT/foo1
+ $XFS_IO_PROG -c "pwrite -S 0xab 0 4K" \
+ -c "fsync" \
+ -c "pwrite -S 0xab 4K 124K" \
+ $SCRATCH_MNT/foo1 | _filter_xfs_io
+
+ # File bar1 has a single 128K extent, and a file size of 128K.
+ echo "Creating file bar1"
+ $XFS_IO_PROG -f -c "pwrite -S 0xcd 0 128K" $SCRATCH_MNT/bar1 | _filter_xfs_io
+
+ echo "Cloning foo1 into the end of bar1"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo1 0 128K 128K" $SCRATCH_MNT/bar1 \
+ | _filter_xfs_io
+
+ echo "File bar1 digest = $(_md5_checksum $SCRATCH_MNT/bar1)"
+
+ # File foo2 has an inline extent with 1000 bytes of data and it's followed
+ # by a regular extent of 60K. It has a file size of 64K.
+ echo "Creating file foo2"
+ $XFS_IO_PROG -f -c "pwrite -S 0xab 0 1000" \
+ -c "fsync" \
+ -c "falloc 0 4K" \
+ -c "pwrite -S 0xab 4K 60K" \
+ $SCRATCH_MNT/foo2 | _filter_xfs_io
+
+ # File bar2 has a regular extent of 64K and a file size of 64K too.
+ echo "Creating file bar2"
+ $XFS_IO_PROG -f -c "pwrite -S 0xcd 0 64K" $SCRATCH_MNT/bar2 | _filter_xfs_io
+
+ echo "Cloning foo2 into the end of bar2"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo2 0 64K 64K" $SCRATCH_MNT/bar2 \
+ | _filter_xfs_io
+
+ echo "File bar2 digest = $(_md5_checksum $SCRATCH_MNT/bar2)"
+
+ # File bar3 has a regular extent of 128K and a file size of 128K too.
+ echo "Creating file bar3"
+ $XFS_IO_PROG -f -c "pwrite -S 0xcd 0 128K" $SCRATCH_MNT/bar3 \
+ | _filter_xfs_io
+
+ echo "Cloning foo2 into the middle of bar3"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo2 0 64K 64K" $SCRATCH_MNT/bar3 \
+ | _filter_xfs_io
+
+ echo "File bar3 digest = $(_md5_checksum $SCRATCH_MNT/bar3)"
+
+ # File bar4 has a 64K hole at offset 0 followed by a 64K regular extent, and
+ # a file size of 128K.
+ echo "Creating file bar4"
+ $XFS_IO_PROG -f -c "pwrite -S 0xcd 64K 64K" $SCRATCH_MNT/bar4 | _filter_xfs_io
+
+ echo "Cloning foo1 into bar4"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo1 0 0 128K" $SCRATCH_MNT/bar4 \
+ | _filter_xfs_io
+
+ echo "File bar4 digest = $(_md5_checksum $SCRATCH_MNT/bar4)"
+
+ # File bar5 has a 1Mb prealloc extent at file offset 0 and a file size of 0.
+ echo "Creating file bar5"
+ $XFS_IO_PROG -f -c "falloc -k 0 1M" $SCRATCH_MNT/bar5
+
+ echo "Cloning foo1 into bar5"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo1 0 0 128K" $SCRATCH_MNT/bar5 \
+ | _filter_xfs_io
+
+ echo "File bar5 digest = $(_md5_checksum $SCRATCH_MNT/bar5)"
+
+ # File bar6 has an inline extent encoding 500 bytes of data followed by a
+ # prealloc extent of 1Mb at file offset 4K. The file size is 500 bytes.
+ echo "Creating file bar6"
+ $XFS_IO_PROG -f -c "pwrite -S 0xef 0 500" \
+ -c "falloc -k 4K 1M" \
+ $SCRATCH_MNT/bar6 | _filter_xfs_io
+
+ echo "Cloning foo1 into bar6"
+ $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo1 0 0 128K" $SCRATCH_MNT/bar6 \
+ | _filter_xfs_io
+
+ echo "File bar6 digest = $(_md5_checksum $SCRATCH_MNT/bar6)"
+
+ # Unmount and mount again the filesystem. We want to verify the reflink
+ # operations were durably persisted.
+ _scratch_cycle_mount
+
+ echo "File digests after mounting again the filesystem:"
+ echo "File bar1 digest = $(_md5_checksum $SCRATCH_MNT/bar1)"
+ echo "File bar2 digest = $(_md5_checksum $SCRATCH_MNT/bar2)"
+ echo "File bar3 digest = $(_md5_checksum $SCRATCH_MNT/bar3)"
+ echo "File bar4 digest = $(_md5_checksum $SCRATCH_MNT/bar4)"
+ echo "File bar5 digest = $(_md5_checksum $SCRATCH_MNT/bar5)"
+ echo "File bar6 digest = $(_md5_checksum $SCRATCH_MNT/bar6)"
+}
+
+_scratch_mkfs "-O ^no-holes" >>$seqres.full 2>&1
+_scratch_mount
+
+echo
+echo "Testing with defaults"
+echo
+run_tests
+
+echo
+echo "Testing with -o compress"
+echo
+_scratch_cycle_mount "compress"
+run_tests
+
+echo
+echo "Testing with -o nodatacow"
+echo
+_scratch_cycle_mount "nodatacow"
+run_tests
+
+echo
+echo "Testing with -O no-holes"
+echo
+_scratch_unmount
+_scratch_mkfs "-O no-holes" >>$seqres.full 2>&1
+_scratch_mount
+run_tests
+
+status=0
+exit
new file mode 100644
@@ -0,0 +1,241 @@
+QA output created by 205
+
+Testing with defaults
+
+Creating file foo1
+wrote 4096/4096 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 126976/126976 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar1
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into the end of bar1
+linked 131072/131072 bytes at offset 131072
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+Creating file foo2
+wrote 1000/1000 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 61440/61440 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar2
+wrote 65536/65536 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the end of bar2
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar3
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the middle of bar3
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar4
+wrote 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar4
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar5
+Cloning foo1 into bar5
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar6
+wrote 500/500 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar6
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+File digests after mounting again the filesystem:
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+
+Testing with -o compress
+
+Creating file foo1
+wrote 4096/4096 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 126976/126976 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar1
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into the end of bar1
+linked 131072/131072 bytes at offset 131072
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+Creating file foo2
+wrote 1000/1000 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 61440/61440 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar2
+wrote 65536/65536 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the end of bar2
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar3
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the middle of bar3
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar4
+wrote 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar4
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar5
+Cloning foo1 into bar5
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar6
+wrote 500/500 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar6
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+File digests after mounting again the filesystem:
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+
+Testing with -o nodatacow
+
+Creating file foo1
+wrote 4096/4096 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 126976/126976 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar1
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into the end of bar1
+linked 131072/131072 bytes at offset 131072
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+Creating file foo2
+wrote 1000/1000 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 61440/61440 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar2
+wrote 65536/65536 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the end of bar2
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar3
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the middle of bar3
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar4
+wrote 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar4
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar5
+Cloning foo1 into bar5
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar6
+wrote 500/500 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar6
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+File digests after mounting again the filesystem:
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+
+Testing with -O no-holes
+
+Creating file foo1
+wrote 4096/4096 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 126976/126976 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar1
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into the end of bar1
+linked 131072/131072 bytes at offset 131072
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+Creating file foo2
+wrote 1000/1000 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 61440/61440 bytes at offset 4096
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Creating file bar2
+wrote 65536/65536 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the end of bar2
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar3
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo2 into the middle of bar3
+linked 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+Creating file bar4
+wrote 65536/65536 bytes at offset 65536
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar4
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar5
+Cloning foo1 into bar5
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+Creating file bar6
+wrote 500/500 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Cloning foo1 into bar6
+linked 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
+File digests after mounting again the filesystem:
+File bar1 digest = e9d03fb5fff30baf3c709f2384dfde67
+File bar2 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar3 digest = 85678cf32ed48f92ca42ad06d0b63f2a
+File bar4 digest = 4b48829714d20a4e73a0cf1565270076
+File bar5 digest = 4b48829714d20a4e73a0cf1565270076
+File bar6 digest = 4b48829714d20a4e73a0cf1565270076
@@ -207,3 +207,4 @@
202 auto quick subvol snapshot
203 auto quick send clone
204 auto quick punch
+205 auto quick clone compress