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 https://opensource.org/licenses/CDDL-1.0.
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 2008 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
30# Copyright (c) 2020 by Lawrence Livermore National Security, LLC.
31#
32
33. $STF_SUITE/include/libtest.shlib
34. $STF_SUITE/tests/functional/replacement/replacement.cfg
35
36#
37# DESCRIPTION:
38# 	Attaching disks during I/O should pass for supported pools.
39#
40# STRATEGY:
41#	1. Create multidisk pools (stripe/mirror/raidz/draid) and
42#	   start some random I/O
43#	2. Attach a disk to the pool.
44#	3. Verify the integrity of the file system and the resilvering.
45#
46# NOTE: Raidz does not support the sequential resilver (-s) option.
47#
48
49verify_runnable "global"
50
51function cleanup
52{
53	if [[ -n "$child_pids" ]]; then
54		for wait_pid in $child_pids; do
55			kill $wait_pid
56		done
57	fi
58
59	if poolexists $TESTPOOL1; then
60		destroy_pool $TESTPOOL1
61	fi
62
63	[[ -e $TESTDIR ]] && log_must rm -rf $TESTDIR/*
64}
65
66log_assert "Replacing a disk during I/O completes."
67
68options=""
69options_display="default options"
70
71log_onexit cleanup
72
73[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
74
75[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
76
77[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
78
79[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
80
81[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
82
83options="$options -r "
84
85[[ -n "$options" ]] && options_display=$options
86
87child_pids=""
88
89function attach_test
90{
91	typeset -i iters=2
92	typeset -i index=0
93	typeset opt=$1
94	typeset disk1=$2
95	typeset disk2=$3
96
97	typeset i=0
98	while [[ $i -lt $iters ]]; do
99		log_note "Invoking file_trunc with: $options_display"
100		file_trunc $options $TESTDIR/$TESTFILE.$i &
101		typeset pid=$!
102
103		sleep 1
104
105		child_pids="$child_pids $pid"
106		((i = i + 1))
107	done
108
109	log_must zpool attach -sw $opt $TESTPOOL1 $disk1 $disk2
110
111	for wait_pid in $child_pids; do
112		kill $wait_pid
113	done
114	child_pids=""
115
116	log_must zpool export $TESTPOOL1
117	log_must zpool import -d $TESTDIR $TESTPOOL1
118	log_must zfs umount $TESTPOOL1/$TESTFS1
119	log_must zdb -cdui $TESTPOOL1/$TESTFS1
120	log_must zfs mount $TESTPOOL1/$TESTFS1
121	verify_pool $TESTPOOL1
122}
123
124specials_list=""
125i=0
126while [[ $i != 3 ]]; do
127	truncate -s $MINVDEVSIZE $TESTDIR/$TESTFILE1.$i
128	specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
129
130	((i = i + 1))
131done
132
133#
134# Create a replacement disk special file.
135#
136truncate -s $MINVDEVSIZE $TESTDIR/$REPLACEFILE
137
138for op in "" "-f"; do
139	create_pool $TESTPOOL1 mirror $specials_list
140	log_must zfs create $TESTPOOL1/$TESTFS1
141	log_must zfs set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
142
143	attach_test "$opt" $TESTDIR/$TESTFILE1.1 $TESTDIR/$REPLACEFILE
144
145	log_must eval "zpool iostat -v $TESTPOOL1 | grep \"$REPLACEFILE\""
146
147	destroy_pool $TESTPOOL1
148done
149
150log_note "Verify 'zpool attach' fails with non-mirrors."
151
152for type in "" "raidz" "raidz1" "draid" "draid1"; do
153	for op in "" "-f"; do
154		create_pool $TESTPOOL1 $type $specials_list
155		log_must zfs create $TESTPOOL1/$TESTFS1
156		log_must zfs set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
157
158		log_mustnot zpool attach -s "$opt" $TESTDIR/$TESTFILE1.1 \
159		    $TESTDIR/$REPLACEFILE
160
161		log_mustnot eval "zpool iostat -v $TESTPOOL1 | grep \"$REPLACEFILE\""
162
163		destroy_pool $TESTPOOL1
164	done
165done
166
167log_pass
168