9075 Improve ZFS pool import/load process and corrupted pool recovery
[unleashed.git] / usr / src / test / zfs-tests / tests / functional / cli_root / zpool_import / zpool_import.kshlib
blob04ce5f858d3ba0e488ef116f1f3a1f179065d6b0
1 #!/usr/bin/ksh
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.
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.
15 # Copyright (c) 2016 by Delphix. All rights reserved.
18 . $STF_SUITE/include/libtest.shlib
19 . $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
22 # Prototype cleanup function for zpool_import tests.
24 function cleanup
26 destroy_pool $TESTPOOL1
28 log_must rm -f $CPATH $CPATHBKP $CPATHBKP2 $MD5FILE $MD5FILE2
30 log_must rm -rf $DEVICE_DIR/*
31 typeset i=0
32 while (( i < $MAX_NUM )); do
33 log_must mkfile $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
34 ((i += 1))
35 done
39 # Write a bit of data and sync several times.
40 # This function is intended to be used by zpool rewind tests.
42 function sync_some_data_a_few_times
44 typeset pool=$1
45 typeset -i a_few_times=${2:-10}
47 typeset file="/$pool/tmpfile"
48 for i in {0..$a_few_times}; do
49 dd if=/dev/urandom of=${file}_$i bs=128k count=10
50 sync
51 done
53 return 0
57 # Just write a moderate amount of data to the pool.
59 function write_some_data
61 typeset pool=$1
62 typeset files10mb=${2:-10}
64 typeset ds="$pool/fillerds"
65 zfs create $ds
66 [[ $? -ne 0 ]] && return 1
68 # Create 100 MB of data
69 typeset file="/$ds/fillerfile"
70 for i in {1..$files10mb}; do
71 dd if=/dev/urandom of=$file.$i bs=128k count=80
72 [[ $? -ne 0 ]] && return 1
73 done
75 return 0
79 # Create/overwrite a few datasets with files.
80 # Apply md5sum on all the files and store checksums in a file.
82 # newdata: overwrite existing files if false.
83 # md5file: file where to store md5sums
84 # datasetname: base name for datasets
86 function _generate_data_common
88 typeset pool=$1
89 typeset newdata=$2
90 typeset md5file=$3
91 typeset datasetname=$4
93 typeset -i datasets=3
94 typeset -i files=5
95 typeset -i blocks=10
97 [[ -n $md5file ]] && rm -f $md5file
98 for i in {1..$datasets}; do
99 ( $newdata ) && log_must zfs create "$pool/$datasetname$i"
100 for j in {1..$files}; do
101 typeset file="/$pool/$datasetname$i/file$j"
102 dd if=/dev/urandom of=$file bs=128k count=$blocks > /dev/null
103 [[ -n $md5file ]] && md5sum $file >> $md5file
104 done
105 ( $newdata ) && sync
106 done
108 return 0
111 function generate_data
113 typeset pool=$1
114 typeset md5file="$2"
115 typeset datasetname=${3:-ds}
117 _generate_data_common $pool true "$md5file" $datasetname
120 function overwrite_data
122 typeset pool=$1
123 typeset md5file="$2"
124 typeset datasetname=${3:-ds}
126 _generate_data_common $1 false "$md5file" $datasetname
130 # Verify md5sums of every file in md5sum file $1.
132 function verify_data_md5sums
134 typeset md5file=$1
136 if [[ ! -f $md5file ]]; then
137 log_note "md5 sums file '$md5file' doesn't exist"
138 return 1
141 md5sum -c --quiet $md5file
142 return $?
146 # Set devices size in DEVICE_DIR to $1.
148 function increase_device_sizes
150 typeset newfilesize=$1
152 typeset -i i=0
153 while (( i < $MAX_NUM )); do
154 log_must mkfile $newfilesize ${DEVICE_DIR}/${DEVICE_FILE}$i
155 ((i += 1))
156 done
160 # Translate vdev names returned by zpool status into more generic names.
162 # eg: mirror-2 --> mirror
164 function _translate_vdev
166 typeset vdev=$1
168 typeset keywords="mirror replacing raidz1 raidz2 raidz3 indirect"
169 for word in $keywords; do
170 echo $vdev | egrep "^${word}-[0-9]+\$" > /dev/null
171 if [[ $? -eq 0 ]]; then
172 vdev=$word
173 break
175 done
177 [[ $vdev == "logs" ]] && echo "log" && return 0
178 [[ $vdev == "raidz1" ]] && echo "raidz" && return 0
180 echo $vdev
181 return 0
185 # Check that pool configuration returned by zpool status matches expected
186 # configuration. Format for the check string is same as the vdev arguments for
187 # creating a pool
188 # Add -q for quiet mode.
190 # eg: check_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0 log c1t1d0s0"
192 function check_pool_config
194 typeset logfailure=true
195 if [[ $1 == '-q' ]]; then
196 logfailure=false
197 shift
200 typeset poolname=$1
201 typeset expected=$2
203 typeset status
204 status=$(zpool status $poolname 2>&1)
205 if [[ $? -ne 0 ]]; then
206 if ( $logfailure ); then
207 log_note "zpool status $poolname failed: $status"
209 return 1
212 typeset actual=""
213 typeset began=false
214 printf "$status\n" | while read line; do
215 typeset vdev=$(echo "$line" | awk '{printf $1}')
216 if ( ! $began ) && [[ $vdev == NAME ]]; then
217 began=true
218 continue
220 ( $began ) && [[ -z $vdev ]] && break;
222 if ( $began ); then
223 [[ -z $actual ]] && actual="$vdev" && continue
224 vdev=$(_translate_vdev $vdev)
225 actual="$actual $vdev"
227 done
229 expected="$poolname $expected"
231 if [[ "$actual" != "$expected" ]]; then
232 if ( $logfailure ); then
233 log_note "expected pool vdevs:"
234 log_note "> '$expected'"
235 log_note "actual pool vdevs:"
236 log_note "> '$actual'"
238 return 1
241 return 0
245 # Check that pool configuration returned by zpool status matches expected
246 # configuration within a given timeout in seconds. See check_pool_config().
248 # eg: wait_for_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0" 60
250 function wait_for_pool_config
252 typeset poolname=$1
253 typeset expectedconfig="$2"
254 typeset -i timeout=${3:-60}
256 timeout=$(( $timeout + $(date +%s) ))
258 while (( $(date +%s) < $timeout )); do
259 check_pool_config -q $poolname "$expectedconfig"
260 [[ $? -eq 0 ]] && return 0
261 sleep 3
262 done
264 check_pool_config $poolname "$expectedconfig"
265 return $?
269 # Check that pool status is ONLINE
271 function check_pool_healthy
273 typeset pool=$1
275 typeset status
276 status=$(zpool status $pool 2>&1)
277 if [[ $? -ne 0 ]]; then
278 log_note "zpool status $pool failed: $status"
279 return 1
282 status=$(echo "$status" | grep "$pool" | grep -v "pool:" | \
283 awk '{print $2}')
285 if [[ $status != "ONLINE" ]]; then
286 log_note "Invalid zpool status for '$pool': '$status'" \
287 "!= 'ONLINE'"
288 return 1
291 return 0
295 # Return 0 if a device is currently being replaced in the pool.
297 function pool_is_replacing
299 typeset pool=$1
301 zpool status $pool | grep "replacing" | grep "ONLINE" > /dev/null
303 return $?
306 function set_vdev_validate_skip
308 mdb_set_uint32 "vdev_validate_skip" "$1"
311 function get_zfs_txg_timeout
313 echo $(mdb_get_uint32 "zfs_txg_timeout")
316 function set_zfs_txg_timeout
318 mdb_set_uint32 "zfs_txg_timeout" "$1"
321 function set_spa_load_verify_metadata
323 mdb_set_uint32 "spa_load_verify_metadata" "$1"
326 function set_spa_load_verify_data
328 mdb_set_uint32 "spa_load_verify_data" "$1"
331 function set_zfs_max_missing_tvds
333 mdb_set_uint32 "zfs_max_missing_tvds" "$1"
337 # Use mdb to find the last txg that was synced in an active pool.
339 function get_last_txg_synced
341 typeset pool=$1
343 typeset spas
344 spas=$(mdb -k -e "::spa")
345 [[ $? -ne 0 ]] && return 1
347 typeset spa=""
348 print "$spas\n" | while read line; do
349 typeset poolname=$(echo "$line" | awk '{print $3}')
350 typeset addr=$(echo "$line" | awk '{print $1}')
351 if [[ $poolname == $pool ]]; then
352 spa=$addr
353 break
355 done
356 if [[ -z $spa ]]; then
357 log_fail "Couldn't find pool '$pool'"
358 return 1
360 typeset mdbcmd="$spa::print spa_t spa_ubsync.ub_txg | ::eval '.=E'"
361 typeset -i txg
362 txg=$(mdb -k -e "$mdbcmd")
363 [[ $? -ne 0 ]] && return 1
365 echo $txg
366 return 0