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