1#!/bin/ksh -p
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright (c) 2018 by Lawrence Livermore National Security, LLC.
24# Copyright (c) 2020 by Delphix. All rights reserved.
25#
26
27# DESCRIPTION:
28#	Verify that duplicate I/O ereport errors are not posted
29#
30# STRATEGY:
31#	1. Create a mirror pool
32#	2. Inject duplicate read/write IO errors and checksum errors
33#	3. Verify there are no duplicate events being posted
34#
35
36. $STF_SUITE/include/libtest.shlib
37
38verify_runnable "both"
39
40MOUNTDIR=$TEST_BASE_DIR/mount
41FILEPATH=$MOUNTDIR/badfile
42VDEV1=$TEST_BASE_DIR/vfile1
43VDEV2=$TEST_BASE_DIR/vfile2
44POOL=error_pool
45FILESIZE="10M"
46OLD_LEN_MAX=$(get_tunable ZEVENT_LEN_MAX)
47RETAIN_MAX=$(get_tunable ZEVENT_RETAIN_MAX)
48
49EREPORTS="$STF_SUITE/tests/functional/cli_root/zpool_events/ereports"
50
51duplicates=false
52
53function cleanup
54{
55	log_must set_tunable64 ZEVENT_LEN_MAX $OLD_LEN_MAX
56
57	log_must zinject -c all
58	if poolexists $POOL ; then
59		destroy_pool $POOL
60	fi
61	log_must rm -f $VDEV1 $VDEV2
62}
63
64log_assert "Duplicate I/O ereport errors are not posted"
65log_note "zevent retain max setting: $RETAIN_MAX"
66
67log_onexit cleanup
68
69# Set our threshold high to avoid dropping events.
70set_tunable64 ZEVENT_LEN_MAX 20000
71
72log_must truncate -s $MINVDEVSIZE $VDEV1 $VDEV2
73log_must mkdir -p $MOUNTDIR
74
75#
76# $1: test type - corrupt (checksum error), io
77# $2: read, write
78function do_dup_test
79{
80	ERR=$1
81	RW=$2
82
83	log_note "Testing $ERR $RW ereports"
84	log_must zpool create -f -m $MOUNTDIR -o failmode=continue $POOL mirror $VDEV1 $VDEV2
85	log_must zpool events -c
86	log_must zfs set compression=off $POOL
87
88	if [ "$RW" == "read" ] ; then
89		log_must mkfile $FILESIZE $FILEPATH
90
91		# unmount and mount filesystems to purge file from ARC
92		# to force reads to go through error inject handler
93		log_must zfs unmount $POOL
94		log_must zfs mount $POOL
95
96		# all reads from this file get an error
97		if [ "$ERR" == "corrupt" ] ; then
98			log_must zinject -a -t data -e checksum -T read $FILEPATH
99		else
100			log_must zinject -a -t data -e io -T read $FILEPATH
101		fi
102
103		# Read the file a few times to generate some
104		# duplicate errors of the same blocks
105		for _ in {1..15}; do
106			dd if=$FILEPATH of=/dev/null bs=128K > /dev/null 2>&1
107		done
108		log_must zinject -c all
109	fi
110
111	log_must zinject -d $VDEV1 -e $ERR -T $RW -f 100 $POOL
112
113	if [ "$RW" == "write" ] ; then
114		log_must mkfile $FILESIZE $FILEPATH
115		sync_pool $POOL
116	fi
117
118	log_must zinject -c all
119
120	ereports="$($EREPORTS | sort)"
121	actual=$(echo "$ereports" | wc -l)
122	unique=$(echo "$ereports" | uniq | wc -l)
123	log_note "$actual total $ERR $RW ereports where $unique were unique"
124
125	if [ $actual -gt $unique ] ; then
126		log_note "UNEXPECTED -- $((actual-unique)) duplicate $ERR $RW ereports"
127		echo "$ereports"
128		duplicates=true
129	fi
130
131	log_must zpool destroy $POOL
132}
133
134do_dup_test "corrupt" "read"
135do_dup_test "io" "read"
136do_dup_test "io" "write"
137
138if $duplicates; then
139	log_fail "FAILED -- Duplicate I/O ereport errors encountered"
140else
141	log_pass "Duplicate I/O ereport errors are not posted"
142fi
143
144