1# vim: filetype=sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26
27. ${STF_SUITE}/include/libtest.kshlib
28
29function cleanup
30{
31	# Log the status of the pool to assist failures.
32	poolexists $TESTPOOL && $ZPOOL status -v $TESTPOOL
33	destroy_pool $TESTPOOL
34	typeset dir
35	for dir in $TESTDIR $BASEDIR; do
36		if [[ -d $dir ]]; then 
37			log_must $RM -rf $dir
38		fi
39	done
40}
41
42#
43# Record the directories construction and checksum all the files which reside 
44# within the specified pool
45#
46# $1 The specified pool
47# $2 The file which save the record.
48#
49function record_data
50{
51	typeset pool=$1
52	typeset recordfile=$2
53
54	[[ -z $pool ]] && log_fail "No specified pool."
55	[[ -f $recordfile ]] && log_must $RM -f $recordfile
56
57	typeset mntpnt
58	mntpnt=$(get_prop mountpoint $pool)
59	log_must eval "$DU -a $mntpnt > $recordfile 2>&1"
60	#
61	# When the data was damaged, checksum is failing and return 1
62	# So, will not use log_must
63	#
64	$FIND $mntpnt -type f -exec $CKSUM {} + >> $recordfile 2>&1
65}
66
67#
68# Create test pool and fill with files and directories.
69#
70# $1 pool name
71# $2 pool type
72# $3 virtual devices number
73#
74function setup_test_env
75{
76	typeset pool=$1
77	typeset keyword=$2
78	typeset -i vdev_cnt=$3
79	typeset vdevs 
80
81	typeset -i i=0
82	while (( i < vdev_cnt )); do
83		vdevs="$vdevs $BASEDIR/vdev$i"
84		((i += 1))
85	done
86
87	log_must $MKDIR -p $BASEDIR
88	destroy_pool $pool
89	log_must create_vdevs $vdevs
90
91	$ECHO $vdevs | tr ' ' '\n' > $BASEDIR/vdevs
92	log_must $ZPOOL create -m $TESTDIR $pool $keyword $vdevs
93
94	typeset file=$TESTDIR/file
95	log_must $FILE_WRITE -o create -f $file -b $BLOCKSZ -c $NUM_WRITES
96	force_sync_path $BASEDIR
97	record_data $TESTPOOL $PRE_RECORD_FILE
98}
99
100#
101# Check pool data is valid
102#
103# $1 pool
104#
105function is_data_valid
106{
107	typeset pool=$1
108
109	record_data $pool $PST_RECORD_FILE
110	if ! $DIFF $PRE_RECORD_FILE $PST_RECORD_FILE > /dev/null 2>&1; then 
111		return 1
112	fi
113
114	return 0
115}
116
117#
118# Get the specified count devices name
119#
120# $1 pool name
121# $2 devices count
122#
123function get_vdevs #pool cnt
124{
125	typeset pool=$1
126	typeset -i cnt=$2
127
128	head -$cnt $BASEDIR/vdevs | tr '\n' ' '
129}
130
131#
132# Synchronize all the data in pool 
133#
134# $1 pool name
135#
136function sync_pool #pool
137{
138	typeset pool=$1
139
140	force_sync_path $BASEDIR
141
142	# If the OS has detected corruption on the pool, it will have
143	# automatically initiated a scrub.  In that case, our "zpool scrub"
144	# command will fail.  So we ignore its exit status and just check that
145	# the pool is scrubbing or has been scrubbed.
146	$ZPOOL scrub $pool >/dev/null 2>&1
147	is_pool_scrubbing $pool || is_pool_scrubbed $pool || \
148		log_fail "$ZPOOL scrub $pool failed." 
149	log_note "$pool: $ZPOOL scrub issued."
150}
151
152#
153# Create and replace the same name virtual device files 
154#
155# $1 pool name
156# $2-n virtual device files
157#
158function replace_missing_devs
159{
160	typeset pool=$1
161	shift
162
163	typeset vdev
164	for vdev in $@; do
165		[ ! -f $vdev ] && log_must create_vdevs $vdev
166		log_must $ZPOOL replace -f $pool $vdev $vdev
167		wait_for 20 1 is_pool_resilvered $pool
168	done
169}
170
171#
172# Damage the labels of the specified devices.  Returns 0 if all such devices
173# are UNAVAIL, 1 otherwise.
174#
175function damage_dev_labels # pool <vdev> [vdev ...]
176{
177	typeset pool=$1
178	typeset -i ret=0
179	shift
180
181	for vdev in $*; do
182		check_state $pool $vdev UNAVAIL && continue
183		log_must create_vdevs $vdev
184		ret=1
185	done
186	[ $ret -eq 0 ] && return $ret
187	sync_pool $pool
188	return $ret
189}
190
191#
192# Damage the pool's virtual device files.
193#
194# $1 pool name
195# $2 Failing devices count
196# $3 damage vdevs method, if not null, we keep the label for the vdevs
197#
198function damage_devs
199{
200	typeset pool=$1
201	typeset -i cnt=$2
202	typeset label="$3"
203	typeset vdevs
204	typeset -i bs_count
205
206	vdevs=$(get_vdevs $pool $cnt)
207	log_note "Damaging pool $pool devices: $vdevs"
208	if [[ -n $label ]]; then
209		typeset -i i=0
210		log_mustnot pool_has_errors $pool
211		while [ $i -lt $cnt ]; do
212			corrupt_file $TESTPOOL $TESTDIR/file $i
213			(( i += 1 ))
214		done
215		sync_pool $pool
216		wait_for 20 1 is_pool_scrubbed $pool
217
218		log_must pool_has_errors $pool
219	else
220		# The pool can be syncing, thus fixing its labels.  So we
221		# have to keep trying until all the devices go offline.
222		wait_for 20 1 damage_dev_labels $pool $vdevs
223	fi
224
225	log_note "Pool $pool vdevs $vdevs damage completed."
226}
227
228#
229# Clear errors in the pool caused by data corruptions 
230#
231# $1 pool name
232#
233function clear_errors
234{
235	typeset pool=$1
236
237	log_must $ZPOOL clear $pool
238	# The pool may need to resilver (issued async by 'zpool clear'),
239	# give it a chance to do so.
240	wait_for 30 1 is_pool_healthy $pool 
241
242	if ! is_data_valid $pool ; then
243		$ZPOOL status -x $pool
244		log_note "Data should be valid in $pool."
245		return 1
246	fi
247
248	return 0
249}
250
251#
252# Remove the specified pool's virtual device files
253#
254# $1 Pool name
255# $2 Missing devices count
256#
257function remove_devs
258{
259	typeset pool=$1
260	typeset -i cnt=$2
261	typeset vdevs
262
263	vdevs=$(get_vdevs $pool $cnt)
264	log_note "Removing pool $pool vdevs: $vdevs"
265	log_must $RM -f $vdevs
266
267	sync_pool $pool
268	for vdev in $vdevs; do
269		wait_for 20 1 check_state $pool $vdev UNAVAIL
270	done
271}
272
273#
274# Recover the bad or missing device files in the pool
275#
276# $1 Pool name
277# $2 Missing devices count
278#
279function recover_bad_missing_devs
280{
281	typeset pool=$1 
282	typeset -i cnt=$2
283	typeset vdevs
284
285	vdevs=$(get_vdevs $pool $cnt)
286	log_note "Replacing missing pool $pool vdevs: $vdevs"
287	replace_missing_devs $pool $vdevs
288
289	if ! is_pool_healthy $pool ; then
290		log_note "$pool should be healthy."
291		return 1
292	fi
293	if ! is_data_valid $pool ; then
294		log_note "Data should be valid in $pool."
295		return 1
296	fi
297
298	return 0
299}
300