1#!/bin/ksh 2 3# 4# This file and its contents are supplied under the terms of the 5# Common Development and Distribution License ("CDDL"), version 1.0. 6# You may only use this file in accordance with the terms of version 7# 1.0 of the CDDL. 8# 9# A full copy of the text of the CDDL should have accompanied this 10# source. A copy of the CDDL is also available via the Internet at 11# http://www.illumos.org/license/CDDL. 12# 13 14# 15# Copyright (c) 2021 by vStack. All rights reserved. 16# 17 18. "$STF_SUITE"/include/libtest.shlib 19. "$STF_SUITE"/include/blkdev.shlib 20 21# 22# Description: 23# 24# Test whether zhack label repair commands can recover detached devices 25# and corrupted checksums with a variety of sizes, and ensure 26# the purposes of either command is cleanly separated from the others. 27# 28# Strategy: 29# 30# Tests are done on loopback devices with sizes divisible by label size and sizes that are not. 31# 32# Test one: 33# 34# 1. Create pool on a loopback device with some test data 35# 2. Export the pool. 36# 3. Corrupt all label checksums in the pool 37# 4. Check that pool cannot be imported 38# 5. Verify that it cannot be imported after using zhack label repair -u 39# to ensure that the -u option will quit on corrupted checksums. 40# 6. Use zhack label repair -c on device 41# 7. Check that pool can be imported and that data is intact 42# 43# Test two: 44# 45# 1. Create pool on a loopback device with some test data 46# 2. Detach either device from the mirror 47# 3. Export the pool 48# 4. Remove the non-detached device and its backing file 49# 5. Verify that the remaining detached device cannot be imported 50# 6. Verify that it cannot be imported after using zhack label repair -c 51# to ensure that the -c option will not undetach a device. 52# 7. Use zhack label repair -u on device 53# 8. Verify that the detached device can be imported and that data is intact 54# 55# Test three: 56# 57# 1. Create pool on a loopback device with some test data 58# 2. Detach either device from the mirror 59# 3. Export the pool 60# 4. Remove the non-detached device and its backing file 61# 5. Corrupt all label checksums on the remaining device 62# 6. Verify that the remaining detached device cannot be imported 63# 7. Verify that it cannot be imported after using zhack label repair -u 64# to ensure that the -u option will quit on corrupted checksums. 65# 8. Verify that it cannot be imported after using zhack label repair -c 66# -c should repair the checksums, but not undetach a device. 67# 9. Use zhack label repair -u on device 68# 10. Verify that the detached device can be imported and that data is intact 69# 70# Test four: 71# 72# 1. Create pool on a loopback device with some test data 73# 2. Detach either device from the mirror 74# 3. Export the pool 75# 4. Remove the non-detached device and its backing file 76# 5. Corrupt all label checksums on the remaining device 77# 6. Verify that the remaining detached device cannot be imported 78# 7. Use zhack label repair -cu on device to attempt to fix checksums and 79# undetach the device in a single operation. 80# 8. Verify that the detached device can be imported and that data is intact 81# 82 83log_assert "Verify zhack label repair <operation> <vdev> will repair label checksums and uberblocks" 84log_onexit cleanup 85 86LABEL_SIZE="$((2**18))" 87LABEL_NVLIST_END="$((LABEL_SIZE / 2))" 88LABEL_CKSUM_SIZE="32" 89LABEL_CKSUM_START="$(( LABEL_NVLIST_END - LABEL_CKSUM_SIZE ))" 90 91VIRTUAL_DISK=$TEST_BASE_DIR/disk 92VIRTUAL_MIRROR_DISK=$TEST_BASE_DIR/mirrordisk 93 94VIRTUAL_DEVICE= 95VIRTUAL_MIRROR_DEVICE= 96 97function cleanup_lo 98{ 99 L_DEVICE="$1" 100 101 if [[ -e $L_DEVICE ]]; then 102 if is_linux; then 103 log_must losetup -d "$L_DEVICE" 104 elif is_freebsd; then 105 log_must mdconfig -d -u "$L_DEVICE" 106 else 107 log_must lofiadm -d "$L_DEVICE" 108 fi 109 fi 110} 111 112function cleanup 113{ 114 poolexists "$TESTPOOL" && destroy_pool "$TESTPOOL" 115 cleanup_lo "$VIRTUAL_DEVICE" 116 cleanup_lo "$VIRTUAL_MIRROR_DEVICE" 117 VIRTUAL_DEVICE= 118 VIRTUAL_MIRROR_DEVICE= 119 [[ -f "$VIRTUAL_DISK" ]] && log_must rm "$VIRTUAL_DISK" 120 [[ -f "$VIRTUAL_MIRROR_DISK" ]] && log_must rm "$VIRTUAL_MIRROR_DISK" 121} 122 123RAND_MAX="$((2**15 - 1))" 124function get_devsize 125{ 126 if [ "$RANDOM" -gt "$(( RAND_MAX / 2 ))" ]; then 127 echo "$(( MINVDEVSIZE + RANDOM ))" 128 else 129 echo "$MINVDEVSIZE" 130 fi 131} 132 133function pick_logop 134{ 135 L_SHOULD_SUCCEED="$1" 136 137 l_logop="log_mustnot" 138 if [ "$L_SHOULD_SUCCEED" == true ]; then 139 l_logop="log_must" 140 fi 141 142 echo "$l_logop" 143} 144 145function check_dataset 146{ 147 L_SHOULD_SUCCEED="$1" 148 L_LOGOP="$(pick_logop "$L_SHOULD_SUCCEED")" 149 150 "$L_LOGOP" mounted "$TESTPOOL"/"$TESTFS" 151 152 "$L_LOGOP" test -f "$TESTDIR"/"test" 153} 154 155function setup_dataset 156{ 157 log_must zfs create "$TESTPOOL"/"$TESTFS" 158 159 log_must mkdir -p "$TESTDIR" 160 log_must zfs set mountpoint="$TESTDIR" "$TESTPOOL"/"$TESTFS" 161 162 log_must mounted "$TESTPOOL"/"$TESTFS" 163 164 log_must touch "$TESTDIR"/"test" 165 log_must test -f "$TESTDIR"/"test" 166 167 log_must zpool sync "$TESTPOOL" 168 169 check_dataset true 170} 171 172function get_practical_size 173{ 174 L_SIZE="$1" 175 176 if [ "$((L_SIZE % LABEL_SIZE))" -ne 0 ]; then 177 echo "$(((L_SIZE / LABEL_SIZE) * LABEL_SIZE))" 178 else 179 echo "$L_SIZE" 180 fi 181} 182 183function corrupt_sized_label_checksum 184{ 185 L_SIZE="$1" 186 L_LABEL="$2" 187 L_DEVICE="$3" 188 189 L_PRACTICAL_SIZE="$(get_practical_size "$L_SIZE")" 190 191 typeset -a L_OFFSETS=("$LABEL_CKSUM_START" \ 192 "$((LABEL_SIZE + LABEL_CKSUM_START))" \ 193 "$(((L_PRACTICAL_SIZE - LABEL_SIZE*2) + LABEL_CKSUM_START))" \ 194 "$(((L_PRACTICAL_SIZE - LABEL_SIZE) + LABEL_CKSUM_START))") 195 196 dd if=/dev/urandom of="$L_DEVICE" \ 197 seek="${L_OFFSETS["$L_LABEL"]}" bs=1 count="$LABEL_CKSUM_SIZE" \ 198 conv=notrunc 199} 200 201function corrupt_labels 202{ 203 L_SIZE="$1" 204 L_DISK="$2" 205 206 corrupt_sized_label_checksum "$L_SIZE" 0 "$L_DISK" 207 corrupt_sized_label_checksum "$L_SIZE" 1 "$L_DISK" 208 corrupt_sized_label_checksum "$L_SIZE" 2 "$L_DISK" 209 corrupt_sized_label_checksum "$L_SIZE" 3 "$L_DISK" 210} 211 212function try_import_and_repair 213{ 214 L_REPAIR_SHOULD_SUCCEED="$1" 215 L_IMPORT_SHOULD_SUCCEED="$2" 216 L_OP="$3" 217 L_POOLDISK="$4" 218 L_REPAIR_LOGOP="$(pick_logop "$L_REPAIR_SHOULD_SUCCEED")" 219 L_IMPORT_LOGOP="$(pick_logop "$L_IMPORT_SHOULD_SUCCEED")" 220 221 log_mustnot zpool import "$TESTPOOL" -d "$L_POOLDISK" 222 223 "$L_REPAIR_LOGOP" zhack label repair "$L_OP" "$L_POOLDISK" 224 225 "$L_IMPORT_LOGOP" zpool import "$TESTPOOL" -d "$L_POOLDISK" 226 227 check_dataset "$L_IMPORT_SHOULD_SUCCEED" 228} 229 230function prepare_vdev 231{ 232 L_SIZE="$1" 233 L_BACKFILE="$2" 234 235 l_devname= 236 if truncate -s "$L_SIZE" "$L_BACKFILE"; then 237 if is_linux; then 238 l_devname="$(losetup -f "$L_BACKFILE" --show)" 239 elif is_freebsd; then 240 l_devname=/dev/"$(mdconfig -a -t vnode -f "$L_BACKFILE")" 241 else 242 l_devname="$(lofiadm -a "$L_BACKFILE")" 243 fi 244 fi 245 echo "$l_devname" 246} 247 248function run_test_one 249{ 250 L_SIZE="$1" 251 252 VIRTUAL_DEVICE="$(prepare_vdev "$L_SIZE" "$VIRTUAL_DISK")" 253 log_must test -e "$VIRTUAL_DEVICE" 254 255 log_must zpool create "$TESTPOOL" "$VIRTUAL_DEVICE" 256 257 setup_dataset 258 259 log_must zpool export "$TESTPOOL" 260 261 corrupt_labels "$L_SIZE" "$VIRTUAL_DISK" 262 263 try_import_and_repair false false "-u" "$VIRTUAL_DEVICE" 264 265 try_import_and_repair true true "-c" "$VIRTUAL_DEVICE" 266 267 cleanup 268 269 log_pass "zhack label repair corruption test passed with a randomized size of $L_SIZE" 270} 271 272function make_mirrored_pool 273{ 274 L_SIZE="$1" 275 276 VIRTUAL_DEVICE="$(prepare_vdev "$L_SIZE" "$VIRTUAL_DISK")" 277 log_must test -e "$VIRTUAL_DEVICE" 278 VIRTUAL_MIRROR_DEVICE="$(prepare_vdev "$L_SIZE" "$VIRTUAL_MIRROR_DISK")" 279 log_must test -e "$VIRTUAL_MIRROR_DEVICE" 280 281 log_must zpool create "$TESTPOOL" "$VIRTUAL_DEVICE" 282 log_must zpool attach "$TESTPOOL" "$VIRTUAL_DEVICE" "$VIRTUAL_MIRROR_DEVICE" 283} 284 285function export_and_cleanup_vdisk 286{ 287 log_must zpool export "$TESTPOOL" 288 289 cleanup_lo "$VIRTUAL_DEVICE" 290 291 VIRTUAL_DEVICE= 292 293 log_must rm "$VIRTUAL_DISK" 294} 295 296function run_test_two 297{ 298 L_SIZE="$1" 299 300 make_mirrored_pool "$L_SIZE" 301 302 setup_dataset 303 304 log_must zpool detach "$TESTPOOL" "$VIRTUAL_MIRROR_DEVICE" 305 306 export_and_cleanup_vdisk 307 308 try_import_and_repair false false "-c" "$VIRTUAL_MIRROR_DEVICE" 309 310 try_import_and_repair true true "-u" "$VIRTUAL_MIRROR_DEVICE" 311 312 cleanup 313 314 log_pass "zhack label repair detached test passed with a randomized size of $L_SIZE" 315} 316 317function run_test_three 318{ 319 L_SIZE="$1" 320 321 make_mirrored_pool "$L_SIZE" 322 323 setup_dataset 324 325 log_must zpool detach "$TESTPOOL" "$VIRTUAL_MIRROR_DEVICE" 326 327 export_and_cleanup_vdisk 328 329 corrupt_labels "$L_SIZE" "$VIRTUAL_MIRROR_DISK" 330 331 try_import_and_repair false false "-u" "$VIRTUAL_MIRROR_DEVICE" 332 333 try_import_and_repair true false "-c" "$VIRTUAL_MIRROR_DEVICE" 334 335 try_import_and_repair true true "-u" "$VIRTUAL_MIRROR_DEVICE" 336 337 cleanup 338 339 log_pass "zhack label repair corruption and detached test passed with a randomized size of $L_SIZE" 340} 341 342function run_test_four 343{ 344 L_SIZE="$1" 345 346 make_mirrored_pool "$L_SIZE" 347 348 setup_dataset 349 350 log_must zpool detach "$TESTPOOL" "$VIRTUAL_MIRROR_DEVICE" 351 352 export_and_cleanup_vdisk 353 354 corrupt_labels "$L_SIZE" "$VIRTUAL_MIRROR_DISK" 355 356 try_import_and_repair true true "-cu" "$VIRTUAL_MIRROR_DEVICE" 357 358 cleanup 359 360 log_pass "zhack label repair corruption and detached single-command test passed with a randomized size of $L_SIZE." 361} 362