1#
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 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27#
28# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
29#
30
31. $STF_SUITE/include/libtest.shlib
32. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback.cfg
33
34# Get file sum
35#
36# $1 full file name
37function getsum #fname
38{
39	(( ${#1} == 0 )) && \
40		log_fail "Need give file name."
41	return $(sum $1 | awk '{print $1}')
42}
43
44# Define global variable checksum, get the original file sum.
45#
46origsum=$(getsum /etc/passwd)
47
48#
49# Setup or recover the test environment. Firstly, copy /etc/passwd to ZFS file
50# system or volume, then make a snapshot or clone. Repeat up to three times.
51#
52# $1 number of snapshot. Note: Currently only support three snapshots.
53# $2 indicate if it is necessary to create clone
54#
55function setup_snap_env
56{
57	typeset -i cnt=${1:-3}
58	typeset createclone=${2:-"false"}
59
60	if datasetnonexists $FS; then
61		log_must zfs create $FS
62		log_must zfs set mountpoint=$TESTDIR $FS
63	fi
64	# Volume can't be created in Local Zone.
65	if datasetnonexists $VOL && is_global_zone; then
66		log_must zfs create -V $VOLSIZE $VOL
67		block_device_wait
68	fi
69
70	# Make sure $VOL is volume
71	typeset type=$(get_prop type $VOL)
72	if datasetexists $VOL && \
73		[[ $type == 'volume' ]]; then
74		#
75		# At the first time, Make a UFS file system in volume and
76		# mount it. Otherwise, only check if this ufs|ext file system
77		# was mounted.
78		#
79		log_must new_fs $ZVOL_DEVDIR/$VOL
80
81		[[ ! -d $TESTDIR1 ]] && log_must mkdir $TESTDIR1
82
83		# Make sure the ufs|ext filesystem hasn't been mounted,
84		# then mount the new ufs|ext filesystem.
85		if ! ismounted $TESTDIR1 $NEWFS_DEFAULT_FS; then
86			log_must mount $ZVOL_DEVDIR/$VOL $TESTDIR1
87		fi
88	fi
89
90	# Separately Create three snapshots for file system & volume
91	typeset -i ind=0
92	typeset dtst
93	for dtst in $FS $VOL; do
94		# Volume can be created in Local Zone.
95		if [[ $dtst == $VOL ]]; then
96			if ! is_global_zone; then
97				break
98			fi
99		fi
100
101		ind=0
102		while (( ind < cnt )); do
103			case $dtst in
104			$FS)
105				eval typeset snap=\$FSSNAP$ind
106				eval typeset clone=\$FSCLONE$ind
107				eval typeset fname=\$TESTDIR/\$TESTFILE$ind
108				;;
109			$VOL)
110				eval typeset snap=\$VOLSNAP$ind
111				eval typeset clone=\$VOLCLONE$ind
112				eval typeset fname=\$TESTDIR1/\$TESTFILE$ind
113				;;
114			esac
115
116			if datasetnonexists $snap; then
117				log_must cp /etc/passwd $fname
118				if is_linux || is_freebsd; then
119					log_must sync
120				else
121					#
122					# using 'lockfs -f' to flush the writes
123					# to disk before taking a snapshot.
124					#
125					if [[ $dtst == $VOL ]]; then
126						log_must lockfs -f $TESTDIR1
127					fi
128				fi
129				if is_freebsd && [[ $dtst == $VOL ]]; then
130					# Though sync does start a fs sync on
131					# FreeBSD, it does not wait for it to
132					# finish.  We can force a blocking sync
133					# by updating the fs mount instead.
134					# Otherwise, the snapshot might occur
135					# with the fs in an unmountable state.
136					log_must mount -ur \
137					    $ZVOL_DEVDIR/$VOL $TESTDIR1
138				fi
139				log_must zfs snapshot $snap
140				if is_freebsd && [[ $dtst == $VOL ]]; then
141					log_must mount -uw \
142					    $ZVOL_DEVDIR/$VOL $TESTDIR1
143				fi
144			fi
145			if [[ $createclone == "true" ]]; then
146				if datasetnonexists $clone; then
147					log_must zfs clone $snap $clone
148					block_device_wait
149				fi
150			fi
151			(( ind += 1 ))
152		done
153	done
154}
155
156function setup_clone_env
157{
158	setup_snap_env $1 "true"
159}
160
161#
162# Clean up the test environment
163#
164# $1 number of snapshot Note: Currently only support three snapshots.
165#
166function cleanup_env
167{
168	typeset -i cnt=${1:-3}
169	typeset -i ind=0
170	typeset dtst
171	typeset snap
172
173	pkill -x dd
174
175	if ismounted $TESTDIR1 $NEWFS_DEFAULT_FS; then
176		log_must umount -f $TESTDIR1
177	fi
178
179	[[ -d $TESTDIR ]] && log_must rm -rf $TESTDIR/*
180	[[ -d $TESTDIR1 ]] && log_must rm -rf $TESTDIR1/*
181
182	for dtst in $FS $VOL; do
183		for snap in $TESTSNAP $TESTSNAP1 $TESTSNAP2; do
184			if snapexists $dtst@$snap; then
185				 log_must zfs destroy -Rf $dtst@$snap
186			fi
187		done
188	done
189
190	# Restore original test environment
191	if datasetnonexists $FS ; then
192		log_must zfs create $FS
193	fi
194	if datasetnonexists $VOL ; then
195		if is_global_zone ; then
196			log_must zfs create -V $VOLSIZE $VOL
197		else
198			log_must zfs create $VOL
199		fi
200	fi
201}
202
203#
204# check if the specified files have specified status.
205#
206# $1 expected status
207# $2-n full file name
208# If it is true return 0, else return 1
209#
210function file_status
211{
212	(( $# == 0 )) && \
213		log_fail "The file name is not defined."
214
215	typeset opt
216	case $1 in
217		exist)	opt="-e" ;;
218		nonexist) opt="! -e" ;;
219		*)	log_fail "Unsupported file status." ;;
220	esac
221
222	shift
223	while (( $# > 0 )); do
224		eval [[ $opt $1 ]] || return 1
225		shift
226	done
227
228	return 0
229}
230
231function files_exist
232{
233	file_status "exist" $@
234}
235
236function files_nonexist
237{
238	file_status "nonexist" $@
239}
240
241#
242# According to snapshot check if the file system was recovered to the right
243# point.
244#
245# $1 snapshot. fs@snap or vol@snap
246#
247function check_files
248{
249	typeset dtst=$1
250
251	if [[ $(get_prop type $dtst) != snapshot ]]; then
252		log_fail "Parameter must be a snapshot."
253	fi
254
255	typeset fsvol=${dtst%%@*}
256	typeset snap=${dtst##*@}
257	if [[ $(get_prop type $fsvol) == "filesystem" ]]; then
258		ind=""
259	else
260		ind="1"
261	fi
262
263	eval typeset file0=\$TESTDIR$ind/\$TESTFILE0
264	eval typeset file1=\$TESTDIR$ind/\$TESTFILE1
265	eval typeset file2=\$TESTDIR$ind/\$TESTFILE2
266
267	case $snap in
268		$TESTSNAP2)
269			log_must files_exist $file0 $file1 $file2
270
271			typeset sum0=$(getsum $file0)
272			typeset sum1=$(getsum $file1)
273			typeset sum2=$(getsum $file2)
274			if [[ $sum0 != $origsum || \
275				$sum1 != $origsum || sum2 != $origsum ]]
276			then
277				log_fail "After rollback, file sum is changed."
278			fi
279			;;
280		$TESTSNAP1)
281			log_must files_exist $file0 $file1
282			log_must files_nonexist $file2
283
284			typeset sum0=$(getsum $file0)
285			typeset sum1=$(getsum $file1)
286			if [[ $sum0 != $origsum || $sum1 != $origsum ]]
287			then
288				log_fail "After rollback, file sum is changed."
289			fi
290			;;
291		$TESTSNAP)
292			log_must files_exist $file0
293			log_must files_nonexist $file1 $file2
294
295			typeset sum0=$(getsum $file0)
296			if [[ $sum0 != $origsum ]]; then
297				log_fail "After rollback, file sum is changed."
298			fi
299			;;
300	esac
301}
302
303# According to dataset type, write file to different directories.
304#
305# $1 dataset
306#
307function write_mountpoint_dir
308{
309	typeset dtst=$1
310	typeset dir
311
312	if [[ $dtst == $FS ]]; then
313		dir=$TESTDIR
314		log_must ismounted $dir
315	else
316		dir=$TESTDIR1
317		log_must ismounted $dir $NEWFS_DEFAULT_FS
318	fi
319	dd if=/dev/urandom of=$dir/$TESTFILE1 &
320	log_must sleep 3
321}
322