#! /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 # remove previous $seqres.full before test rm -f $seqres.full # real QA test starts here _supported_fs btrfs _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 > /dev/null 2>&1 $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)" # File foo3 a single inline extent of 500 bytes. echo "Creating file foo3" $XFS_IO_PROG -f -c "pwrite -S 0xbf 0 500" $SCRATCH_MNT/foo3 | _filter_xfs_io # File bar7 is an empty file, has no extents. touch $SCRATCH_MNT/bar7 echo "Cloning foo3 into bar7" $XFS_IO_PROG -c "reflink $SCRATCH_MNT/foo3" $SCRATCH_MNT/bar7 | _filter_xfs_io echo "File bar7 digest = $(_md5_checksum $SCRATCH_MNT/bar7)" # 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)" echo "File bar7 digest = $(_md5_checksum $SCRATCH_MNT/bar7)" } _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