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 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 destroied.
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	if datasetexists $CTR; then
81		log_must zfs destroy -Rf $CTR
82	fi
83
84	# According to option create test compatible environment.
85	case $opt in
86		-r|-rf) setup_testenv snap ;;
87		-R|-Rf) setup_testenv clone ;;
88		-f)	setup_testenv ;;
89		*)	log_fail "Incorrect option: '$opt'." ;;
90	esac
91
92	#
93	# According to different dataset type, create busy condition when try to
94	# destroy this dataset.
95	#
96	typeset mpt_dir
97	case $dtst in
98		$CTR|$FS)
99			if [[ $opt == *f* ]]; then
100				mpt_dir=$(get_prop mountpoint $FS)
101				pidlist="$pidlist $(mkbusy \
102				    $mpt_dir/$TESTFILE0)"
103				log_note "mkbusy $mpt_dir/$TESTFILE0 " \
104				    "(pidlist: $pidlist)"
105				[[ -z $pidlist ]] && \
106				    log_fail "Failure from mkbusy"
107				log_mustnot zfs destroy -rR $dtst
108			fi
109			;;
110		$VOL)
111			if [[ $opt == *f* ]]; then
112				pidlist="$pidlist $(mkbusy \
113				    $TESTDIR1/$TESTFILE0)"
114				log_note "mkbusy $TESTDIR1/$TESTFILE0 " \
115				    "(pidlist: $pidlist)"
116				[[ -z $pidlist ]] && \
117				    log_fail "Failure from mkbusy"
118				log_mustnot zfs destroy -rR $dtst
119			fi
120			;;
121		$VOLSNAP)
122			if [[ $opt == *f* ]]; then
123				pidlist="$pidlist $(mkbusy \
124				    $TESTDIR1/$TESTFILE0)"
125				log_note "mkbusy $TESTDIR1/$TESTFILE0 " \
126				    "(pidlist: $pidlist)"
127				[[ -z $pidlist ]] && \
128				    log_fail "Failure from mkbusy"
129				log_must zfs destroy -rR $dtst
130				log_must zfs snapshot $dtst
131			fi
132			;;
133		$FSSNAP)
134			if [[ $opt == *f* ]]; then
135				mpt_dir=$(snapshot_mountpoint $dtst)
136				pidlist="$pidlist $(mkbusy $mpt_dir)"
137				log_note "mkbusy $mpt_dir (pidlist: $pidlist)"
138				[[ -z $pidlist ]] && \
139				    log_fail "Failure from mkbusy"
140				log_must zfs destroy -rR $dtst
141				log_must zfs snapshot $dtst
142			fi
143			;;
144		*)	log_fail "Unsupported dataset: '$dtst'."
145	esac
146
147	# Firstly, umount ufs filesystem which was created by zfs volume.
148	if is_global_zone; then
149		log_must umount -f $TESTDIR1
150	fi
151
152	# Invoke 'zfs destroy [-rRf] <dataset>'
153	log_must zfs destroy $opt $dtst
154
155	# Kill any lingering instances of mkbusy, and clear the list.
156	[[ -z $pidlist ]] || log_must kill -TERM $pidlist
157	pidlist=""
158	log_mustnot pgrep -fl mkbusy
159
160	case $dtst in
161		$CTR)	check_dataset datasetnonexists \
162					$CTR $FS $VOL $FSSNAP $VOLSNAP
163			if [[ $opt == *R* ]]; then
164				check_dataset datasetnonexists \
165					$FSCLONE $VOLCLONE
166			fi
167			;;
168		$FS)	check_dataset datasetexists $CTR $VOL
169			check_dataset datasetnonexists $FS
170			if [[ $opt != -f ]]; then
171				check_dataset datasetexists $VOLSNAP
172				check_dataset datasetnonexists $FSSNAP
173			fi
174			if [[ $opt == *R* ]]; then
175				check_dataset datasetexists $VOLCLONE
176				check_dataset datasetnonexists $FSCLONE
177			fi
178			;;
179		$VOL)	check_dataset datasetexists $CTR $FS $FSSNAP
180			check_dataset datasetnonexists $VOL $VOLSNAP
181			if [[ $opt == *R* ]]; then
182				check_dataset datasetexists $FSCLONE
183				check_dataset datasetnonexists $VOLCLONE
184			fi
185			;;
186		$FSSNAP)
187			check_dataset datasetexists $CTR $FS $VOL $VOLSNAP
188			check_dataset datasetnonexists $FSSNAP
189			if [[ $opt == *R* ]]; then
190				check_dataset datasetexists $VOLCLONE
191				check_dataset datasetnonexists $FSCLONE
192			fi
193			;;
194		$VOLSNAP)
195			check_dataset datasetexists $CTR $FS $VOL $FSSNAP
196			check_dataset datasetnonexists $VOLSNAP
197			if [[ $opt == *R* ]]; then
198				check_dataset datasetexists $FSCLONE
199				check_dataset datasetnonexists $VOLCLONE
200			fi
201			;;
202	esac
203
204	log_note "'zfs destroy $opt $dtst' passed."
205}
206
207log_assert "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' should " \
208	"recursively destroy all children."
209log_onexit cleanup_testenv
210
211typeset dtst=""
212typeset opt=""
213typeset pidlist=""
214for dtst in $CTR $FS $VOL $FSSNAP $VOLSNAP; do
215	for opt in "-r" "-R" "-f" "-rf" "-Rf"; do
216		log_note "Starting test: zfs destroy $opt $dtst"
217		test_n_check $opt $dtst
218	done
219done
220
221log_pass "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' passed."
222