1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy is of the CDDL is also available via the Internet
12# at http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2018 Datto Inc.
19#
20
21. $STF_SUITE/include/libtest.shlib
22
23#
24# DESCRIPTION:
25#	zfs unmount should work on nested datasets
26#
27# STRATEGY:
28#	1. Create a set of nested datasets
29#	2. Unmount a nested dataset and make sure it is unmounted
30#	3. Ensure the dataset deeper than the one above is also unmounted
31#	4. Ensure the datasets shallower than the unmounted one is still mounted
32#	5. Repeat from step 2 with other mountpoint values and shallower nesting
33#
34
35verify_runnable "both"
36
37function nesting_cleanup
38{
39	log_must zfs destroy -fR $TESTPOOL/a
40	log_must zfs destroy -fR $TESTPOOL/b
41	log_must zfs destroy -fR $TESTPOOL/c
42	log_must zfs destroy -fR $TESTPOOL/d
43}
44
45log_onexit nesting_cleanup
46
47set -A test_depths 30 16 3
48typeset mountpoint=/$TESTPOOL/mnt
49
50dsA32=$(printf 'a/%.0s' {1..32})"a"
51log_must zfs create -p $TESTPOOL/$dsA32
52
53dsB32=$(printf 'b/%.0s' {1..32})"b"
54log_must zfs create -o mountpoint=none -p $TESTPOOL/$dsB32
55# FreeBSD's mount command ignores the mountpoint property.
56if ! is_freebsd; then
57	log_mustnot mount -t zfs $TESTPOOL/$dsB32 /mnt
58fi
59
60dsC32=$(printf 'c/%.0s' {1..32})"c"
61log_must zfs create -o mountpoint=legacy -p $TESTPOOL/$dsC32
62log_must mount -t zfs $TESTPOOL/$dsC32 /mnt
63
64dsD32=$(printf 'd/%.0s' {1..32})"d"
65log_must zfs create -o mountpoint=$mountpoint -p $TESTPOOL/$dsD32
66
67
68for d in ${test_depths[@]}; do
69	# default mountpoint
70	ds_pre=$(printf 'a/%.0s' {1..$(($d-2))})"a"
71	ds=$(printf 'a/%.0s' {1..$(($d-1))})"a"
72	ds_post=$(printf 'a/%.0s' {1..$(($d))})"a"
73	if ! ismounted $TESTPOOL/$ds_pre; then
74		log_fail "$TESTPOOL/$ds_pre (pre) not initially mounted"
75	fi
76	if ! ismounted $TESTPOOL/$ds; then
77		log_fail "$TESTPOOL/$ds not initially mounted"
78	fi
79	if ! ismounted $TESTPOOL/$ds_post; then
80		log_fail "$TESTPOOL/$ds_post (post) not initially mounted"
81	fi
82
83	log_must zfs snapshot $TESTPOOL/$ds@snap
84	# force snapshot mount in .zfs
85	log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap
86	log_must_nostderr zfs unmount $TESTPOOL/$ds
87
88	if ! ismounted $TESTPOOL/$ds_pre; then
89		log_fail "$ds_pre is not mounted"
90	fi
91	if ismounted $TESTPOOL/$ds; then
92		log_fail "$ds is mounted"
93	fi
94	if ismounted $TESTPOOL/$ds_post; then
95		log_fail "$ds_post (post) is mounted"
96	fi
97
98
99	# mountpoint=none
100	ds_pre=$(printf 'b/%.0s' {1..$(($d-2))})"b"
101	ds=$(printf 'b/%.0s' {1..$(($d-1))})"b"
102	ds_post=$(printf 'b/%.0s' {1..$(($d))})"b"
103	if ! ismounted $TESTPOOL/$ds_pre; then
104		log_fail "$TESTPOOL/$ds_pre (pre) not initially mounted"
105	fi
106	if ! ismounted $TESTPOOL/$ds; then
107		log_fail "$TESTPOOL/$ds not initially mounted"
108	fi
109	if ! ismounted $TESTPOOL/$ds_post; then
110		log_fail "$TESTPOOL/$ds_post (post) not initially mounted"
111	fi
112
113	log_must zfs snapshot $TESTPOOL/$ds@snap
114	# force snapshot mount in .zfs
115	log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap
116	log_must_nostderr zfs unmount $TESTPOOL/$ds
117
118	if ! ismounted $TESTPOOL/$ds_pre; then
119		log_fail "$TESTPOOL/$ds_pre (pre) not mounted"
120	fi
121	if ismounted $TESTPOOL/$ds; then
122		log_fail "$TESTPOOL/$ds is mounted"
123	fi
124	if ismounted $TESTPOOL/$ds_post; then
125		log_fail "$TESTPOOL/$ds_post (post) is mounted"
126	fi
127
128
129	# mountpoint=legacy
130	ds_pre=$(printf 'c/%.0s' {1..$(($d-2))})"c"
131	ds=$(printf 'c/%.0s' {1..$(($d-1))})"c"
132	ds_post=$(printf 'c/%.0s' {1..$(($d))})"c"
133	if ! ismounted $TESTPOOL/$ds_pre; then
134		log_fail "$TESTPOOL/$ds_pre (pre) not initially mounted"
135	fi
136	if ! ismounted $TESTPOOL/$ds; then
137		log_fail "$TESTPOOL/$ds not initially mounted"
138	fi
139	if ! ismounted $TESTPOOL/$ds_post; then
140		log_fail "$TESTPOOL/$ds_post (post) not initially mounted"
141	fi
142
143	log_must zfs snapshot $TESTPOOL/$ds@snap
144	# force snapshot mount in .zfs
145	log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap
146	log_must_nostderr zfs unmount $TESTPOOL/$ds
147
148	if ! ismounted $TESTPOOL/$ds_pre; then
149		log_fail "$TESTPOOL/$ds_pre (pre) not mounted"
150	fi
151	if ismounted $TESTPOOL/$ds; then
152		log_fail "$TESTPOOL/$ds is mounted"
153	fi
154	if ismounted $TESTPOOL/$ds_post; then
155		log_fail "$TESTPOOL/$ds_post (post) is mounted"
156	fi
157
158
159	# mountpoint=/testpool/mnt
160	ds_pre=$(printf 'd/%.0s' {1..$(($d-2))})"d"
161	ds=$(printf 'd/%.0s' {1..$(($d-1))})"d"
162	ds_post=$(printf 'd/%.0s' {1..$(($d))})"d"
163	if ! ismounted $TESTPOOL/$ds_pre; then
164		log_fail "$TESTPOOL/$ds_pre (pre) not initially mounted"
165	fi
166	if ! ismounted $TESTPOOL/$ds; then
167		log_fail "$TESTPOOL/$ds not initially mounted"
168	fi
169	if ! ismounted $TESTPOOL/$ds_post; then
170		log_fail "$TESTPOOL/$ds_post (post) not initially mounted"
171	fi
172
173	log_must zfs snapshot $TESTPOOL/$ds@snap
174	# force snapshot mount in .zfs
175	log_must ls /$TESTPOOL/$ds/.zfs/snapshot/snap
176	log_must_nostderr zfs unmount $TESTPOOL/$ds
177
178	if ! ismounted $TESTPOOL/$ds_pre; then
179		log_fail "$ds_pre is not mounted"
180	fi
181	if ismounted $TESTPOOL/$ds; then
182		log_fail "$ds is mounted"
183	fi
184	if ismounted $TESTPOOL/$ds_post; then
185		log_fail "$ds_post (post) is mounted"
186	fi
187done
188
189log_must rmdir $mountpoint # remove the mountpoint we created
190log_must zpool export $TESTPOOL
191log_must zpool import $TESTPOOL
192
193log_pass "Verified nested dataset are unmounted."
194