1#!/usr/bin/ksh -p
2
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright (c) 2016 by Delphix. All rights reserved.
16#
17
18. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.kshlib
19
20#
21# DESCRIPTION:
22#	A pool should be importable using an outdated cachefile that is unaware
23#	of a zpool replace operation at different stages in time.
24#
25# STRATEGY:
26#	1. Create a pool with some devices and an alternate cachefile.
27#	2. Backup the cachefile.
28#	3. Initiate device replacement, backup cachefile again and export pool.
29#	   Special care must be taken so that resilvering doesn't complete
30#	   before we exported the pool.
31#	4. Verify that we can import the pool using the first cachefile backup.
32#	   (Test 1. cachefile: pre-replace, pool: resilvering)
33#	5. Wait for the resilvering to finish and export the pool.
34#	6. Verify that we can import the pool using the first cachefile backup.
35#	   (Test 2. cachefile: pre-replace, pool: post-replace)
36#	7. Export the pool.
37#	8. Verify that we can import the pool using the second cachefile backup.
38#	   (Test 3. cachefile: resilvering, pool: post-replace)
39#
40# STRATEGY TO SLOW DOWN RESILVERING:
41#	1. Reduce zfs_txg_timeout, which controls how long can we resilver for
42#	   each sync.
43#	2. Add data to pool
44#	3. Re-import the pool so that data isn't cached
45#	4. Use zinject to slow down device I/O
46#	5. Trigger the resilvering
47#	6. Use spa freeze to stop writing to the pool.
48#	7. Clear zinject events (needed to export the pool)
49#	8. Export the pool
50#
51
52verify_runnable "global"
53
54ZFS_TXG_TIMEOUT=""
55
56function custom_cleanup
57{
58	# Revert zfs_txg_timeout to defaults
59	[[ -n ZFS_TXG_TIMEOUT ]] &&
60	    log_must set_zfs_txg_timeout $ZFS_TXG_TIMEOUT
61
62	cleanup
63}
64
65log_onexit custom_cleanup
66
67function test_replacing_vdevs
68{
69	typeset poolcreate="$1"
70	typeset replacevdev="$2"
71	typeset replaceby="$3"
72	typeset poolfinalstate="$4"
73	typeset zinjectdevices="$5"
74	typeset earlyremove="$6"
75
76	log_note "$0: pool '$poolcreate', replace $replacevdev by $replaceby."
77
78	log_must zpool create -o cachefile=$CPATH $TESTPOOL1 $poolcreate
79
80	# Cachefile: pool in pre-replace state
81	log_must cp $CPATH $CPATHBKP
82
83	# Steps to insure resilvering happens very slowly.
84	log_must write_some_data $TESTPOOL1
85	log_must zpool export $TESTPOOL1
86	log_must cp $CPATHBKP $CPATH
87	log_must zpool import -c $CPATH -o cachefile=$CPATH $TESTPOOL1
88	typeset device
89	for device in $zinjectdevices ; do
90		log_must zinject -d $device -D 200:1 $TESTPOOL1 > /dev/null
91	done
92	log_must zpool replace $TESTPOOL1 $replacevdev $replaceby
93
94	# Cachefile: pool in resilvering state
95	log_must cp $CPATH $CPATHBKP2
96
97	# We must disable zinject in order to export the pool, so we freeze
98	# it first to prevent writing out subsequent resilvering progress.
99	log_must zpool freeze $TESTPOOL1
100	# Confirm pool is still replacing
101	log_must pool_is_replacing $TESTPOOL1
102	log_must zinject -c all > /dev/null
103	log_must zpool export $TESTPOOL1
104
105	( $earlyremove ) && log_must rm $replacevdev
106
107	############################################################
108	# Test 1. Cachefile: pre-replace, pool: resilvering
109	############################################################
110	log_must cp $CPATHBKP $CPATH
111	log_must zpool import -c $CPATH $TESTPOOL1
112
113	# Wait for resilvering to finish
114	log_must wait_for_pool_config $TESTPOOL1 "$poolfinalstate"
115	log_must zpool export $TESTPOOL1
116
117	( ! $earlyremove ) && log_must rm $replacevdev
118
119	############################################################
120	# Test 2. Cachefile: pre-replace, pool: post-replace
121	############################################################
122	log_must zpool import -c $CPATHBKP $TESTPOOL1
123	log_must check_pool_config $TESTPOOL1 "$poolfinalstate"
124	log_must zpool export $TESTPOOL1
125
126	############################################################
127	# Test 3. Cachefile: resilvering, pool: post-replace
128	############################################################
129	log_must zpool import -c $CPATHBKP2 $TESTPOOL1
130	log_must check_pool_config $TESTPOOL1 "$poolfinalstate"
131
132	# Cleanup
133	log_must zpool destroy $TESTPOOL1
134	log_must rm -f $CPATH $CPATHBKP $CPATHBKP2
135	log_must mkfile $FILE_SIZE $replacevdev
136
137	log_note ""
138}
139
140# We set zfs_txg_timeout to 1 to reduce resilvering time at each sync.
141ZFS_TXG_TIMEOUT=$(get_zfs_txg_timeout)
142set_zfs_txg_timeout 1
143
144test_replacing_vdevs "$VDEV0 $VDEV1" \
145    "$VDEV1" "$VDEV2" \
146    "$VDEV0 $VDEV2" \
147    "$VDEV0 $VDEV1" \
148    false
149
150test_replacing_vdevs "mirror $VDEV0 $VDEV1" \
151	"$VDEV1" "$VDEV2" \
152	"mirror $VDEV0 $VDEV2" \
153	"$VDEV0 $VDEV1" \
154	true
155
156test_replacing_vdevs "raidz $VDEV0 $VDEV1 $VDEV2" \
157	"$VDEV1" "$VDEV3" \
158	"raidz $VDEV0 $VDEV3 $VDEV2" \
159	"$VDEV0 $VDEV1 $VDEV2" \
160	true
161
162set_zfs_txg_timeout $ZFS_TXG_TIMEOUT
163
164log_pass "zpool import -c cachefile_unaware_of_replace passed."
165