1#! /bin/ksh -p 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/include/libtest.shlib 28. $STF_SUITE/include/math.shlib 29. $STF_SUITE/tests/functional/bclone/bclone_common.kshlib 30 31function first_half_checksum 32{ 33 typeset -r file=$1 34 35 dd if=$file bs=$HALFRECORDSIZE count=1 2>/dev/null | sha256digest 36} 37 38function second_half_checksum 39{ 40 typeset -r file=$1 41 42 dd if=$file bs=$HALFRECORDSIZE count=1 skip=1 2>/dev/null | sha256digest 43} 44 45function bclone_corner_cases_init 46{ 47 typeset -r srcdir=$1 48 typeset -r dstdir=$2 49 50 export RECORDSIZE=4096 51 export HALFRECORDSIZE=$((RECORDSIZE / 2)) 52 53 export CLONE="$dstdir/clone0" 54 export ORIG0="$srcdir/orig0" 55 export ORIG1="$srcdir/orig1" 56 export ORIG2="$srcdir/orig2" 57 58 # Create source files. 59 log_must dd if=/dev/urandom of="$ORIG0" bs=$RECORDSIZE count=1 60 log_must dd if=/dev/urandom of="$ORIG1" bs=$RECORDSIZE count=1 61 log_must dd if=/dev/urandom of="$ORIG2" bs=$RECORDSIZE count=1 62 63 export FIRST_HALF_ORIG0_CHECKSUM=$(first_half_checksum $ORIG0) 64 export FIRST_HALF_ORIG1_CHECKSUM=$(first_half_checksum $ORIG1) 65 export FIRST_HALF_ORIG2_CHECKSUM=$(first_half_checksum $ORIG2) 66 export SECOND_HALF_ORIG0_CHECKSUM=$(second_half_checksum $ORIG0) 67 export SECOND_HALF_ORIG1_CHECKSUM=$(second_half_checksum $ORIG1) 68 export SECOND_HALF_ORIG2_CHECKSUM=$(second_half_checksum $ORIG2) 69 export ZEROS_CHECKSUM=$(dd if=/dev/zero bs=$HALFRECORDSIZE count=1 2>/dev/null | sha256digest) 70 export FIRST_HALF_CHECKSUM="" 71 export SECOND_HALF_CHECKSUM="" 72} 73 74function cache_clone 75{ 76 typeset -r cached=$1 77 78 case "$cached" in 79 "cached") 80 dd if=$CLONE of=/dev/null bs=$RECORDSIZE 2>/dev/null 81 ;; 82 "uncached") 83 ;; 84 *) 85 log_fail "invalid cached: $cached" 86 ;; 87 esac 88} 89 90function create_existing 91{ 92 typeset -r existing=$1 93 94 case "$existing" in 95 "no") 96 ;; 97 "small empty") 98 log_must truncate_test -s $HALFRECORDSIZE -f $CLONE 99 ;; 100 "full empty") 101 log_must truncate_test -s $RECORDSIZE -f $CLONE 102 ;; 103 "small data") 104 log_must dd if=/dev/urandom of=$CLONE bs=$HALFRECORDSIZE count=1 \ 105 2>/dev/null 106 ;; 107 "full data") 108 log_must dd if=/dev/urandom of=$CLONE bs=$RECORDSIZE count=1 2>/dev/null 109 ;; 110 *) 111 log_fail "invalid existing: $existing" 112 ;; 113 esac 114} 115 116function create_clone 117{ 118 typeset -r clone=$1 119 typeset -r file=$2 120 121 case "$clone" in 122 "no") 123 ;; 124 "yes") 125 clonefile -f $file $CLONE 126 case "$file" in 127 $ORIG0) 128 FIRST_HALF_CHECKSUM=$FIRST_HALF_ORIG0_CHECKSUM 129 SECOND_HALF_CHECKSUM=$SECOND_HALF_ORIG0_CHECKSUM 130 ;; 131 $ORIG2) 132 FIRST_HALF_CHECKSUM=$FIRST_HALF_ORIG2_CHECKSUM 133 SECOND_HALF_CHECKSUM=$SECOND_HALF_ORIG2_CHECKSUM 134 ;; 135 *) 136 log_fail "invalid file: $file" 137 ;; 138 esac 139 ;; 140 *) 141 log_fail "invalid clone: $clone" 142 ;; 143 esac 144} 145 146function overwrite_clone 147{ 148 typeset -r overwrite=$1 149 150 case "$overwrite" in 151 "no") 152 ;; 153 "free") 154 log_must truncate_test -s 0 -f $CLONE 155 log_must truncate_test -s $RECORDSIZE -f $CLONE 156 FIRST_HALF_CHECKSUM=$ZEROS_CHECKSUM 157 SECOND_HALF_CHECKSUM=$ZEROS_CHECKSUM 158 ;; 159 "full") 160 log_must dd if=$ORIG1 of=$CLONE bs=$RECORDSIZE count=1 2>/dev/null 161 FIRST_HALF_CHECKSUM=$FIRST_HALF_ORIG1_CHECKSUM 162 SECOND_HALF_CHECKSUM=$SECOND_HALF_ORIG1_CHECKSUM 163 ;; 164 "first half") 165 log_must dd if=$ORIG1 of=$CLONE bs=$HALFRECORDSIZE skip=0 seek=0 \ 166 count=1 conv=notrunc 2>/dev/null 167 FIRST_HALF_CHECKSUM=$FIRST_HALF_ORIG1_CHECKSUM 168 ;; 169 "second half") 170 log_must dd if=$ORIG1 of=$CLONE bs=$HALFRECORDSIZE skip=1 seek=1 \ 171 count=1 conv=notrunc 2>/dev/null 172 SECOND_HALF_CHECKSUM=$SECOND_HALF_ORIG1_CHECKSUM 173 ;; 174 *) 175 log_fail "invalid overwrite: $overwrite" 176 ;; 177 esac 178} 179 180function checksum_compare 181{ 182 typeset -r compare=$1 183 typeset first_half_calculated_checksum second_half_calculated_checksum 184 185 case "$compare" in 186 "no") 187 ;; 188 "yes") 189 first_half_calculated_checksum=$(first_half_checksum $CLONE) 190 second_half_calculated_checksum=$(second_half_checksum $CLONE) 191 192 if [[ $first_half_calculated_checksum != $FIRST_HALF_CHECKSUM ]] || \ 193 [[ $second_half_calculated_checksum != $SECOND_HALF_CHECKSUM ]]; then 194 return 1 195 fi 196 ;; 197 *) 198 log_fail "invalid compare: $compare" 199 ;; 200 esac 201} 202 203function bclone_corner_cases_test 204{ 205 typeset cached existing 206 typeset first_clone first_overwrite 207 typeset read_after read_before 208 typeset second_clone second_overwrite 209 typeset -r srcdir=$1 210 typeset -r dstdir=$2 211 typeset limit=$3 212 typeset -i count=0 213 typeset oused 214 typeset osaved 215 216 if [[ $srcdir != "count" ]]; then 217 if [[ -n "$limit" ]]; then 218 typeset -r total_count=$(bclone_corner_cases_test count) 219 limit=$(random_int_between 1 $total_count $((limit*2)) | sort -nu | head -n $limit | xargs) 220 fi 221 bclone_corner_cases_init $srcdir $dstdir 222 223 # Save current block cloning stats for later use. 224 sync_pool $TESTPOOL 225 oused=$(get_pool_prop bcloneused $TESTPOOL) 226 osaved=$(get_pool_prop bclonesaved $TESTPOOL) 227 fi 228 229 # 230 # (create) / (cache) / (clone) / (overwrite) / (read) / (clone) / (overwrite) / (read) / read next txg 231 # 232 for existing in "no" "small empty" "full empty" "small data" "full data"; do 233 for cached in "uncached" "cached"; do 234 for first_clone in "no" "yes"; do 235 for first_overwrite in "no" "free" "full" "first half" "second half"; do 236 for read_before in "no" "yes"; do 237 for second_clone in "no" "yes"; do 238 for second_overwrite in "no" "free" "full" "first half" "second half"; do 239 for read_after in "no" "yes"; do 240 if [[ $first_clone = "no" ]] && \ 241 [[ $second_clone = "no" ]]; then 242 continue 243 fi 244 if [[ $first_clone = "no" ]] && \ 245 [[ $read_before = "yes" ]]; then 246 continue 247 fi 248 if [[ $second_clone = "no" ]] && \ 249 [[ $read_before = "yes" ]] && \ 250 [[ $read_after = "yes" ]]; then 251 continue 252 fi 253 254 count=$((count+1)) 255 256 if [[ $srcdir = "count" ]]; then 257 # Just counting. 258 continue 259 fi 260 261 if [[ -n "$limit" ]]; then 262 if ! echo " $limit " | grep -q " $count "; then 263 continue 264 fi 265 fi 266 267 FIRST_HALF_CHECKSUM="" 268 SECOND_HALF_CHECKSUM="" 269 270 log_must zpool export $TESTPOOL 271 log_must zpool import $TESTPOOL 272 273 create_existing "$existing" 274 275 log_must zpool export $TESTPOOL 276 log_must zpool import $TESTPOOL 277 278 cache_clone "$cached" 279 280 create_clone "$first_clone" "$ORIG0" 281 282 overwrite_clone "$first_overwrite" 283 284 if checksum_compare $read_before; then 285 log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before" 286 else 287 log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before" 288 fi 289 290 create_clone "$second_clone" "$ORIG2" 291 292 overwrite_clone "$second_overwrite" 293 294 if checksum_compare $read_after; then 295 log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after" 296 else 297 log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after" 298 fi 299 300 log_must zpool export $TESTPOOL 301 log_must zpool import $TESTPOOL 302 303 if checksum_compare "yes"; then 304 log_note "existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after / read_next_txg" 305 else 306 log_fail "FAIL: existing: $existing / cached: $cached / first_clone: $first_clone / first_overwrite: $first_overwrite / read_before: $read_before / second_clone: $second_clone / second_overwrite: $second_overwrite / read_after: $read_after / read_next_txg" 307 fi 308 309 rm -f "$CLONE" 310 sync_pool $TESTPOOL 311 verify_pool_prop_eq bcloneused $oused 312 verify_pool_prop_eq bclonesaved $osaved 313 done 314 done 315 done 316 done 317 done 318 done 319 done 320 done 321 322 if [[ $srcdir = "count" ]]; then 323 echo $count 324 fi 325} 326