1#!/usr/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) 2016 by Delphix. All rights reserved.
16#
17
18. $STF_SUITE/include/libtest.shlib
19. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
20
21#
22# Prototype cleanup function for zpool_import tests.
23#
24function cleanup
25{
26	destroy_pool $TESTPOOL1
27
28	log_must rm -f $CPATH $CPATHBKP $CPATHBKP2 $MD5FILE $MD5FILE2
29
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
36}
37
38#
39# Write a bit of data and sync several times.
40# This function is intended to be used by zpool rewind tests.
41#
42function sync_some_data_a_few_times
43{
44	typeset pool=$1
45	typeset -i a_few_times=${2:-10}
46
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
52
53	return 0
54}
55
56#
57# Just write a moderate amount of data to the pool.
58#
59function write_some_data
60{
61	typeset pool=$1
62	typeset files10mb=${2:-10}
63
64	typeset ds="$pool/fillerds"
65	zfs create $ds
66	[[ $? -ne 0 ]] && return 1
67
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
74
75	return 0
76}
77
78#
79# Create/overwrite a few datasets with files.
80# Apply md5sum on all the files and store checksums in a file.
81#
82# newdata: overwrite existing files if false.
83# md5file: file where to store md5sums
84# datasetname: base name for datasets
85#
86function _generate_data_common
87{
88	typeset pool=$1
89	typeset newdata=$2
90	typeset md5file=$3
91	typeset datasetname=$4
92
93	typeset -i datasets=3
94	typeset -i files=5
95	typeset -i blocks=10
96
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
107
108	return 0
109}
110
111function generate_data
112{
113	typeset pool=$1
114	typeset md5file="$2"
115	typeset datasetname=${3:-ds}
116
117	_generate_data_common $pool true "$md5file" $datasetname
118}
119
120function overwrite_data
121{
122	typeset pool=$1
123	typeset md5file="$2"
124	typeset datasetname=${3:-ds}
125
126	_generate_data_common $1 false "$md5file" $datasetname
127}
128
129#
130# Verify md5sums of every file in md5sum file $1.
131#
132function verify_data_md5sums
133{
134	typeset md5file=$1
135
136	if [[ ! -f $md5file ]]; then
137		log_note "md5 sums file '$md5file' doesn't exist"
138		return 1
139	fi
140
141	md5sum -c --quiet $md5file
142	return $?
143}
144
145#
146# Set devices size in DEVICE_DIR to $1.
147#
148function increase_device_sizes
149{
150	typeset newfilesize=$1
151
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
157}
158
159#
160# Translate vdev names returned by zpool status into more generic names.
161#
162# eg: mirror-2 --> mirror
163#
164function _translate_vdev
165{
166	typeset vdev=$1
167
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
174		fi
175	done
176
177	[[ $vdev == "logs" ]] && echo "log" && return 0
178	[[ $vdev == "raidz1" ]] && echo "raidz" && return 0
179
180	echo $vdev
181	return 0
182}
183
184#
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.
189#
190# eg: check_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0 log c1t1d0s0"
191#
192function check_pool_config
193{
194	typeset logfailure=true
195	if [[ $1 == '-q' ]]; then
196		logfailure=false
197		shift
198	fi
199
200	typeset poolname=$1
201	typeset expected=$2
202
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"
208		fi
209		return 1
210	fi
211
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
219		fi
220		( $began ) && [[ -z $vdev ]] && break;
221
222		if ( $began ); then
223			[[ -z $actual ]] && actual="$vdev" && continue
224			vdev=$(_translate_vdev $vdev)
225			actual="$actual $vdev"
226		fi
227	done
228
229	expected="$poolname $expected"
230
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'"
237		fi
238		return 1
239	fi
240
241	return 0
242}
243
244#
245# Check that pool configuration returned by zpool status matches expected
246# configuration within a given timeout in seconds. See check_pool_config().
247#
248# eg: wait_for_pool_config pool1 "mirror c0t0d0s0 c0t1d0s0" 60
249#
250function wait_for_pool_config
251{
252	typeset poolname=$1
253	typeset expectedconfig="$2"
254	typeset -i timeout=${3:-60}
255
256	timeout=$(( $timeout + $(date +%s) ))
257
258	while  (( $(date +%s) < $timeout )); do
259		check_pool_config -q $poolname "$expectedconfig"
260		[[ $? -eq 0 ]] && return 0
261		sleep 3
262	done
263
264	check_pool_config $poolname "$expectedconfig"
265	return $?
266}
267
268#
269# Check that pool status is ONLINE
270#
271function check_pool_healthy
272{
273	typeset pool=$1
274
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
280	fi
281
282	status=$(echo "$status" | grep "$pool" | grep -v "pool:" | \
283	    awk '{print $2}')
284
285	if [[ $status != "ONLINE" ]]; then
286		log_note "Invalid zpool status for '$pool': '$status'" \
287		    "!= 'ONLINE'"
288		return 1
289	fi
290
291	return 0
292}
293
294#
295# Return 0 if a device is currently being replaced in the pool.
296#
297function pool_is_replacing
298{
299	typeset pool=$1
300
301	zpool status $pool | grep "replacing" | grep "ONLINE" > /dev/null
302
303	return $?
304}
305
306function set_vdev_validate_skip
307{
308	mdb_set_uint32 "vdev_validate_skip" "$1"
309}
310
311function get_zfs_txg_timeout
312{
313	echo $(mdb_get_uint32 "zfs_txg_timeout")
314}
315
316function set_zfs_txg_timeout
317{
318	mdb_set_uint32 "zfs_txg_timeout" "$1"
319}
320
321function set_spa_load_verify_metadata
322{
323	mdb_set_uint32 "spa_load_verify_metadata" "$1"
324}
325
326function set_spa_load_verify_data
327{
328	mdb_set_uint32 "spa_load_verify_data" "$1"
329}
330
331function set_zfs_max_missing_tvds
332{
333	mdb_set_uint32 "zfs_max_missing_tvds" "$1"
334}
335
336#
337# Use mdb to find the last txg that was synced in an active pool.
338#
339function get_last_txg_synced
340{
341	typeset pool=$1
342
343	typeset spas
344	spas=$(mdb -k -e "::spa")
345	[[ $? -ne 0 ]] && return 1
346
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
354		fi
355	done
356	if [[ -z $spa ]]; then
357		log_fail "Couldn't find pool '$pool'"
358		return 1
359	fi
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
364
365	echo $txg
366	return 0
367}
368