1#!/bin/ksh -p
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 2007 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
30#
31
32. $STF_SUITE/include/libtest.shlib
33. $STF_SUITE/tests/functional/cli_root/zpool_clear/zpool_clear.cfg
34
35#
36# DESCRIPTION:
37# Verify 'zpool clear' can clear pool errors.
38#
39# STRATEGY:
40# 1. Create various configuration pools
41# 2. Make errors to pool
42# 3. Use zpool clear to clear errors
43# 4. Verify the errors has been cleared.
44#
45
46verify_runnable "global"
47
48function cleanup
49{
50        poolexists $TESTPOOL1 && \
51                log_must zpool destroy -f $TESTPOOL1
52
53        for file in `ls $TESTDIR/file.*`; do
54		log_must rm -f $file
55        done
56}
57
58
59log_assert "Verify 'zpool clear' can clear errors of a storage pool."
60log_onexit cleanup
61
62#make raw files to create various configuration pools
63typeset -i i=0
64while (( i < 3 )); do
65	log_must mkfile $FILESIZE $TESTDIR/file.$i
66
67	(( i = i + 1 ))
68done
69
70fbase=$TESTDIR/file
71set -A poolconf "mirror $fbase.0 $fbase.1 $fbase.2" \
72                "raidz1 $fbase.0 $fbase.1 $fbase.2" \
73                "raidz2 $fbase.0 $fbase.1 $fbase.2"
74
75function check_err # <pool> [<vdev>]
76{
77	typeset pool=$1
78	shift
79	if (( $# > 0 )); then
80		typeset	checkvdev=$1
81	else
82		typeset checkvdev=""
83	fi
84	typeset -i errnum=0
85	typeset c_read=0
86	typeset c_write=0
87	typeset c_cksum=0
88	typeset tmpfile=/var/tmp/file.$$
89	typeset healthstr="pool '$pool' is healthy"
90	typeset output="`zpool status -x $pool`"
91
92	[[ "$output" ==  "$healthstr" ]] && return $errnum
93
94	zpool status -x $pool | grep -v "^$" | grep -v "pool:" \
95			| grep -v "state:" | grep -v "config:" \
96			| grep -v "errors:" > $tmpfile
97	typeset line
98	typeset -i fetchbegin=1
99	while read line; do
100		if (( $fetchbegin != 0 )); then
101                        echo $line | grep "NAME" >/dev/null 2>&1
102                        (( $? == 0 )) && (( fetchbegin = 0 ))
103                         continue
104                fi
105
106		if [[ -n $checkvdev ]]; then
107			echo $line | grep $checkvdev >/dev/null 2>&1
108			(( $? != 0 )) && continue
109			c_read=`echo $line | awk '{print $3}'`
110			c_write=`echo $line | awk '{print $4}'`
111			c_cksum=`echo $line | awk '{print $5}'`
112			if [ $c_read != 0 ] || [ $c_write != 0 ] || \
113			    [ $c_cksum != 0 ]
114			then
115				(( errnum = errnum + 1 ))
116			fi
117			break
118		fi
119
120		c_read=`echo $line | awk '{print $3}'`
121		c_write=`echo $line | awk '{print $4}'`
122		c_cksum=`echo $line | awk '{print $5}'`
123		if [ $c_read != 0 ] || [ $c_write != 0 ] || \
124		    [ $c_cksum != 0 ]
125		then
126			(( errnum = errnum + 1 ))
127		fi
128	done <$tmpfile
129
130	return $errnum
131}
132
133function do_testing #<clear type> <vdevs>
134{
135	typeset FS=$TESTPOOL1/fs
136	typeset file=/$FS/f
137	typeset type=$1
138	shift
139	typeset vdev="$@"
140
141	log_must zpool create -f $TESTPOOL1 $vdev
142	log_must zfs create $FS
143	#
144	# Fully fill up the zfs filesystem in order to make data block errors
145	# zfs filesystem
146	#
147	typeset -i ret=0
148	typeset -i i=0
149	while true ; do
150		file_write -o create -f $file.$i -b $BLOCKSZ -c $NUM_WRITES
151		ret=$?
152		(( $ret != 0 )) && break
153		(( i = i + 1 ))
154	done
155	(( $ret != 28 )) && log_fail "file_write fails to fully fill up the $FS."
156
157	#
158	#Make errors to the testing pool by overwrite the vdev device with
159	#/usr/bin/dd command. We donot want to have a full overwrite. That
160	#may cause the system panic. So, we should skip the vdev label space.
161	#
162	(( i = $RANDOM % 3 ))
163	typeset -i wcount=0
164	typeset -i size
165	case $FILESIZE in
166		*g|*G)
167			(( size = ${FILESIZE%%[g|G]} ))
168			(( wcount = size*1024*1024 - 512 ))
169			;;
170		*m|*M)
171			(( size = ${FILESIZE%%[m|M]} ))
172			(( wcount = size*1024 - 512 ))
173			;;
174		*k|*K)
175			(( size = ${FILESIZE%%[k|K]} ))
176			(( wcount = size - 512 ))
177			;;
178		*)
179			(( wcount = FILESIZE/1024 - 512 ))
180			;;
181	esac
182	dd if=/dev/zero of=$fbase.$i seek=512 bs=1024 count=$wcount conv=notrunc \
183			> /dev/null 2>&1
184	log_must sync
185	log_must zpool scrub $TESTPOOL1
186	# Wait for the completion of scrub operation
187	while is_pool_scrubbing $TESTPOOL1; do
188		sleep 1
189	done
190
191	check_err $TESTPOOL1 && \
192		log_fail "No error generated."
193	if [[ $type == "device" ]]; then
194		log_must zpool clear $TESTPOOL1 $fbase.$i
195		! check_err $TESTPOOL1 $fbase.$i && \
196		    log_fail "'zpool clear' fails to clear error for $fbase.$i device."
197	fi
198
199	if [[ $type == "pool" ]]; then
200		log_must zpool clear $TESTPOOL1
201		! check_err $TESTPOOL1 && \
202		    log_fail "'zpool clear' fails to clear error for pool $TESTPOOL1."
203	fi
204
205	log_must zpool destroy $TESTPOOL1
206}
207
208log_note "'zpool clear' clears leaf-device error."
209for devconf in "${poolconf[@]}"; do
210	do_testing "device" $devconf
211done
212log_note "'zpool clear' clears top-level pool error."
213for devconf in "${poolconf[@]}"; do
214	do_testing "pool" $devconf
215done
216
217log_pass "'zpool clear' clears pool errors as expected."
218