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