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#	Seperately verify 'zfs destroy -f|-r|-rf|-R|-rR <dataset>' will fail in
39#       different conditions.
40#
41# STRATEGY:
42#	1. Create pool, fs & vol.
43#	2. Create snapshot for fs & vol.
44#	3. Invoke 'zfs destroy ''|-f <dataset>', it should fail.
45#	4. Create clone for fs & vol.
46#	5. Invoke 'zfs destroy -r|-rf <dataset>', it should fail.
47#	6. Write file to filesystem or enter snapshot mountpoint.
48#	7. Invoke 'zfs destroy -R|-rR <dataset>', it should fail.
49#
50
51verify_runnable "both"
52
53log_assert "Seperately verify 'zfs destroy -f|-r|-rf|-R|-rR <dataset>' will " \
54	"fail in different conditions."
55log_onexit cleanup_testenv
56
57#
58# Run 'zfs destroy [-rRf] <dataset>', make sure it fail.
59#
60# $1 the collection of options
61# $2 the collection of datasets
62#
63function negative_test
64{
65	typeset options=$1
66	typeset datasets=$2
67
68	for dtst in $datasets; do
69		if ! is_global_zone; then
70			if [[ $dtst == $VOL || $dtst == $VOLSNAP || \
71				$dtst == $VOLCLONE ]]
72			then
73				log_note "UNSUPPORTED: " \
74					"Volume is unavailable in LZ."
75				continue
76			fi
77		fi
78		for opt in $options; do
79			log_mustnot zfs destroy $opt $dtst
80		done
81	done
82}
83
84#
85# Create snapshots for filesystem and volume,
86# and verify 'zfs destroy' fails without '-r' or '-R'.
87#
88setup_testenv snap
89negative_test "-f" "$CTR $FS $VOL"
90
91#
92# Create clones for filesystem and volume,
93# and verify 'zfs destroy' fails without '-R'.
94#
95setup_testenv clone
96negative_test "-r -rf" "$CTR $FS $VOL"
97
98#
99# Get $FS mountpoint and make it busy, and verify 'zfs destroy $CTR' fails
100# without '-f'. Then verify the remaining datasets are correct. See below for
101# an explanation of what 'correct' means for this test.
102#
103mntpt=$(get_prop mountpoint $FS)
104pidlist=$(mkbusy $mntpt/$TESTFILE0)
105log_note "mkbusy $mntpt/$TESTFILE0 (pidlist: $pidlist)"
106[[ -z $pidlist ]] && log_fail "Failure from mkbusy"
107negative_test "-R -rR" $CTR
108
109#
110# Checking the outcome of the test above is tricky, because the order in
111# which datasets are destroyed is not deterministic. Both $FS and $VOL are
112# busy, and the remaining datasets will be different depending on whether we
113# tried (and failed) to delete $FS or $VOL first.
114
115# The following datasets will exist independent of the order
116check_dataset datasetexists $CTR $FS $VOL
117
118if datasetexists $VOLSNAP && datasetnonexists $FSSNAP; then
119	# The recursive destroy failed on $FS
120	check_dataset datasetnonexists $FSSNAP $FSCLONE
121	check_dataset datasetexists $VOLSNAP $VOLCLONE
122elif datasetexists $FSSNAP && datasetnonexists $VOLSNAP; then
123	# The recursive destroy failed on $VOL
124	check_dataset datasetnonexists $VOLSNAP $VOLCLONE
125	check_dataset datasetexists $FSSNAP $FSCLONE
126else
127	log_must zfs list -rtall
128	log_fail "Unexpected datasets remaining"
129fi
130
131#
132# Create the clones for test environment, and verify 'zfs destroy $FS' fails
133# without '-f'.  Then verify the FS snap and clone are the only datasets
134# that were removed.
135#
136setup_testenv clone
137negative_test "-R -rR" $FS
138check_dataset datasetexists $CTR $FS $VOL $VOLSNAP $VOLCLONE
139check_dataset datasetnonexists $FSSNAP $FSCLONE
140
141log_must kill $pidlist
142log_mustnot pgrep -fl mkbusy
143pidlist=""
144
145#
146# Create the clones for test environment and make the volume busy.
147# Then verify 'zfs destroy $CTR' fails without '-f'.
148#
149# Then verify the expected datasets exist (see below).
150#
151if is_global_zone; then
152	setup_testenv clone
153	pidlist=$(mkbusy $TESTDIR1/$TESTFILE0)
154	log_note "mkbusy $TESTDIR1/$TESTFILE0 (pidlist: $pidlist)"
155	[[ -z $pidlist ]] && log_fail "Failure from mkbusy"
156	negative_test "-R -rR" $CTR
157	check_dataset datasetexists $CTR $VOL
158	check_dataset datasetnonexists $VOLSNAP $VOLCLONE
159
160	# Here again, the non-determinism of destroy order is a factor. $FS,
161	# $FSSNAP and $FSCLONE will still exist here iff we attempted to destroy
162	# $VOL (and failed) first. So check that either all of the datasets are
163	# present, or they're all gone.
164	if datasetexists $FS; then
165		check_dataset datasetexists $FS $FSSNAP $FSCLONE
166	else
167		check_dataset datasetnonexists $FS $FSSNAP $FSCLONE
168	fi
169fi
170
171#
172# Create the clones for test environment and make the volume busy.
173# Then verify 'zfs destroy $VOL' fails without '-f'.
174#
175# Then verify the snapshot and clone are destroyed, but nothing else is.
176#
177if is_global_zone; then
178	setup_testenv clone
179	negative_test "-R -rR" $VOL
180	check_dataset datasetexists $CTR $VOL $FS $FSSNAP $FSCLONE
181	check_dataset datasetnonexists $VOLSNAP $VOLCLONE
182fi
183
184log_must kill $pidlist
185log_mustnot pgrep -fl mkbusy
186pidlist=""
187
188#
189# Create the clones for test environment and make the snapshot busy.
190# Then verify 'zfs destroy $snap' succeeds without '-f'.
191#
192# Then verify the snapshot and clone are destroyed, but nothing else is.
193#
194
195mntpt=$(snapshot_mountpoint $FSSNAP)
196pidlist=$(mkbusy $mntpt)
197log_note "mkbusy $mntpt (pidlist: $pidlist)"
198[[ -z $pidlist ]] && log_fail "Failure from mkbusy"
199
200for option in -R -rR ; do
201	setup_testenv clone
202	log_must zfs destroy $option $FSSNAP
203	check_dataset datasetexists $CTR $FS $VOL
204	check_dataset datasetnonexists $FSSNAP $FSCLONE
205done
206
207log_must kill $pidlist
208log_mustnot pgrep -fl mkbusy
209pidlist=""
210
211log_pass "zfs destroy -f|-r|-rf|-R|-rR <dataset>' failed in different " \
212	"condition passed."
213