mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
c3cb6fbde7
Add _require_scratch_duperemove which validates that the file system supports duperemove. This allows us to move three tests from shared/ to generic/. This means these tests will automatically adapt when duperemove supports other file systems. Tests moved are: shared/008 --> generic/559 shared/009 --> generic/560 shared/010 --> generic/561 Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Eryu Guan <guaneryu@gmail.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
429 lines
12 KiB
Plaintext
429 lines
12 KiB
Plaintext
##/bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0+
|
|
# Copyright (c) 2015 Oracle. All Rights Reserved.
|
|
#
|
|
# Routines for reflinking, deduping, and comparing parts of files.
|
|
|
|
# Check that cp has a reflink argument
|
|
_require_cp_reflink()
|
|
{
|
|
cp --help | grep -q reflink || \
|
|
_notrun "This test requires a cp with --reflink support."
|
|
}
|
|
|
|
# Can we reflink between arbitrary file sets?
|
|
# i.e. if we reflink a->b and c->d, can we later share
|
|
# blocks between b & c?
|
|
_supports_arbitrary_fileset_reflink()
|
|
{
|
|
test "$FSTYP" != "ocfs2"
|
|
}
|
|
|
|
_require_arbitrary_fileset_reflink()
|
|
{
|
|
_supports_arbitrary_fileset_reflink ||
|
|
_notrun "reflink between arbitrary file groups not supported in $FSTYP"
|
|
}
|
|
|
|
# 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 duperemove working for the file system
|
|
_require_scratch_duperemove()
|
|
{
|
|
_require_scratch
|
|
_require_command "$DUPEREMOVE_PROG" duperemove
|
|
|
|
_scratch_mkfs > /dev/null
|
|
_scratch_mount
|
|
dd if=/dev/zero of="$SCRATCH_MNT/file1" bs=128k count=1 >& /dev/null
|
|
dd if=/dev/zero of="$SCRATCH_MNT/file2" bs=128k count=1 >& /dev/null
|
|
if ! "$DUPEREMOVE_PROG" -d "$SCRATCH_MNT/file1" \
|
|
"$SCRATCH_MNT/file2" >& /dev/null ; then
|
|
_scratch_unmount
|
|
_notrun "duperemove does not support file system type: $FSTYP"
|
|
fi
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires scratch fs to report explicit SHARED flag
|
|
# e.g.
|
|
# 0 4K 8K
|
|
# / File1: Extent 0 \
|
|
# / \
|
|
# |<- On disk Extent-->|
|
|
# | /
|
|
# | File2 /
|
|
# Extent: 0
|
|
# Fs supports explicit SHARED extent reporting should report fiemap like:
|
|
# File1: 2 extents
|
|
# Extent 0-4K: SHARED
|
|
# Extent 4-8K:
|
|
# File2: 1 extents
|
|
# Extent 0-4K: SHARED
|
|
#
|
|
# Fs doesn't support explicit reporting will report fiemap like:
|
|
# File1: 1 extent
|
|
# Extent 0-8K: SHARED
|
|
# File2: 1 extent
|
|
# Extent 0-4K: SHARED
|
|
_require_scratch_explicit_shared_extents()
|
|
{
|
|
_require_scratch
|
|
_require_xfs_io_command "fiemap"
|
|
_require_scratch_reflink
|
|
_require_xfs_io_command "reflink"
|
|
local nr_extents
|
|
|
|
_scratch_mkfs > /dev/null
|
|
_scratch_mount
|
|
|
|
_pwrite_byte 0x61 0 128k $SCRATCH_MNT/file1 >/dev/null
|
|
_reflink_range $SCRATCH_MNT/file1 0 $SCRATCH_MNT/file2 0 64k >/dev/null
|
|
|
|
_scratch_cycle_mount
|
|
|
|
nr_extents=$(_count_extents $SCRATCH_MNT/file1)
|
|
if [ $nr_extents -eq 1 ]; then
|
|
_notrun "Explicit SHARED flag reporting not support by 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 $SCRATCH_MNT/file1 0 0 65536" "$SCRATCH_MNT/file2" 2>&1)"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Inappropriate ioctl for device" && \
|
|
_notrun "Dedupe not supported by scratch filesystem type: $FSTYP"
|
|
echo $testio | grep -q "Invalid argument" && \
|
|
_notrun "Dedupe not supported by scratch 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 -f "$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"
|
|
}
|
|
|
|
# Unify xfs_io dedupe ioctl error message prefix
|
|
_filter_dedupe_error()
|
|
{
|
|
sed -e 's/^dedupe:/XFS_IOC_FILE_EXTENT_SAME:/g'
|
|
}
|
|
|
|
# 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
|
|
}
|