1#
2# This file and its contents are supplied under the terms of the
3# Common Development and Distribution License ("CDDL"), version 1.0.
4# You may only use this file in accordance with the terms of version
5# 1.0 of the CDDL.
6#
7# A full copy of the text of the CDDL should have accompanied this
8# source.  A copy of the CDDL is also available via the Internet at
9# http://www.illumos.org/license/CDDL.
10#
11
12#
13# Copyright (c) 2016 by Delphix. All rights reserved.
14#
15
16. $STF_SUITE/include/libtest.shlib
17. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
18
19#
20# Prototype cleanup function for zpool_import tests.
21#
22function cleanup
23{
24	# clear any remaining zinjections
25	log_must eval "zinject -c all > /dev/null"
26
27	destroy_pool $TESTPOOL1
28
29	log_must rm -f $CPATH $CPATHBKP $CPATHBKP2 $MD5FILE $MD5FILE2
30
31	log_must rm -rf $DEVICE_DIR/*
32	typeset i=0
33	while (( i < $MAX_NUM )); do
34		log_must truncate -s $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
35		((i += 1))
36	done
37	is_linux && set_tunable32 TXG_HISTORY 0
38}
39
40#
41# Write a bit of data and sync several times.
42# This function is intended to be used by zpool rewind tests.
43#
44function sync_some_data_a_few_times
45{
46	typeset pool=$1
47	typeset -i a_few_times=${2:-10}
48
49	typeset file="/$pool/tmpfile"
50	for i in {0..$a_few_times}; do
51		dd if=/dev/urandom of=${file}_$i bs=128k count=10
52		sync_pool "$pool"
53	done
54
55	return 0
56}
57
58#
59# Just write a moderate amount of data to the pool.
60#
61function write_some_data
62{
63	typeset pool=$1
64	typeset files10mb=${2:-10}
65
66	typeset ds="$pool/fillerds"
67	zfs create $ds || return 1
68
69	# Create 100 MB of data
70	typeset file="/$ds/fillerfile"
71	for i in {1..$files10mb}; do
72		dd if=/dev/urandom of=$file.$i bs=128k count=80 || return 1
73	done
74}
75
76#
77# Create/overwrite a few datasets with files.
78# Checksum all the files and store digests in a file.
79#
80# newdata: overwrite existing files if false.
81# md5file: file where to store md5 digests
82# datasetname: base name for datasets
83#
84function _generate_data_common
85{
86	typeset pool=$1
87	typeset newdata=$2
88	typeset md5file=$3
89	typeset datasetname=$4
90
91	typeset -i datasets=3
92	typeset -i files=5
93	typeset -i blocks=10
94
95	[[ -n $md5file ]] && rm -f $md5file
96	for i in {1..$datasets}; do
97		( $newdata ) && log_must zfs create "$pool/$datasetname$i"
98		for j in {1..$files}; do
99			typeset file="/$pool/$datasetname$i/file$j"
100			dd if=/dev/urandom of=$file bs=128k count=$blocks > /dev/null
101			if [[ -n $md5file ]]; then
102				typeset cksum=$(md5digest $file)
103				echo $cksum $file >> $md5file
104			fi
105		done
106		( $newdata ) && sync_pool "$pool"
107	done
108
109	return 0
110}
111
112function generate_data
113{
114	typeset pool=$1
115	typeset md5file="$2"
116	typeset datasetname=${3:-ds}
117
118	_generate_data_common $pool true "$md5file" $datasetname
119}
120
121function overwrite_data
122{
123	typeset pool=$1
124	typeset md5file="$2"
125	typeset datasetname=${3:-ds}
126
127	_generate_data_common $1 false "$md5file" $datasetname
128}
129
130#
131# Verify md5sums of every file in md5sum file $1.
132#
133function verify_data_md5sums
134{
135	typeset md5file=$1
136
137	if [[ ! -f $md5file ]]; then
138		log_note "md5 sums file '$md5file' doesn't exist"
139		return 1
140	fi
141
142	while read -r digest file; do
143		typeset digest1=$(md5digest $file)
144		if [[ "$digest1" != "$digest" ]]; then
145			return 1
146		fi
147	done < $md5file
148
149	return 0
150}
151
152#
153# Set devices size in DEVICE_DIR to $1.
154#
155function increase_device_sizes
156{
157	typeset newfilesize=$1
158
159	typeset -i i=0
160	while (( i < $MAX_NUM )); do
161		log_must truncate -s $newfilesize ${DEVICE_DIR}/${DEVICE_FILE}$i
162		((i += 1))
163	done
164}
165
166#
167# Translate vdev names returned by zpool status into more generic names.
168#
169function _translate_vdev
170{
171	typeset vdev=$1
172
173	#
174	# eg: mirror-2 --> mirror
175	# eg: draid2:4d:12c:1s-0 --> draid2
176	#
177	typeset keywords="mirror replacing raidz1 raidz2 raidz3 indirect draid1 draid2 draid3"
178	for word in $keywords; do
179		if echo $vdev |
180		    grep -qE  "^${word}-[0-9]+\$|^${word}:[0-9]+d:[0-9]c:[0-9]+s-[0-9]+\$"
181		then
182			vdev=$word
183			break
184		fi
185	done
186
187	case "$vdev" in
188		logs) echo "log" ;;
189		raidz1) echo "raidz" ;;
190		draid1) echo "draid" ;;
191		*) echo $vdev ;;
192	esac
193}
194
195#
196# Check that pool configuration returned by zpool status matches expected
197# configuration. Format for the check string is same as the vdev arguments for
198# creating a pool
199# Add -q for quiet mode.
200#
201# eg: check_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0 log c1t1d0s0"
202#
203function check_pool_config
204{
205	typeset logfailure=true
206	if [[ $1 == '-q' ]]; then
207		logfailure=false
208		shift
209	fi
210
211	typeset poolname=$1
212	typeset expected=$2
213
214	typeset status
215	if ! status=$(zpool status $poolname 2>&1); then
216		if $logfailure; then
217			log_note "zpool status $poolname failed: $status"
218		fi
219		return 1
220	fi
221
222	typeset actual=""
223	typeset began=false
224	while read -r vdev _; do
225		if ( ! $began ) && [[ $vdev == NAME ]]; then
226			began=true
227			continue
228		fi
229		( $began ) && [[ -z $vdev ]] && break;
230
231		if ( $began ); then
232			[[ -z $actual ]] && actual="$vdev" && continue
233			vdev=$(_translate_vdev $vdev)
234			actual="$actual $vdev"
235		fi
236	done <<<"$status"
237
238	expected="$poolname $expected"
239
240	if [[ "$actual" != "$expected" ]]; then
241		if $logfailure; then
242			log_note "expected pool vdevs:"
243			log_note "> '$expected'"
244			log_note "actual pool vdevs:"
245			log_note "> '$actual'"
246		fi
247		return 1
248	fi
249
250	return 0
251}
252
253#
254# Check that pool configuration returned by zpool status matches expected
255# configuration within a given timeout in seconds. See check_pool_config().
256#
257# eg: wait_for_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0" 60
258#
259function wait_for_pool_config
260{
261	typeset poolname=$1
262	typeset expectedconfig="$2"
263	typeset -i timeout=${3:-60}
264
265	timeout=$(( $timeout + $(date +%s) ))
266
267	while  (( $(date +%s) < $timeout )); do
268		check_pool_config -q $poolname "$expectedconfig" && return 0
269		sleep 3
270	done
271
272	check_pool_config $poolname "$expectedconfig"
273}
274
275#
276# Check that pool status is ONLINE
277#
278function check_pool_healthy
279{
280	typeset pool=$1
281	typeset status
282
283	if ! status=$(zpool status $pool 2>&1); then
284		log_note "zpool status $pool failed: $status"
285		return 1
286	fi
287
288	status=$(echo "$status" | awk -v p="$pool" '!/pool:/ && $0 ~ p {print $2}')
289
290	if [[ $status != "ONLINE" ]]; then
291		log_note "Invalid zpool status for '$pool': '$status'" \
292		    "!= 'ONLINE'"
293		return 1
294	fi
295
296	return 0
297}
298
299#
300# Return 0 if a device is currently being replaced in the pool.
301#
302function pool_is_replacing
303{
304	typeset pool=$1
305
306	zpool status $pool | grep "replacing" | grep -q "ONLINE"
307}
308
309function set_vdev_validate_skip
310{
311	set_tunable32 VDEV_VALIDATE_SKIP "$1"
312}
313
314function get_zfs_txg_timeout
315{
316	get_tunable TXG_TIMEOUT
317}
318
319function set_zfs_txg_timeout
320{
321	set_tunable32 TXG_TIMEOUT "$1"
322}
323
324function set_spa_load_verify_metadata
325{
326	set_tunable32 SPA_LOAD_VERIFY_METADATA "$1"
327}
328
329function set_spa_load_verify_data
330{
331	set_tunable32 SPA_LOAD_VERIFY_DATA "$1"
332}
333
334function set_zfs_max_missing_tvds
335{
336	set_tunable32 MAX_MISSING_TVDS "$1"
337}
338
339#
340# Use zdb to find the last txg that was synced in an active pool.
341#
342function get_last_txg_synced
343{
344	typeset pool=$1
345
346	zdb -u $pool | awk '$1 == "txg" { print $3 }' | sort -n | tail -n 1
347}
348