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 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
68	[[ $? -ne 0 ]] && return 1
69
70	# Create 100 MB of data
71	typeset file="/$ds/fillerfile"
72	for i in {1..$files10mb}; do
73		dd if=/dev/urandom of=$file.$i bs=128k count=80
74		[[ $? -ne 0 ]] && return 1
75	done
76
77	return 0
78}
79
80#
81# Create/overwrite a few datasets with files.
82# Checksum all the files and store digests in a file.
83#
84# newdata: overwrite existing files if false.
85# md5file: file where to store md5 digests
86# datasetname: base name for datasets
87#
88function _generate_data_common
89{
90	typeset pool=$1
91	typeset newdata=$2
92	typeset md5file=$3
93	typeset datasetname=$4
94
95	typeset -i datasets=3
96	typeset -i files=5
97	typeset -i blocks=10
98
99	[[ -n $md5file ]] && rm -f $md5file
100	for i in {1..$datasets}; do
101		( $newdata ) && log_must zfs create "$pool/$datasetname$i"
102		for j in {1..$files}; do
103			typeset file="/$pool/$datasetname$i/file$j"
104			dd if=/dev/urandom of=$file bs=128k count=$blocks > /dev/null
105			if [[ -n $md5file ]]; then
106				typeset cksum=$(md5digest $file)
107				echo $cksum $file >> $md5file
108			fi
109		done
110		( $newdata ) && sync_pool "$pool"
111	done
112
113	return 0
114}
115
116function generate_data
117{
118	typeset pool=$1
119	typeset md5file="$2"
120	typeset datasetname=${3:-ds}
121
122	_generate_data_common $pool true "$md5file" $datasetname
123}
124
125function overwrite_data
126{
127	typeset pool=$1
128	typeset md5file="$2"
129	typeset datasetname=${3:-ds}
130
131	_generate_data_common $1 false "$md5file" $datasetname
132}
133
134#
135# Verify md5sums of every file in md5sum file $1.
136#
137function verify_data_md5sums
138{
139	typeset md5file=$1
140
141	if [[ ! -f $md5file ]]; then
142		log_note "md5 sums file '$md5file' doesn't exist"
143		return 1
144	fi
145
146	cat $md5file | \
147	while read digest file; do
148		typeset digest1=$(md5digest $file)
149		if [[ "$digest1" != "$digest" ]]; then
150			return 1
151		fi
152	done
153
154	return 0
155}
156
157#
158# Set devices size in DEVICE_DIR to $1.
159#
160function increase_device_sizes
161{
162	typeset newfilesize=$1
163
164	typeset -i i=0
165	while (( i < $MAX_NUM )); do
166		log_must truncate -s $newfilesize ${DEVICE_DIR}/${DEVICE_FILE}$i
167		((i += 1))
168	done
169}
170
171#
172# Translate vdev names returned by zpool status into more generic names.
173#
174function _translate_vdev
175{
176	typeset vdev=$1
177
178	#
179	# eg: mirror-2 --> mirror
180	# eg: draid2:4d:12c:1s-0 --> draid2
181	#
182	typeset keywords="mirror replacing raidz1 raidz2 raidz3 indirect draid1 draid2 draid3"
183	for word in $keywords; do
184		echo $vdev | egrep -qE \
185		    "^${word}-[0-9]+\$|^${word}:[0-9]+d:[0-9]c:[0-9]+s-[0-9]+\$"
186		if [[ $? -eq 0 ]]; then
187			vdev=$word
188			break
189		fi
190	done
191
192	[[ $vdev == "logs" ]] && echo "log" && return 0
193	[[ $vdev == "raidz1" ]] && echo "raidz" && return 0
194	[[ $vdev == "draid1" ]] && echo "draid" && return 0
195
196	echo $vdev
197	return 0
198}
199
200#
201# Check that pool configuration returned by zpool status matches expected
202# configuration. Format for the check string is same as the vdev arguments for
203# creating a pool
204# Add -q for quiet mode.
205#
206# eg: check_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0 log c1t1d0s0"
207#
208function check_pool_config
209{
210	typeset logfailure=true
211	if [[ $1 == '-q' ]]; then
212		logfailure=false
213		shift
214	fi
215
216	typeset poolname=$1
217	typeset expected=$2
218
219	typeset status
220	status=$(zpool status $poolname 2>&1)
221	if [[ $? -ne 0 ]]; then
222		if ( $logfailure ); then
223			log_note "zpool status $poolname failed: $status"
224		fi
225		return 1
226	fi
227
228	typeset actual=""
229	typeset began=false
230	printf "$status\n" | while read line; do
231		typeset vdev=$(echo "$line" | awk '{printf $1}')
232		if ( ! $began ) && [[ $vdev == NAME ]]; then
233			began=true
234			continue
235		fi
236		( $began ) && [[ -z $vdev ]] && break;
237
238		if ( $began ); then
239			[[ -z $actual ]] && actual="$vdev" && continue
240			vdev=$(_translate_vdev $vdev)
241			actual="$actual $vdev"
242		fi
243	done
244
245	expected="$poolname $expected"
246
247	if [[ "$actual" != "$expected" ]]; then
248		if ( $logfailure ); then
249			log_note "expected pool vdevs:"
250			log_note "> '$expected'"
251			log_note "actual pool vdevs:"
252			log_note "> '$actual'"
253		fi
254		return 1
255	fi
256
257	return 0
258}
259
260#
261# Check that pool configuration returned by zpool status matches expected
262# configuration within a given timeout in seconds. See check_pool_config().
263#
264# eg: wait_for_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0" 60
265#
266function wait_for_pool_config
267{
268	typeset poolname=$1
269	typeset expectedconfig="$2"
270	typeset -i timeout=${3:-60}
271
272	timeout=$(( $timeout + $(date +%s) ))
273
274	while  (( $(date +%s) < $timeout )); do
275		check_pool_config -q $poolname "$expectedconfig"
276		[[ $? -eq 0 ]] && return 0
277		sleep 3
278	done
279
280	check_pool_config $poolname "$expectedconfig"
281	return $?
282}
283
284#
285# Check that pool status is ONLINE
286#
287function check_pool_healthy
288{
289	typeset pool=$1
290
291	typeset status
292	status=$(zpool status $pool 2>&1)
293	if [[ $? -ne 0 ]]; then
294		log_note "zpool status $pool failed: $status"
295		return 1
296	fi
297
298	status=$(echo "$status" | grep "$pool" | grep -v "pool:" | \
299	    awk '{print $2}')
300
301	if [[ $status != "ONLINE" ]]; then
302		log_note "Invalid zpool status for '$pool': '$status'" \
303		    "!= 'ONLINE'"
304		return 1
305	fi
306
307	return 0
308}
309
310#
311# Return 0 if a device is currently being replaced in the pool.
312#
313function pool_is_replacing
314{
315	typeset pool=$1
316
317	zpool status $pool | grep "replacing" | grep "ONLINE" > /dev/null
318
319	return $?
320}
321
322function set_vdev_validate_skip
323{
324	set_tunable32 VDEV_VALIDATE_SKIP "$1"
325}
326
327function get_zfs_txg_timeout
328{
329	get_tunable TXG_TIMEOUT
330}
331
332function set_zfs_txg_timeout
333{
334	set_tunable32 TXG_TIMEOUT "$1"
335}
336
337function set_spa_load_verify_metadata
338{
339	set_tunable32 SPA_LOAD_VERIFY_METADATA "$1"
340}
341
342function set_spa_load_verify_data
343{
344	set_tunable32 SPA_LOAD_VERIFY_DATA "$1"
345}
346
347function set_zfs_max_missing_tvds
348{
349	set_tunable32 MAX_MISSING_TVDS "$1"
350}
351
352#
353# Use zdb to find the last txg that was synced in an active pool.
354#
355function get_last_txg_synced
356{
357	typeset pool=$1
358
359	zdb -u $pool | awk '$1 == "txg" { print $3 }' | sort -n | tail -n 1
360}
361