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 2009 Sun Microsystems, Inc.  All rights reserved.
25# Use is subject to license terms.
26#
27
28#
29# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
30#
31
32. $STF_SUITE/include/libtest.shlib
33. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
34. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
35
36#
37# DESCRIPTION:
38#	'zfs destroy -r|-rf|-R|-Rf <fs|ctr|vol|snap>' should recursively destroy
39#	all children and clones based on options.
40#
41# STRATEGY:
42#	1. Create test environment according to options. There are three test
43#	models can be created. Only ctr, fs & vol; with snap; with clone.
44#	2. According to option, make the dataset busy or not.
45#	3. Run 'zfs destroy [-rRf] <dataset>'
46#	4. According to dataset and option, check if get the expected results.
47#
48
49verify_runnable "both"
50
51#
52# According to parameters, 1st, create suitable testing environment. 2nd,
53# run 'zfs destroy $opt <dataset>'. 3rd, check the system status.
54#
55# $1 option of 'zfs destroy'
56# $2 dataset will be destroyed.
57#
58function test_n_check
59{
60	typeset opt=$1
61	typeset dtst=$2
62
63	if ! is_global_zone ; then
64		if [[ $dtst == $VOL || $dtst == $VOLSNAP ]]; then
65			log_note "UNSUPPORTED: Volume are unavailable in LZ."
66			return
67		fi
68	fi
69
70	# '-f' has no effect on non-filesystems
71	if [[ $opt == -f ]]; then
72		if [[ $dtst != $FS ]]; then
73			log_note "UNSUPPORTED: '-f ' is only available for " \
74			    "leaf FS."
75			return
76		fi
77	fi
78
79	# Clean the test environment and make it clear.
80	datasetexists $CTR && destroy_dataset $CTR -Rf
81
82	# According to option create test compatible environment.
83	case $opt in
84		-r|-rf) setup_testenv snap ;;
85		-R|-Rf) setup_testenv clone ;;
86		-f)	setup_testenv ;;
87		*)	log_fail "Incorrect option: '$opt'." ;;
88	esac
89
90	#
91	# According to different dataset type, create busy condition when try to
92	# destroy this dataset.
93	#
94	typeset mpt_dir
95	case $dtst in
96		$CTR|$FS)
97			if [[ $opt == *f* ]]; then
98				mpt_dir=$(get_prop mountpoint $FS)
99				pidlist="$pidlist $(mkbusy \
100				    $mpt_dir/$TESTFILE0)"
101				log_note "mkbusy $mpt_dir/$TESTFILE0 " \
102				    "(pidlist: $pidlist)"
103				[[ -z $pidlist ]] && \
104				    log_fail "Failure from mkbusy"
105				log_mustnot zfs destroy -rR $dtst
106			fi
107			;;
108		$VOL)
109			if [[ $opt == *f* ]]; then
110				pidlist="$pidlist $(mkbusy \
111				    $TESTDIR1/$TESTFILE0)"
112				log_note "mkbusy $TESTDIR1/$TESTFILE0 " \
113				    "(pidlist: $pidlist)"
114				[[ -z $pidlist ]] && \
115				    log_fail "Failure from mkbusy"
116				log_mustnot zfs destroy -rR $dtst
117			fi
118			;;
119		$VOLSNAP)
120			if [[ $opt == *f* ]]; then
121				pidlist="$pidlist $(mkbusy \
122				    $TESTDIR1/$TESTFILE0)"
123				log_note "mkbusy $TESTDIR1/$TESTFILE0 " \
124				    "(pidlist: $pidlist)"
125				[[ -z $pidlist ]] && \
126				    log_fail "Failure from mkbusy"
127				log_must_busy zfs destroy -rR $dtst
128				log_must zfs snapshot $dtst
129			fi
130			;;
131		$FSSNAP)
132			if [[ $opt == *f* ]]; then
133				mpt_dir=$(snapshot_mountpoint $dtst)
134				pidlist="$pidlist $(mkbusy $mpt_dir)"
135				log_note "mkbusy $mpt_dir (pidlist: $pidlist)"
136				[[ -z $pidlist ]] && \
137				    log_fail "Failure from mkbusy"
138				if is_linux ; then
139					log_mustnot zfs destroy -rR $dtst
140				else
141					log_must zfs destroy -rR $dtst
142					log_must zfs snapshot $dtst
143				fi
144			fi
145			;;
146		*)	log_fail "Unsupported dataset: '$dtst'."
147	esac
148
149	# Kill any lingering instances of mkbusy, and clear the list.
150	if is_linux ; then
151		[[ -z $pidlist ]] || log_must kill -TERM $pidlist
152		pidlist=""
153		log_mustnot pgrep -fl mkbusy
154	fi
155
156	# Firstly, umount ufs filesystem which was created by zfs volume.
157	if is_global_zone; then
158		log_must umount -f $TESTDIR1
159	fi
160
161	# Invoke 'zfs destroy [-rRf] <dataset>'
162	log_must_busy zfs destroy $opt $dtst
163	block_device_wait
164
165	# Kill any lingering instances of mkbusy, and clear the list.
166	if ! is_linux ; then
167		[[ -z $pidlist ]] || log_must kill -TERM $pidlist
168		pidlist=""
169		log_mustnot pgrep -fl mkbusy
170	fi
171
172	case $dtst in
173		$CTR)	check_dataset datasetnonexists \
174					$CTR $FS $VOL $FSSNAP $VOLSNAP
175			if [[ $opt == *R* ]]; then
176				check_dataset datasetnonexists \
177					$FSCLONE $VOLCLONE
178			fi
179			;;
180		$FS)	check_dataset datasetexists $CTR $VOL
181			check_dataset datasetnonexists $FS
182			if [[ $opt != -f ]]; then
183				check_dataset datasetexists $VOLSNAP
184				check_dataset datasetnonexists $FSSNAP
185			fi
186			if [[ $opt == *R* ]]; then
187				check_dataset datasetexists $VOLCLONE
188				check_dataset datasetnonexists $FSCLONE
189			fi
190			;;
191		$VOL)	check_dataset datasetexists $CTR $FS $FSSNAP
192			check_dataset datasetnonexists $VOL $VOLSNAP
193			if [[ $opt == *R* ]]; then
194				check_dataset datasetexists $FSCLONE
195				check_dataset datasetnonexists $VOLCLONE
196			fi
197			;;
198		$FSSNAP)
199			check_dataset datasetexists $CTR $FS $VOL $VOLSNAP
200			check_dataset datasetnonexists $FSSNAP
201			if [[ $opt == *R* ]]; then
202				check_dataset datasetexists $VOLCLONE
203				check_dataset datasetnonexists $FSCLONE
204			fi
205			;;
206		$VOLSNAP)
207			check_dataset datasetexists $CTR $FS $VOL $FSSNAP
208			check_dataset datasetnonexists $VOLSNAP
209			if [[ $opt == *R* ]]; then
210				check_dataset datasetexists $FSCLONE
211				check_dataset datasetnonexists $VOLCLONE
212			fi
213			;;
214	esac
215
216	log_note "'zfs destroy $opt $dtst' passed."
217}
218
219log_assert "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' should " \
220	"recursively destroy all children."
221log_onexit cleanup_testenv
222
223typeset dtst=""
224typeset opt=""
225typeset pidlist=""
226for dtst in $CTR $FS $VOL $FSSNAP $VOLSNAP; do
227	for opt in "-r" "-R" "-f" "-rf" "-Rf"; do
228		log_note "Starting test: zfs destroy $opt $dtst"
229		test_n_check $opt $dtst
230	done
231done
232
233log_pass "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' passed."
234