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