mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
198 lines
5.2 KiB
Bash
198 lines
5.2 KiB
Bash
|
|
#! /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_os Linux
|
||
|
|
_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
|