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 (c) 2020 by Delphix. All rights reserved.
25#
26
27. $STF_SUITE/include/libtest.shlib
28
29#
30# DESCRIPTION:
31# Verify that 'zfs set sharenfs=on', 'zfs share', and 'zfs unshare' can
32# run concurrently. The test creates 50 filesystem and 50 threads.
33# Each thread will run through the test strategy in parallel.
34#
35# STRATEGY:
36# 1. Verify that the file system is not shared.
37# 2. Enable the 'sharenfs' property
38# 3. Invoke 'zfs unshare' and verify filesystem is no longer shared
39# 4. Invoke 'zfs share'.
40# 4. Verify that the file system is shared.
41# 5. Verify that a shared filesystem cannot be shared again.
42# 6. Verify that share -a succeeds.
43#
44
45verify_runnable "global"
46
47function cleanup
48{
49	wait
50	for fs in {0..50}
51	do
52		for pfs in $TESTFS1 $TESTFS2 $TESTFS3
53		do
54			log_must zfs set sharenfs=off $TESTPOOL/$pfs/$fs
55			unshare_fs $TESTPOOL/$pfs/$fs
56
57			if mounted $TESTPOOL/$pfs/$fs; then
58				log_must zfs unmount $TESTPOOL/$pfs/$fs
59			fi
60
61			datasetexists $TESTPOOL/$pfs/$fs && \
62				destroy_dataset $TESTPOOL/$pfs/$fs -f
63		done
64	done
65
66	log_must zfs share -a
67}
68
69function create_filesystems
70{
71	for fs in {0..50}
72	do
73		log_must zfs create -p $TESTPOOL/$TESTFS1/$fs
74		log_must zfs create -p $TESTPOOL/$TESTFS2/$fs
75		log_must zfs create -p $TESTPOOL/$TESTFS3/$fs
76	done
77}
78
79function sub_fail
80{
81	log_note $$: "$@"
82	exit 1
83}
84
85#
86# Main test routine.
87#
88# Given a file system this routine will attempt
89# share the mountpoint and then verify it has been shared.
90#
91function test_share # filesystem
92{
93	typeset filesystem=$1
94	typeset mntp=$(get_prop mountpoint $filesystem)
95
96	not_shared $mntp || \
97	    sub_fail "File system $filesystem is already shared."
98
99	zfs set sharenfs=on $filesystem || \
100	    sub_fail "zfs set sharenfs=on $filesystem failed."
101	is_shared $mntp || \
102	    sub_fail "File system $filesystem is not shared (set sharenfs)."
103
104	#
105	# Verify 'zfs share' works as well.
106	#
107	zfs unshare $filesystem || \
108	    sub_fail "zfs unshare $filesystem failed."
109	is_shared $mntp && \
110	    sub_fail "File system $filesystem is still shared."
111
112
113	zfs share $filesystem || \
114	    sub_fail "zfs share $filesystem failed."
115	is_shared $mntp || \
116	    sub_fail "file system $filesystem is not shared (zfs share)."
117
118
119	#log_note "Sharing a shared file system fails."
120	zfs share $filesystem && \
121	    sub_fail "zfs share $filesystem did not fail"
122
123	return 0
124}
125
126function unshare_fs_nolog
127{
128	typeset fs=$1
129
130	if is_shared $fs || is_shared_smb $fs; then
131		zfs unshare $fs ||
132		    sub_fail "zfs unshare $fs: $?"
133	fi
134}
135
136#
137# Set the main process id so that we know to capture
138# failures from child processes and allow the parent process
139# to report the failure.
140#
141set_main_pid $$
142log_assert "Verify that 'zfs share' succeeds as root."
143log_onexit cleanup
144
145create_filesystems
146
147child_pids=()
148for fs in {0..50}
149do
150	for pfs in $TESTFS1 $TESTFS2 $TESTFS3
151	do
152		test_share $TESTPOOL/$pfs/$fs &
153		child_pids+=($!)
154		log_note "$TESTPOOL/$pfs/$fs ==> $!"
155	done
156done
157log_must wait_for_children "${child_pids[@]}"
158
159log_note "Verify 'zfs share -a' succeeds."
160
161#
162# Unshare each of the file systems.
163#
164child_pids=()
165for fs in {0..50}
166do
167	for pfs in $TESTFS1 $TESTFS2 $TESTFS3
168	do
169		unshare_fs_nolog $TESTPOOL/$pfs/$fs &
170		child_pids+=($!)
171		log_note "$TESTPOOL/$pfs/$fs (unshare) ==> $!"
172	done
173done
174log_must wait_for_children "${child_pids[@]}"
175
176#
177# Try a zfs share -a and verify all file systems are shared.
178#
179log_must zfs share -a
180
181#
182# We need to unset __ZFS_POOL_EXCLUDE so that we include all file systems
183# in the os-specific zfs exports file. This will be reset by the next test.
184#
185unset __ZFS_POOL_EXCLUDE
186
187for fs in {0..50}
188do
189	for pfs in $TESTFS1 $TESTFS2 $TESTFS3
190	do
191		log_must is_shared $TESTPOOL/$pfs/$fs
192		log_must is_exported $TESTPOOL/$pfs/$fs
193	done
194done
195
196log_pass "'zfs share [-a] <filesystem>' succeeds as root."
197