1#!/bin/ksh -p 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) 2017 by Delphix. All rights reserved. 16# 17 18. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.kshlib 19 20# 21# DESCRIPTION: 22# It should be possible to rewind a pool beyond a configuration change. 23# 24# STRATEGY: 25# 1. Create a pool. 26# 2. Generate files and remember their hashsum. 27# 3. Note last synced txg. 28# 4. Take a snapshot to make sure old blocks are not overwritten. 29# 5. Perform zpool add/attach/detach/remove operation. 30# 6. Change device paths if requested and re-import pool. 31# 7. Checkpoint the pool as one last attempt to preserve old blocks. 32# 8. Overwrite the files. 33# 9. Export the pool. 34# 10. Verify that we can rewind the pool to the noted txg. 35# 11. Verify that the files are readable and retain their old data. 36# 37# DISCLAIMER: 38# This test can fail since nothing guarantees that old MOS blocks aren't 39# overwritten. Snapshots protect datasets and data files but not the MOS. 40# sync_some_data_a_few_times interleaves file data and MOS data for a few 41# txgs, thus increasing the odds that some txgs will have their MOS data 42# left untouched. 43# 44 45verify_runnable "global" 46 47function custom_cleanup 48{ 49 set_vdev_validate_skip 0 50 cleanup 51 log_must set_tunable64 VDEV_MIN_MS_COUNT 16 52} 53 54log_onexit custom_cleanup 55 56function test_common 57{ 58 typeset poolcreate="$1" 59 typeset addvdevs="$2" 60 typeset attachargs="${3:-}" 61 typeset detachvdev="${4:-}" 62 typeset removevdev="${5:-}" 63 typeset finalpool="${6:-}" 64 typeset retval=1 65 66 typeset poolcheck="$poolcreate" 67 68 log_must zpool create $TESTPOOL1 $poolcreate 69 70 log_must generate_data $TESTPOOL1 $MD5FILE 71 72 # syncing a few times while writing new data increases the odds that MOS 73 # metadata for some of the txgs will survive 74 log_must sync_some_data_a_few_times $TESTPOOL1 75 typeset txg 76 txg=$(get_last_txg_synced $TESTPOOL1) 77 log_must zfs snapshot -r $TESTPOOL1@snap1 78 79 # 80 # Perform config change operations 81 # 82 if [[ -n $addvdevs ]]; then 83 log_must zpool add -f $TESTPOOL1 $addvdevs 84 fi 85 if [[ -n $attachargs ]]; then 86 log_must zpool attach $TESTPOOL1 $attachargs 87 fi 88 if [[ -n $detachvdev ]]; then 89 log_must zpool detach $TESTPOOL1 $detachvdev 90 fi 91 if [[ -n $removevdev ]]; then 92 [[ -z $finalpool ]] && 93 log_fail "Must provide final pool status!" 94 log_must zpool remove $TESTPOOL1 $removevdev 95 log_must wait_for_pool_config $TESTPOOL1 "$finalpool" 96 fi 97 if [[ -n $pathstochange ]]; then 98 # 99 # Change device paths and re-import pool to update labels 100 # 101 zpool export $TESTPOOL1 102 for dev in $pathstochange; do 103 log_must mv $dev "${dev}_new" 104 poolcheck=$(echo "$poolcheck" | \ 105 sed "s:$dev:${dev}_new:g") 106 done 107 zpool import -d $DEVICE_DIR $TESTPOOL1 108 fi 109 110 # 111 # In an attempt to leave MOS data untouched so extreme 112 # rewind is successful during import we checkpoint the 113 # pool and hope that these MOS data are part of the 114 # checkpoint (e.g they stay around). If this goes as 115 # expected, then extreme rewind should rewind back even 116 # further than the time that we took the checkpoint. 117 # 118 # Note that, ideally we would want to take a checkpoint 119 # right after we record the txg we plan to rewind to. 120 # But since we can't attach, detach or remove devices 121 # while having a checkpoint, we take it after the 122 # operation that changes the config. 123 # 124 # However, it is possible the MOS data was overwritten 125 # in which case the pool will either be unimportable, or 126 # may have been rewound prior to the data being written. 127 # In which case an error is returned and test_common() 128 # is retried by the caller to minimize false positives. 129 # 130 log_must zpool checkpoint $TESTPOOL1 131 132 log_must overwrite_data $TESTPOOL1 "" 133 134 log_must zpool export $TESTPOOL1 135 136 if zpool import -d $DEVICE_DIR -T $txg $TESTPOOL1; then 137 verify_data_hashsums $MD5FILE && retval=0 138 139 log_must check_pool_config $TESTPOOL1 "$poolcheck" 140 log_must zpool destroy $TESTPOOL1 141 fi 142 143 # Cleanup 144 if [[ -n $pathstochange ]]; then 145 for dev in $pathstochange; do 146 log_must mv "${dev}_new" $dev 147 done 148 fi 149 # Fast way to clear vdev labels 150 log_must zpool create -f $TESTPOOL2 $VDEV0 $VDEV1 $VDEV2 $VDEV3 $VDEV4 151 log_must zpool destroy $TESTPOOL2 152 153 log_note "" 154 return $retval 155} 156 157function test_add_vdevs 158{ 159 typeset poolcreate="$1" 160 typeset addvdevs="$2" 161 162 log_note "$0: pool '$poolcreate', add $addvdevs." 163 164 for retry in $(seq 1 5); do 165 test_common "$poolcreate" "$addvdevs" && return 166 log_note "Retry $retry / 5 for test_add_vdevs()" 167 done 168 169 log_fail "Exhausted all 5 retries for test_add_vdevs()" 170} 171 172function test_attach_vdev 173{ 174 typeset poolcreate="$1" 175 typeset attachto="$2" 176 typeset attachvdev="$3" 177 178 log_note "$0: pool '$poolcreate', attach $attachvdev to $attachto." 179 180 for retry in $(seq 1 5); do 181 test_common "$poolcreate" "" "$attachto $attachvdev" && return 182 log_note "Retry $retry / 5 for test_attach_vdev()" 183 done 184 185 log_fail "Exhausted all 5 retries for test_attach_vdev()" 186} 187 188function test_detach_vdev 189{ 190 typeset poolcreate="$1" 191 typeset detachvdev="$2" 192 193 log_note "$0: pool '$poolcreate', detach $detachvdev." 194 195 for retry in $(seq 1 5); do 196 test_common "$poolcreate" "" "" "$detachvdev" && return 197 log_note "Retry $retry / 5 for test_detach_vdev()" 198 done 199 200 log_fail "Exhausted all 5 retries for test_detach_vdev()" 201} 202 203function test_attach_detach_vdev 204{ 205 typeset poolcreate="$1" 206 typeset attachto="$2" 207 typeset attachvdev="$3" 208 typeset detachvdev="$4" 209 210 log_note "$0: pool '$poolcreate', attach $attachvdev to $attachto," \ 211 "then detach $detachvdev." 212 213 for retry in $(seq 1 5); do 214 test_common "$poolcreate" "" "$attachto $attachvdev" \ 215 "$detachvdev" && return 216 log_note "Retry $retry / 5 for test_attach_detach_vdev()" 217 done 218 219 log_fail "Exhausted all 5 retries for test_attach_detach_vdev()" 220} 221 222function test_remove_vdev 223{ 224 typeset poolcreate="$1" 225 typeset removevdev="$2" 226 typeset finalpool="$3" 227 228 log_note "$0: pool '$poolcreate', remove $removevdev." 229 230 for retry in $(seq 1 5); do 231 test_common "$poolcreate" "" "" "" "$removevdev" \ 232 "$finalpool" && return 233 log_note "Retry $retry / 5 for test_remove_vdev()" 234 done 235 236 log_fail "Exhausted all 5 retries for test_remove_vdev()" 237} 238 239# Record txg history 240is_linux && log_must set_tunable32 TXG_HISTORY 100 241 242# Make the devices bigger to reduce chances of overwriting MOS metadata. 243increase_device_sizes $(( FILE_SIZE * 4 )) 244 245# Increase the number of metaslabs for small pools temporarily to 246# reduce the chance of reusing a metaslab that holds old MOS metadata. 247log_must set_tunable64 VDEV_MIN_MS_COUNT 150 248 249# Part of the rewind test is to see how it reacts to path changes 250typeset pathstochange="$VDEV0 $VDEV1 $VDEV2 $VDEV3" 251 252log_note " == test rewind after device addition == " 253 254test_add_vdevs "$VDEV0" "$VDEV1" 255test_add_vdevs "$VDEV0 $VDEV1" "$VDEV2" 256test_add_vdevs "$VDEV0" "$VDEV1 $VDEV2" 257test_add_vdevs "mirror $VDEV0 $VDEV1" "mirror $VDEV2 $VDEV3" 258test_add_vdevs "$VDEV0" "raidz $VDEV1 $VDEV2 $VDEV3" 259test_add_vdevs "$VDEV0" "draid $VDEV1 $VDEV2 $VDEV3" 260test_add_vdevs "$VDEV0" "log $VDEV1" 261test_add_vdevs "$VDEV0 log $VDEV1" "$VDEV2" 262 263log_note " == test rewind after device attach == " 264 265test_attach_vdev "$VDEV0" "$VDEV0" "$VDEV1" 266test_attach_vdev "mirror $VDEV0 $VDEV1" "$VDEV0" "$VDEV2" 267test_attach_vdev "$VDEV0 $VDEV1" "$VDEV0" "$VDEV2" 268 269log_note " == test rewind after device removal == " 270 271# Once we remove a device it will be overlooked in the device scan, so we must 272# preserve its original path 273pathstochange="$VDEV0 $VDEV2" 274test_remove_vdev "$VDEV0 $VDEV1 $VDEV2" "$VDEV1" "$VDEV0 $VDEV2" 275 276# 277# Path change and detach are incompatible. Detach changes the guid of the vdev 278# so we have no direct way to link the new path to an existing vdev. 279# 280pathstochange="" 281 282log_note " == test rewind after device detach == " 283 284test_detach_vdev "mirror $VDEV0 $VDEV1" "$VDEV1" 285test_detach_vdev "mirror $VDEV0 $VDEV1 mirror $VDEV2 $VDEV3" "$VDEV1" 286test_detach_vdev "$VDEV0 log mirror $VDEV1 $VDEV2" "$VDEV2" 287 288log_note " == test rewind after device attach followed by device detach == " 289 290# 291# We need to disable vdev validation since once we detach VDEV1, VDEV0 will 292# inherit the mirror tvd's guid and lose its original guid. 293# 294set_vdev_validate_skip 1 295test_attach_detach_vdev "$VDEV0" "$VDEV0" "$VDEV1" "$VDEV1" 296set_vdev_validate_skip 0 297 298log_pass "zpool import rewind after configuration change passed." 299