1# SPDX-License-Identifier: CDDL-1.0 2# 3# CDDL HEADER START 4# 5# The contents of this file are subject to the terms of the 6# Common Development and Distribution License (the "License"). 7# You may not use this file except in compliance with the License. 8# 9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10# or https://opensource.org/licenses/CDDL-1.0. 11# See the License for the specific language governing permissions 12# and limitations under the License. 13# 14# When distributing Covered Code, include this CDDL HEADER in each 15# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16# If applicable, add the following below this CDDL HEADER, with the 17# fields enclosed by brackets "[]" replaced with your own identifying 18# information: Portions Copyright [yyyy] [name of copyright owner] 19# 20# CDDL HEADER END 21# 22 23# 24# Copyright (c) 2023 by Pawel Jakub Dawidek 25# 26 27. $STF_SUITE/tests/functional/bclone/bclone.cfg 28 29export RECORDSIZE=$(zfs get -Hp -o value recordsize $TESTPOOL/$TESTFS) 30 31MINBLKSIZE1=512 32MINBLKSIZE2=1024 33 34function verify_crossfs_block_cloning 35{ 36 if is_linux && [[ $(linux_version) -lt $(linux_version "5.3") ]]; then 37 log_unsupported "copy_file_range can't copy cross-filesystem before Linux 5.3" 38 fi 39 40 # Cross dataset block cloning only supported on FreeBSD 14+ 41 # https://github.com/freebsd/freebsd-src/commit/969071be938c 42 if is_freebsd && [ $(freebsd_version) -lt $(freebsd_version 14.0) ] ; then 43 log_unsupported "Cloning across datasets not supported in $(uname -r)" 44 fi 45} 46 47# Unused. 48function size_to_dsize 49{ 50 typeset -r size=$1 51 typeset -r dir=$2 52 53 typeset -r dataset=$(df $dir | tail -1 | awk '{print $1}') 54 typeset -r recordsize=$(get_prop recordsize $dataset) 55 typeset -r copies=$(get_prop copies $dataset) 56 typeset dsize 57 58 if [[ $size -le $recordsize ]]; then 59 dsize=$(( ((size - 1) / MINBLOCKSIZE + 1) * MINBLOCKSIZE )) 60 else 61 dsize=$(( ((size - 1) / recordsize + 1) * recordsize )) 62 fi 63 dsize=$((dsize*copies)) 64 65 echo $dsize 66} 67 68function test_file_integrity 69{ 70 typeset -r original_checksum=$1 71 typeset -r clone=$2 72 typeset -r filesize=$3 73 74 typeset -r clone_checksum=$(xxh128digest $clone) 75 76 if [[ $original_checksum != $clone_checksum ]]; then 77 log_fail "Clone $clone is corrupted with file size $filesize" 78 fi 79} 80 81function verify_pool_prop_eq 82{ 83 typeset -r prop=$1 84 typeset -r expected=$2 85 86 typeset -r value=$(get_pool_prop $prop $TESTPOOL) 87 if [[ $value != $expected ]]; then 88 log_fail "Pool property $prop is incorrect: expected $expected, got $value" 89 fi 90} 91 92function verify_pool_props 93{ 94 typeset -r oused=$1 95 typeset -r osaved=$2 96 typeset dsize=$3 97 typeset ratio=$4 98 99 if [[ $dsize -eq 0 ]]; then 100 ratio=1 101 elif [[ $ratio -eq 1 ]]; then 102 dsize=0 103 fi 104 verify_pool_prop_eq bcloneused $(($oused+$dsize)) 105 verify_pool_prop_eq bclonesaved $(($osaved+dsize*(ratio-1))) 106 if [[ $oused -eq 0 ]]; then 107 verify_pool_prop_eq bcloneratio "${ratio}.00" 108 fi 109} 110 111# Function to test file copying and integrity check. 112function bclone_test 113{ 114 typeset -r datatype=$1 115 typeset filesize=$2 116 typeset -r embedded=$3 117 typeset -r srcdir=$4 118 typeset -r dstdir=$5 119 typeset dsize 120 typeset oused 121 typeset osaved 122 123 typeset -r original="${srcdir}/original" 124 typeset -r clone="${dstdir}/clone" 125 126 log_note "Testing file copy with datatype $datatype, file size $filesize, embedded $embedded" 127 128 # Save current block cloning stats for later use. 129 sync_pool $TESTPOOL 130 oused=$(get_pool_prop bcloneused $TESTPOOL) 131 osaved=$(get_pool_prop bclonesaved $TESTPOOL) 132 133 # Create a test file with known content. 134 case $datatype in 135 random|text) 136 if [[ $datatype = "random" ]]; then 137 dd if=/dev/urandom of=$original bs=$filesize count=1 2>/dev/null 138 else 139 filesize=$(((filesize/4)*4)) 140 dd if=/dev/urandom bs=$(((filesize/4)*3)) count=1 | \ 141 openssl base64 -A > $original 142 fi 143 sync_pool $TESTPOOL 144 clonefile -f $original "${clone}-tmp" 145 sync_pool $TESTPOOL 146 # It is hard to predict block sizes that will be used, 147 # so just do one clone and take it from bcloneused. 148 dsize=$(get_pool_prop bcloneused $TESTPOOL) 149 dsize=$(($dsize-$oused)) 150 if [[ $embedded = "false" ]]; then 151 log_must test $dsize -gt 0 152 fi 153 rm -f "${clone}-tmp" 154 sync_pool $TESTPOOL 155 ;; 156 hole) 157 log_must truncate_test -s $filesize -f $original 158 dsize=0 159 ;; 160 *) 161 log_fail "Unknown datatype $datatype" 162 ;; 163 esac 164 if [[ $embedded = "true" ]]; then 165 dsize=0 166 fi 167 168 typeset -r original_checksum=$(xxh128digest $original) 169 170 sync_pool $TESTPOOL 171 172 # Create a first clone of the entire file. 173 clonefile -f $original "${clone}0" 174 # Try to clone the clone in the same transaction group. 175 clonefile -f "${clone}0" "${clone}2" 176 177 # Clone the original again... 178 clonefile -f $original "${clone}1" 179 # ...and overwrite it in the same transaction group. 180 clonefile -f $original "${clone}1" 181 182 # Clone the clone... 183 clonefile -f "${clone}1" "${clone}3" 184 sync_pool $TESTPOOL 185 # ...and overwrite in the new transaction group. 186 clonefile -f "${clone}1" "${clone}3" 187 188 sync_pool $TESTPOOL 189 190 # Test removal of the pending clones (before they are committed to disk). 191 clonefile -f $original "${clone}4" 192 clonefile -f "${clone}4" "${clone}5" 193 rm -f "${clone}4" "${clone}5" 194 195 # Clone into one file, but remove another file, but with the same data in 196 # the same transaction group. 197 clonefile -f $original "${clone}5" 198 sync_pool $TESTPOOL 199 clonefile -f $original "${clone}4" 200 rm -f "${clone}5" 201 test_file_integrity $original_checksum "${clone}4" $filesize 202 sync_pool $TESTPOOL 203 test_file_integrity $original_checksum "${clone}4" $filesize 204 205 clonefile -f "${clone}4" "${clone}5" 206 # Verify integrity of the cloned file before it is committed to disk. 207 test_file_integrity $original_checksum "${clone}5" $filesize 208 209 sync_pool $TESTPOOL 210 211 # Verify integrity in the new transaction group. 212 test_file_integrity $original_checksum "${clone}0" $filesize 213 test_file_integrity $original_checksum "${clone}1" $filesize 214 test_file_integrity $original_checksum "${clone}2" $filesize 215 test_file_integrity $original_checksum "${clone}3" $filesize 216 test_file_integrity $original_checksum "${clone}4" $filesize 217 test_file_integrity $original_checksum "${clone}5" $filesize 218 219 verify_pool_props $oused $osaved $dsize 7 220 221 # Clear cache and test after fresh import. 222 log_must zpool export $TESTPOOL 223 log_must zpool import $TESTPOOL 224 225 # Cloned uncached file. 226 clonefile -f $original "${clone}6" 227 # Cloned uncached clone. 228 clonefile -f "${clone}6" "${clone}7" 229 230 # Cache the file. 231 cat $original >/dev/null 232 clonefile -f $original "${clone}8" 233 clonefile -f "${clone}8" "${clone}9" 234 235 test_file_integrity $original_checksum "${clone}6" $filesize 236 test_file_integrity $original_checksum "${clone}7" $filesize 237 test_file_integrity $original_checksum "${clone}8" $filesize 238 test_file_integrity $original_checksum "${clone}9" $filesize 239 240 sync_pool $TESTPOOL 241 242 verify_pool_props $oused $osaved $dsize 11 243 244 log_must zpool export $TESTPOOL 245 log_must zpool import $TESTPOOL 246 247 test_file_integrity $original_checksum "${clone}0" $filesize 248 test_file_integrity $original_checksum "${clone}1" $filesize 249 test_file_integrity $original_checksum "${clone}2" $filesize 250 test_file_integrity $original_checksum "${clone}3" $filesize 251 test_file_integrity $original_checksum "${clone}4" $filesize 252 test_file_integrity $original_checksum "${clone}5" $filesize 253 test_file_integrity $original_checksum "${clone}6" $filesize 254 test_file_integrity $original_checksum "${clone}7" $filesize 255 test_file_integrity $original_checksum "${clone}8" $filesize 256 test_file_integrity $original_checksum "${clone}9" $filesize 257 258 rm -f $original 259 rm -f "${clone}1" "${clone}3" "${clone}5" "${clone}7" 260 261 sync_pool $TESTPOOL 262 263 test_file_integrity $original_checksum "${clone}0" $filesize 264 test_file_integrity $original_checksum "${clone}2" $filesize 265 test_file_integrity $original_checksum "${clone}4" $filesize 266 test_file_integrity $original_checksum "${clone}6" $filesize 267 test_file_integrity $original_checksum "${clone}8" $filesize 268 test_file_integrity $original_checksum "${clone}9" $filesize 269 270 verify_pool_props $oused $osaved $dsize 6 271 272 rm -f "${clone}0" "${clone}2" "${clone}4" "${clone}8" "${clone}9" 273 274 sync_pool $TESTPOOL 275 276 test_file_integrity $original_checksum "${clone}6" $filesize 277 278 verify_pool_props $oused $osaved $dsize 1 279 280 rm -f "${clone}6" 281 282 sync_pool $TESTPOOL 283 284 verify_pool_props $oused $osaved $dsize 1 285} 286