mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
aad7738cda
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
364 lines
10 KiB
Plaintext
364 lines
10 KiB
Plaintext
##/bin/bash
|
|
# Routines for reflinking, deduping, and comparing parts of files.
|
|
#-----------------------------------------------------------------------
|
|
# Copyright (c) 2015 Oracle. All Rights Reserved.
|
|
# 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; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will 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 to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
# USA
|
|
#
|
|
# Contact information: Oracle Corporation, 500 Oracle Parkway,
|
|
# Redwood Shores, CA 94065, USA, or: http://www.oracle.com/
|
|
#-----------------------------------------------------------------------
|
|
|
|
# Check that cp has a reflink argument
|
|
_require_cp_reflink()
|
|
{
|
|
cp --help | grep -q reflink || \
|
|
_notrun "This test requires a cp with --reflink support."
|
|
}
|
|
|
|
# Given 2 files, verify that they have the same mapping but different
|
|
# inodes - i.e. an undisturbed reflink
|
|
# Silent if so, make noise if not
|
|
_verify_reflink()
|
|
{
|
|
# not a hard link or symlink?
|
|
cmp -s <(stat -c '%i' $1) <(stat -c '%i' $2) \
|
|
&& echo "$1 and $2 are not reflinks: same inode number"
|
|
|
|
# same mapping?
|
|
diff -u <($XFS_IO_PROG -c "fiemap" $1 | grep -v $1) \
|
|
<($XFS_IO_PROG -c "fiemap" $2 | grep -v $2) \
|
|
|| echo "$1 and $2 are not reflinks: different extents"
|
|
}
|
|
|
|
# New reflink/dedupe helpers
|
|
|
|
# this test requires the test fs support reflink...
|
|
_require_test_reflink()
|
|
{
|
|
_require_test
|
|
_require_xfs_io_command "reflink"
|
|
|
|
rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
|
|
"$XFS_IO_PROG" -f -c "reflink $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" > /dev/null
|
|
if [ ! -s "$TEST_DIR/file2" ]; then
|
|
rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
|
|
_notrun "Reflink not supported by test filesystem type: $FSTYP"
|
|
fi
|
|
rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
|
|
}
|
|
|
|
# this test requires the scratch fs support reflink...
|
|
_require_scratch_reflink()
|
|
{
|
|
_require_scratch
|
|
_require_xfs_io_command "reflink"
|
|
|
|
_scratch_mkfs > /dev/null
|
|
_scratch_mount
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
|
|
"$XFS_IO_PROG" -f -c "reflink $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" > /dev/null
|
|
if [ ! -s "$SCRATCH_MNT/file2" ]; then
|
|
_scratch_unmount
|
|
_notrun "Reflink not supported by scratch filesystem type: $FSTYP"
|
|
fi
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires the test fs support dedupe...
|
|
_require_test_dedupe()
|
|
{
|
|
_require_test
|
|
_require_xfs_io_command "dedupe"
|
|
|
|
rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file1" > /dev/null
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$TEST_DIR/file2" > /dev/null
|
|
testio="$("$XFS_IO_PROG" -f -c "dedupe $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" 2>&1)"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Inappropriate ioctl for device" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Invalid argument" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
rm -rf "$TEST_DIR/file1" "$TEST_DIR/file2"
|
|
}
|
|
|
|
# this test requires the scratch fs support dedupe...
|
|
_require_scratch_dedupe()
|
|
{
|
|
_require_scratch
|
|
_require_xfs_io_command "dedupe"
|
|
|
|
_scratch_mkfs > /dev/null
|
|
_scratch_mount
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file1" > /dev/null
|
|
"$XFS_IO_PROG" -f -c "pwrite -S 0x61 0 65536" "$SCRATCH_MNT/file2" > /dev/null
|
|
testio="$("$XFS_IO_PROG" -f -c "dedupe $TEST_DIR/file1 0 0 65536" "$TEST_DIR/file2" 2>&1)"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Inappropriate ioctl for device" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Invalid argument" && \
|
|
_notrun "Dedupe not supported by test filesystem type: $FSTYP"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# Prints a range of a file as a hex dump
|
|
_read_range() {
|
|
file="$1"
|
|
offset="$2"
|
|
len="$3"
|
|
xfs_io_args="$4"
|
|
|
|
$XFS_IO_PROG $xfs_io_args -f -c "pread -q -v $offset $len" "$file" | cut -d ' ' -f '3-18'
|
|
}
|
|
|
|
# Compare ranges of two files
|
|
_compare_range() {
|
|
file1="$1"
|
|
offset1="$2"
|
|
file2="$3"
|
|
offset2="$4"
|
|
len="$5"
|
|
|
|
cmp -s <(_read_range "$file1" "$offset1" "$len") \
|
|
<(_read_range "$file2" "$offset2" "$len")
|
|
}
|
|
|
|
# Prints the md5 checksum of a hexdump of a part of a given file
|
|
_md5_range_checksum() {
|
|
file="$1"
|
|
offset="$2"
|
|
len="$3"
|
|
|
|
md5sum <(_read_range "$file" "$offset" "$len") | cut -d ' ' -f 1
|
|
}
|
|
|
|
# Reflink some file1 into file2 via cp
|
|
_cp_reflink() {
|
|
file1="$1"
|
|
file2="$2"
|
|
|
|
cp --reflink=always -p "$file1" "$file2"
|
|
}
|
|
|
|
# Reflink some file1 into file2
|
|
_reflink() {
|
|
file1="$1"
|
|
file2="$2"
|
|
|
|
"$XFS_IO_PROG" -f -c "reflink $file1" "$file2"
|
|
}
|
|
|
|
# Reflink some part of file1 into another part of file2
|
|
_reflink_range() {
|
|
file1="$1"
|
|
offset1="$2"
|
|
file2="$3"
|
|
offset2="$4"
|
|
len="$5"
|
|
xfs_io_args="$6"
|
|
|
|
"$XFS_IO_PROG" $xfs_io_args -f -c "reflink $file1 $offset1 $offset2 $len" "$file2"
|
|
}
|
|
|
|
# Dedupe some part of file1 into another part of file2
|
|
_dedupe_range() {
|
|
file1="$1"
|
|
offset1="$2"
|
|
file2="$3"
|
|
offset2="$4"
|
|
len="$5"
|
|
xfs_io_args="$6"
|
|
|
|
"$XFS_IO_PROG" $xfs_io_args -f -c "dedupe $file1 $offset1 $offset2 $len" "$file2"
|
|
}
|
|
|
|
# Create a file of interleaved unwritten and reflinked blocks
|
|
_weave_reflink_unwritten() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile
|
|
$XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $dfile
|
|
_pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
|
|
seq 0 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
}
|
|
|
|
# Create a file of interleaved holes and reflinked blocks
|
|
_weave_reflink_holes() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile
|
|
$XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
|
|
_pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
|
|
seq 0 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
}
|
|
|
|
# For a file created with _weave_reflink_holes, fill the holes with delalloc
|
|
# extents
|
|
_weave_reflink_holes_delalloc() {
|
|
blksz=$1
|
|
nr=$2
|
|
dfile=$3
|
|
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
|
|
_pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
}
|
|
|
|
# Create a file of interleaved regular blocks and reflinked blocks
|
|
_weave_reflink_regular() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile
|
|
_pwrite_byte 0x62 0 $((blksz * nr)) $dfile
|
|
_pwrite_byte 0x62 0 $((blksz * nr)) $dfile.chk
|
|
seq 0 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
}
|
|
|
|
# Create a file of interleaved holes, unwritten blocks, regular blocks, and
|
|
# reflinked blocks
|
|
_weave_reflink_rainbow() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile
|
|
$XFS_IO_PROG -f -c "truncate $((blksz * nr))" $dfile
|
|
_pwrite_byte 0x00 0 $((blksz * nr)) $dfile.chk
|
|
# 0 blocks are reflinked
|
|
seq 0 5 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
# 1 blocks are unwritten
|
|
seq 1 5 $((nr - 1)) | while read i; do
|
|
$XFS_IO_PROG -f -c "falloc $((blksz * i)) $blksz" $dfile
|
|
_pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
# 2 blocks are holes
|
|
seq 2 5 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x00 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
# 3 blocks are regular
|
|
seq 3 5 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x71 $((blksz * i)) $blksz $dfile
|
|
_pwrite_byte 0x71 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
# 4 blocks will be delalloc later
|
|
}
|
|
|
|
# For a file created with _weave_reflink_rainbow, fill the holes with delalloc
|
|
# extents
|
|
_weave_reflink_rainbow_delalloc() {
|
|
blksz=$1
|
|
nr=$2
|
|
dfile=$3
|
|
|
|
# 4 blocks are delalloc (do later)
|
|
seq 4 5 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x62 $((blksz * i)) $blksz $dfile
|
|
_pwrite_byte 0x62 $((blksz * i)) $blksz $dfile.chk
|
|
done
|
|
}
|
|
|
|
# Make the source file have interleaved regular blocks and reflinked blocks
|
|
_sweave_reflink_regular() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile
|
|
_pwrite_byte 0x62 0 $((blksz * nr)) $dfile
|
|
_pwrite_byte 0x61 0 $((blksz * nr)) $sfile.chk
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
done
|
|
}
|
|
|
|
# Make the source file have interleaved unwritten blocks and reflinked blocks
|
|
_sweave_reflink_unwritten() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
$XFS_IO_PROG -f -c "falloc 0 $((blksz * nr))" $sfile
|
|
_pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
|
|
_pwrite_byte 0x62 0 $((blksz * nr)) $dfile
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
|
|
done
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
done
|
|
}
|
|
|
|
# Make the source file have interleaved holes and reflinked blocks
|
|
_sweave_reflink_holes() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
dfile=$4
|
|
|
|
$XFS_IO_PROG -f -c "truncate $((blksz * nr))" $sfile
|
|
_pwrite_byte 0x00 0 $((blksz * nr)) $sfile.chk
|
|
_pwrite_byte 0x62 0 $((blksz * nr)) $dfile
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $sfile
|
|
_pwrite_byte 0x61 $((blksz * i)) $blksz $sfile.chk
|
|
done
|
|
seq 1 2 $((nr - 1)) | while read i; do
|
|
_reflink_range $sfile $((blksz * i)) $dfile $((blksz * i)) $blksz
|
|
done
|
|
}
|
|
|
|
# For a file created with _sweave_reflink_holes, fill the holes with delalloc
|
|
# extents
|
|
_sweave_reflink_holes_delalloc() {
|
|
blksz=$1
|
|
nr=$2
|
|
sfile=$3
|
|
|
|
seq 0 2 $((nr - 1)) | while read i; do
|
|
_pwrite_byte 0x64 $((blksz * i)) $blksz $sfile
|
|
_pwrite_byte 0x64 $((blksz * i)) $blksz $sfile.chk
|
|
done
|
|
}
|