blob: 4bdd58957f33d27b380ca3ab20b18fbfa009ae4e [file] [log] [blame]
#! /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