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