##/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 "$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 fs of certain blocksize on scratch device # _scratch_mkfs_blocksized blocksize _scratch_mkfs_blocksized() { blocksize=$1 re='^[0-9]+$' if ! [[ $blocksize =~ $re ]] ; then _notrun "error: _scratch_mkfs_sized: block size \"$blocksize\" not an integer." fi case $FSTYP in xfs) # don't override MKFS_OPTIONS that set a block size. echo $MKFS_OPTIONS |egrep -q "b?size=" if [ $? -eq 0 ]; then _scratch_mkfs_xfs else _scratch_mkfs_xfs -b size=$blocksize fi ;; ext2|ext3|ext4|ocfs2) ${MKFS_PROG}.$FSTYP -F $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV ;; *) _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_blocksized" ;; esac }