diff --git a/tests/zfs-tests/tests/functional/bclone/bclone_common.kshlib b/tests/zfs-tests/tests/functional/bclone/bclone_common.kshlib index 3b8eaea5bb54..84b92b4dcdc9 100644 --- a/tests/zfs-tests/tests/functional/bclone/bclone_common.kshlib +++ b/tests/zfs-tests/tests/functional/bclone/bclone_common.kshlib @@ -1,286 +1,291 @@ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or https://opensource.org/licenses/CDDL-1.0. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2023 by Pawel Jakub Dawidek # . $STF_SUITE/tests/functional/bclone/bclone.cfg export RECORDSIZE=$(zfs get -Hp -o value recordsize $TESTPOOL/$TESTFS) MINBLKSIZE1=512 MINBLKSIZE2=1024 function verify_block_cloning { if is_linux && [[ $(linux_version) -lt $(linux_version "4.5") ]]; then log_unsupported "copy_file_range not available before Linux 4.5" fi } function verify_crossfs_block_cloning { if is_linux && [[ $(linux_version) -lt $(linux_version "5.3") ]]; then log_unsupported "copy_file_range can't copy cross-filesystem before Linux 5.3" fi # Cross dataset block cloning only supported on FreeBSD 14+ # https://github.com/freebsd/freebsd-src/commit/969071be938c if is_freebsd && [ $(freebsd_version) -lt $(freebsd_version 14.0) ] ; then log_unsupported "Cloning across datasets not supported in $(uname -r)" fi } # Unused. function size_to_dsize { typeset -r size=$1 typeset -r dir=$2 typeset -r dataset=$(df $dir | tail -1 | awk '{print $1}') typeset -r recordsize=$(get_prop recordsize $dataset) typeset -r copies=$(get_prop copies $dataset) typeset dsize if [[ $size -le $recordsize ]]; then dsize=$(( ((size - 1) / MINBLOCKSIZE + 1) * MINBLOCKSIZE )) else dsize=$(( ((size - 1) / recordsize + 1) * recordsize )) fi dsize=$((dsize*copies)) echo $dsize } function test_file_integrity { typeset -r original_checksum=$1 typeset -r clone=$2 typeset -r filesize=$3 typeset -r clone_checksum=$(sha256digest $clone) if [[ $original_checksum != $clone_checksum ]]; then log_fail "Clone $clone is corrupted with file size $filesize" fi } function verify_pool_prop_eq { typeset -r prop=$1 typeset -r expected=$2 typeset -r value=$(get_pool_prop $prop $TESTPOOL) if [[ $value != $expected ]]; then log_fail "Pool property $prop is incorrect: expected $expected, got $value" fi } function verify_pool_props { - typeset -r dsize=$1 - typeset -r ratio=$2 + typeset -r oused=$1 + typeset -r osaved=$2 + typeset dsize=$3 + typeset ratio=$4 if [[ $dsize -eq 0 ]]; then - verify_pool_prop_eq bcloneused 0 - verify_pool_prop_eq bclonesaved 0 - verify_pool_prop_eq bcloneratio 1.00 - else - if [[ $ratio -eq 1 ]]; then - verify_pool_prop_eq bcloneused 0 - else - verify_pool_prop_eq bcloneused $dsize - fi - verify_pool_prop_eq bclonesaved $((dsize*(ratio-1))) + ratio=1 + elif [[ $ratio -eq 1 ]]; then + dsize=0 + fi + verify_pool_prop_eq bcloneused $(($oused+$dsize)) + verify_pool_prop_eq bclonesaved $(($osaved+dsize*(ratio-1))) + if [[ $oused -eq 0 ]]; then verify_pool_prop_eq bcloneratio "${ratio}.00" fi } # Function to test file copying and integrity check. function bclone_test { typeset -r datatype=$1 typeset filesize=$2 typeset -r embedded=$3 typeset -r srcdir=$4 typeset -r dstdir=$5 typeset dsize + typeset oused + typeset osaved typeset -r original="${srcdir}/original" typeset -r clone="${dstdir}/clone" log_note "Testing file copy with datatype $datatype, file size $filesize, embedded $embedded" + # Save current block cloning stats for later use. + sync_pool $TESTPOOL + oused=$(get_pool_prop bcloneused $TESTPOOL) + osaved=$(get_pool_prop bclonesaved $TESTPOOL) + # Create a test file with known content. case $datatype in random|text) - sync_pool $TESTPOOL if [[ $datatype = "random" ]]; then dd if=/dev/urandom of=$original bs=$filesize count=1 2>/dev/null else filesize=$(((filesize/4)*4)) dd if=/dev/urandom bs=$(((filesize/4)*3)) count=1 | \ openssl base64 -A > $original fi sync_pool $TESTPOOL clonefile -f $original "${clone}-tmp" sync_pool $TESTPOOL # It is hard to predict block sizes that will be used, # so just do one clone and take it from bcloneused. - filesize=$(zpool get -Hp -o value bcloneused $TESTPOOL) + dsize=$(get_pool_prop bcloneused $TESTPOOL) + dsize=$(($dsize-$oused)) if [[ $embedded = "false" ]]; then - log_must test $filesize -gt 0 + log_must test $dsize -gt 0 fi rm -f "${clone}-tmp" sync_pool $TESTPOOL - dsize=$filesize ;; hole) log_must truncate_test -s $filesize -f $original dsize=0 ;; *) log_fail "Unknown datatype $datatype" ;; esac if [[ $embedded = "true" ]]; then dsize=0 fi typeset -r original_checksum=$(sha256digest $original) sync_pool $TESTPOOL # Create a first clone of the entire file. clonefile -f $original "${clone}0" # Try to clone the clone in the same transaction group. clonefile -f "${clone}0" "${clone}2" # Clone the original again... clonefile -f $original "${clone}1" # ...and overwrite it in the same transaction group. clonefile -f $original "${clone}1" # Clone the clone... clonefile -f "${clone}1" "${clone}3" sync_pool $TESTPOOL # ...and overwrite in the new transaction group. clonefile -f "${clone}1" "${clone}3" sync_pool $TESTPOOL # Test removal of the pending clones (before they are committed to disk). clonefile -f $original "${clone}4" clonefile -f "${clone}4" "${clone}5" rm -f "${clone}4" "${clone}5" # Clone into one file, but remove another file, but with the same data in # the same transaction group. clonefile -f $original "${clone}5" sync_pool $TESTPOOL clonefile -f $original "${clone}4" rm -f "${clone}5" test_file_integrity $original_checksum "${clone}4" $filesize sync_pool $TESTPOOL test_file_integrity $original_checksum "${clone}4" $filesize clonefile -f "${clone}4" "${clone}5" # Verify integrity of the cloned file before it is committed to disk. test_file_integrity $original_checksum "${clone}5" $filesize sync_pool $TESTPOOL # Verify integrity in the new transaction group. test_file_integrity $original_checksum "${clone}0" $filesize test_file_integrity $original_checksum "${clone}1" $filesize test_file_integrity $original_checksum "${clone}2" $filesize test_file_integrity $original_checksum "${clone}3" $filesize test_file_integrity $original_checksum "${clone}4" $filesize test_file_integrity $original_checksum "${clone}5" $filesize - verify_pool_props $dsize 7 + verify_pool_props $oused $osaved $dsize 7 # Clear cache and test after fresh import. log_must zpool export $TESTPOOL log_must zpool import $TESTPOOL # Cloned uncached file. clonefile -f $original "${clone}6" # Cloned uncached clone. clonefile -f "${clone}6" "${clone}7" # Cache the file. cat $original >/dev/null clonefile -f $original "${clone}8" clonefile -f "${clone}8" "${clone}9" test_file_integrity $original_checksum "${clone}6" $filesize test_file_integrity $original_checksum "${clone}7" $filesize test_file_integrity $original_checksum "${clone}8" $filesize test_file_integrity $original_checksum "${clone}9" $filesize sync_pool $TESTPOOL - verify_pool_props $dsize 11 + verify_pool_props $oused $osaved $dsize 11 log_must zpool export $TESTPOOL log_must zpool import $TESTPOOL test_file_integrity $original_checksum "${clone}0" $filesize test_file_integrity $original_checksum "${clone}1" $filesize test_file_integrity $original_checksum "${clone}2" $filesize test_file_integrity $original_checksum "${clone}3" $filesize test_file_integrity $original_checksum "${clone}4" $filesize test_file_integrity $original_checksum "${clone}5" $filesize test_file_integrity $original_checksum "${clone}6" $filesize test_file_integrity $original_checksum "${clone}7" $filesize test_file_integrity $original_checksum "${clone}8" $filesize test_file_integrity $original_checksum "${clone}9" $filesize rm -f $original rm -f "${clone}1" "${clone}3" "${clone}5" "${clone}7" sync_pool $TESTPOOL test_file_integrity $original_checksum "${clone}0" $filesize test_file_integrity $original_checksum "${clone}2" $filesize test_file_integrity $original_checksum "${clone}4" $filesize test_file_integrity $original_checksum "${clone}6" $filesize test_file_integrity $original_checksum "${clone}8" $filesize test_file_integrity $original_checksum "${clone}9" $filesize - verify_pool_props $dsize 6 + verify_pool_props $oused $osaved $dsize 6 rm -f "${clone}0" "${clone}2" "${clone}4" "${clone}8" "${clone}9" sync_pool $TESTPOOL test_file_integrity $original_checksum "${clone}6" $filesize - verify_pool_props $dsize 1 + verify_pool_props $oused $osaved $dsize 1 rm -f "${clone}6" sync_pool $TESTPOOL - verify_pool_props $dsize 1 + verify_pool_props $oused $osaved $dsize 1 }