#! /bin/bash # FS QA Test No. btrfs/097 # # Test that an incremental send works after a file gets one of its extents # cloned/deduplicated into lower file offsets. # #----------------------------------------------------------------------- # Copyright (C) 2015 SUSE Linux Products GmbH. All Rights Reserved. # Author: Filipe Manana # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #----------------------------------------------------------------------- # 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() { rm -fr $send_files_dir rm -f $tmp.* } # get standard environment, filters and checks . ./common/rc . ./common/filter # real QA test starts here _supported_fs btrfs _supported_os Linux _require_scratch _require_cloner send_files_dir=$TEST_DIR/btrfs-test-$seq rm -f $seqres.full rm -fr $send_files_dir mkdir $send_files_dir _scratch_mkfs >>$seqres.full 2>&1 _scratch_mount BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT) # Create our test file with a single extent of 16 blocks starting at a file # offset mapped by 32nd block. $XFS_IO_PROG -f -c "pwrite -S 0xaa $((32 * $BLOCK_SIZE)) $((16 * $BLOCK_SIZE))" \ $SCRATCH_MNT/foo | _filter_xfs_io_blocks_modified _run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/mysnap1 # Now clone parts of the original extent into lower offsets of the file. # # The first clone operation adds a file extent item to file offset 0 that points # to our initial extent with a data offset of 4 blocks. The corresponding data back # reference in the extent tree has a large value for the 'offset' field, which is # the result of file_offset - data_offset = 0 - (file offset of 4th block). For # example in case of 4k block size, it will be 0 - 16k = 18446744073709535232. # The second clone operation adds a file extent item to file offset mapped by # 4th block that points to our initial extent with a data offset of 12 # blocks. The corresponding data back reference in the extent tree has a large # value for the 'offset' field, which is the result of file_offset - data_offset # = (file offset of 4th block) - (file offset of 12th block). For example in # case of 4k block size, it will be 16K - 48K = 18446744073709518848. # # Those large back reference offsets (result of unsigned arithmetic underflow) # confused the back reference walking code (used by an incremental send and # the multiple inspect-internal ioctls) and made it miss the back references, # which for the case of an incremental send it made it fail with -EIO and print # a message like the following to dmesg: # # "BTRFS error (device sdc): did not find backref in send_root. inode=257, \ # offset=0, disk_byte=12845056 found extent=12845056" # $CLONER_PROG -s $(((32 + 4) * $BLOCK_SIZE)) -d 0 -l $((4 * $BLOCK_SIZE)) \ $SCRATCH_MNT/foo $SCRATCH_MNT/foo $CLONER_PROG -s $(((32 + 12) * $BLOCK_SIZE)) -d $((4 * $BLOCK_SIZE)) \ -l $((4 * $BLOCK_SIZE)) $SCRATCH_MNT/foo $SCRATCH_MNT/foo _run_btrfs_util_prog subvolume snapshot -r $SCRATCH_MNT $SCRATCH_MNT/mysnap2 _run_btrfs_util_prog send -f $send_files_dir/1.snap $SCRATCH_MNT/mysnap1 _run_btrfs_util_prog send -p $SCRATCH_MNT/mysnap1 -f $send_files_dir/2.snap \ $SCRATCH_MNT/mysnap2 echo "File contents in the original filesystem:" od -t x1 $SCRATCH_MNT/mysnap2/foo | _filter_od # Now recreate the filesystem by receiving both send streams and verify we get # the same file contents that the original filesystem had. _scratch_unmount _scratch_mkfs >>$seqres.full 2>&1 _scratch_mount _run_btrfs_util_prog receive -f $send_files_dir/1.snap $SCRATCH_MNT _run_btrfs_util_prog receive -f $send_files_dir/2.snap $SCRATCH_MNT echo "File contents in the new filesystem:" od -t x1 $SCRATCH_MNT/mysnap2/foo | _filter_od status=0 exit