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 (c) 2020 by vStack. All rights reserved.
25#
26
27. $STF_SUITE/include/libtest.shlib
28
29#
30# DESCRIPTION:
31#	'zpool attach poolname raidz ...' should attach new device to the pool.
32#
33# STRATEGY:
34#	1. Create block device files for the test raidz pool
35#	2. For each parity value [1..3]
36#	    - create raidz pool
37#	    - fill it with some directories/files
38#	    - attach device to the raidz pool
39#	    - verify that device attached and the raidz pool size increase
40#	    - verify resilver by replacing parity devices
41#	    - verify resilver by replacing data devices
42#	    - verify scrub by zeroing parity devices
43#	    - verify scrub by zeroing data devices
44#	    - verify the raidz pool
45#	    - destroy the raidz pool
46
47typeset -r devs=6
48typeset -r dev_size_mb=128
49
50typeset -a disks
51
52prefetch_disable=$(get_tunable PREFETCH_DISABLE)
53
54function cleanup
55{
56	log_pos zpool status $TESTPOOL
57
58	poolexists "$TESTPOOL" && log_must_busy zpool destroy "$TESTPOOL"
59
60	for i in {0..$devs}; do
61		log_must rm -f "$TEST_BASE_DIR/dev-$i"
62	done
63
64	log_must set_tunable32 PREFETCH_DISABLE $prefetch_disable
65	log_must set_tunable64 RAIDZ_EXPAND_MAX_REFLOW_BYTES 0
66}
67
68function wait_expand_paused
69{
70	oldcopied='0'
71	newcopied='1'
72	while [[ $oldcopied != $newcopied ]]; do
73		oldcopied=$newcopied
74		sleep 2
75		newcopied=$(zpool status $TESTPOOL | \
76		    grep 'copied out of' | \
77		    awk '{print $1}')
78		log_note "newcopied=$newcopied"
79	done
80	log_note "paused at $newcopied"
81}
82
83function test_resilver # <pool> <parity> <dir>
84{
85	typeset pool=$1
86	typeset nparity=$2
87	typeset dir=$3
88
89	for (( i=0; i<$nparity; i=i+1 )); do
90		log_must zpool offline $pool $dir/dev-$i
91	done
92
93	log_must zpool export $pool
94
95	for (( i=0; i<$nparity; i=i+1 )); do
96		log_must zpool labelclear -f $dir/dev-$i
97	done
98
99	log_must zpool import -o cachefile=none -d $dir $pool
100
101	for (( i=0; i<$nparity; i=i+1 )); do
102		log_must zpool replace -f $pool $dir/dev-$i
103	done
104
105	log_must zpool wait -t resilver $pool
106
107	log_must check_pool_status $pool "errors" "No known data errors"
108
109	log_must zpool clear $pool
110
111	for (( i=$nparity; i<$nparity*2; i=i+1 )); do
112		log_must zpool offline $pool $dir/dev-$i
113	done
114
115	log_must zpool export $pool
116
117	for (( i=$nparity; i<$nparity*2; i=i+1 )); do
118		log_must zpool labelclear -f $dir/dev-$i
119	done
120
121	log_must zpool import -o cachefile=none -d $dir $pool
122
123	for (( i=$nparity; i<$nparity*2; i=i+1 )); do
124		log_must zpool replace -f $pool $dir/dev-$i
125	done
126
127	log_must zpool wait -t resilver $pool
128
129	log_must check_pool_status $pool "errors" "No known data errors"
130
131	log_must zpool clear $pool
132}
133
134function test_scrub # <pool> <parity> <dir>
135{
136	typeset pool=$1
137	typeset nparity=$2
138	typeset dir=$3
139	typeset combrec=$4
140
141	reflow_size=$(get_pool_prop allocated $pool)
142	randbyte=$(( ((RANDOM<<15) + RANDOM) % $reflow_size ))
143	log_must set_tunable64 RAIDZ_EXPAND_MAX_REFLOW_BYTES $randbyte
144	log_must zpool attach $TESTPOOL ${raid}-0 $dir/dev-$devs
145	wait_expand_paused
146
147	log_must zpool export $pool
148
149	# zero out parity disks
150	for (( i=0; i<$nparity; i=i+1 )); do
151		dd conv=notrunc if=/dev/zero of=$dir/dev-$i \
152		    bs=1M seek=4 count=$(($dev_size_mb-4))
153	done
154
155	log_must zpool import -o cachefile=none -d $dir $pool
156
157	log_must zpool scrub -w $pool
158	log_must zpool clear $pool
159	log_must zpool export $pool
160
161	# zero out parity count worth of data disks
162	for (( i=$nparity; i<$nparity*2; i=i+1 )); do
163		dd conv=notrunc if=/dev/zero of=$dir/dev-$i \
164		    bs=1M seek=4 count=$(($dev_size_mb-4))
165	done
166
167	log_must zpool import -o cachefile=none -d $dir $pool
168
169	log_must zpool scrub -w $pool
170
171	log_must check_pool_status $pool "errors" "No known data errors"
172
173	log_must zpool clear $pool
174	log_must set_tunable64 RAIDZ_EXPAND_MAX_REFLOW_BYTES 0
175	log_must zpool wait -t raidz_expand $TESTPOOL
176}
177
178log_onexit cleanup
179
180log_must set_tunable32 PREFETCH_DISABLE 1
181
182# Disk files which will be used by pool
183for i in {0..$(($devs - 1))}; do
184	device=$TEST_BASE_DIR/dev-$i
185	log_must truncate -s ${dev_size_mb}M $device
186	disks[${#disks[*]}+1]=$device
187done
188
189# Disk file which will be attached
190log_must truncate -s 512M $TEST_BASE_DIR/dev-$devs
191
192nparity=$((RANDOM%(3) + 1))
193raid=raidz$nparity
194dir=$TEST_BASE_DIR
195
196log_must zpool create -f -o cachefile=none $TESTPOOL $raid ${disks[@]}
197log_must zfs set primarycache=metadata $TESTPOOL
198
199log_must zfs create $TESTPOOL/fs
200log_must fill_fs /$TESTPOOL/fs 1 512 100 1024 R
201
202log_must zfs create -o compress=on $TESTPOOL/fs2
203log_must fill_fs /$TESTPOOL/fs2 1 512 100 1024 R
204
205log_must zfs create -o compress=on -o recordsize=8k $TESTPOOL/fs3
206log_must fill_fs /$TESTPOOL/fs3 1 512 100 1024 R
207
208log_must check_pool_status $TESTPOOL "errors" "No known data errors"
209
210test_scrub $TESTPOOL $nparity $dir
211test_resilver $TESTPOOL $nparity $dir
212
213zpool destroy "$TESTPOOL"
214
215log_pass "raidz expansion test succeeded."
216