#! /bin/bash # SPDX-License-Identifier: GPL-2.0+ # Copyright (c) 2019, Oracle and/or its affiliates. All Rights Reserved. # # FS QA Test No. 544 # # Ensure that we can reflink from a file with a higher inode number to a lower # inode number and vice versa. Mix it up by doing this test with inodes that # already share blocks and inodes that don't share blocks. This tests both # double-inode locking order correctness as well as stressing things like ocfs2 # which have per-inode sharing groups and therefore have to check that we don't # try to link data between disjoint sharing groups. 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 -rf $tmp.* } # get standard environment, filters and checks . ./common/rc . ./common/filter . ./common/reflink # real QA test starts here _supported_fs generic _require_scratch_reflink _require_cp_reflink rm -f $seqres.full echo "Format and mount" _scratch_mkfs > $seqres.full 2>&1 _scratch_mount >> $seqres.full 2>&1 blksz=65536 nr=2 filesize=$((blksz * nr)) testdir=$SCRATCH_MNT/test-$seq dummy_file=$testdir/dummy low_file=$testdir/low high_file=$testdir/high scenario=1 mkdir $testdir # Return inode number inum() { stat -c '%i' $1 } # Create two test files, make $low_file the file with the lower inode # number, and make $high_file the file with the higher inode number. create_files() { _pwrite_byte 0x60 0 $filesize $testdir/file1 >> $seqres.full _pwrite_byte 0x61 0 $filesize $testdir/file2 >> $seqres.full if [ "$(inum $testdir/file1)" -lt "$(inum $testdir/file2)" ]; then mv $testdir/file1 $low_file mv $testdir/file2 $high_file else mv $testdir/file2 $low_file mv $testdir/file1 $high_file fi } # Check md5sum of both files, but keep results sorted by inode order check_files() { md5sum $low_file | _filter_scratch md5sum $high_file | _filter_scratch } # Test reflinking data from the first file to the second file test_files() { local src="$1" local dest="$2" local off=$((filesize / 2)) local sz=$((filesize / 2)) check_files _reflink_range $src $off $dest $off $sz >> $seqres.full _scratch_cycle_mount check_files } # Make a file shared with a dummy file dummy_share() { local which="$2" test -z "$which" && which=1 local dummy=$dummy_file.$which rm -f $dummy _cp_reflink $1 $dummy } # Make two files share (different ranges) with a dummy file mutual_dummy_share() { rm -f $dummy_file _cp_reflink $1 $dummy_file _reflink_range $2 0 $dummy_file $blksz $blksz >> $seqres.full } # Announce ourselves, remembering which scenario we've tried ann() { echo "$scenario: $@" | tee -a $seqres.full scenario=$((scenario + 1)) } # Scenario 1: low to high, neither file shares ann "low to high, neither share" create_files test_files $low_file $high_file # Scenario 2: high to low, neither file shares ann "high to low, neither share" create_files test_files $high_file $low_file # Scenario 3: low to high, only source file shares ann "low to high, only source shares" create_files dummy_share $low_file test_files $low_file $high_file # Scenario 4: high to low, only source file shares ann "high to low, only source shares" create_files dummy_share $high_file test_files $high_file $low_file # Scenario 5: low to high, only dest file shares ann "low to high, only dest shares" create_files dummy_share $high_file test_files $low_file $high_file # Scenario 6: high to low, only dest file shares ann "high to low, only dest shares" create_files dummy_share $low_file test_files $high_file $low_file # Scenario 7: low to high, both files share with each other ann "low to high, both files share with each other" create_files _reflink_range $low_file 0 $high_file 0 $blksz >> $seqres.full test_files $low_file $high_file # Scenario 8: high to low, both files share with each other ann "high to low, both files share with each other" create_files _reflink_range $low_file 0 $high_file 0 $blksz >> $seqres.full test_files $high_file $low_file # Scenario 9: low to high, both files share but not with each other ann "low to high, both files share but not with each other" create_files # ocfs2 can only reflink between files sharing a refcount tree, so for # this test (and #10) we skip the dummy file because we'd rather not split # the test code just to mask off the /one/ weird fs like this... if _supports_arbitrary_fileset_reflink; then dummy_share $low_file 1 dummy_share $high_file 2 fi test_files $low_file $high_file # Scenario 10: high to low, both files share but not with each other ann "high to low, both files share but not with each other" create_files if _supports_arbitrary_fileset_reflink; then dummy_share $low_file 1 dummy_share $high_file 2 fi test_files $high_file $low_file # Scenario 11: low to high, both files share mutually ann "low to high, both files share mutually" create_files mutual_dummy_share $low_file $high_file test_files $low_file $high_file # Scenario 12: high to low, both files share mutually ann "high to low, both files share mutually" create_files mutual_dummy_share $low_file $high_file test_files $high_file $low_file # success, all done status=0 exit