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 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
25#
26
27. $STF_SUITE/include/libtest.shlib
28. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
29. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
30. $STF_SUITE/tests/functional/zvol/zvol_misc/zvol_misc_common.kshlib
31
32#
33# DESCRIPTION:
34# Verify that ZFS volume property "volmode" works as intended.
35#
36# STRATEGY:
37# 1. Verify "volmode" property does not accept invalid values
38# 2. Verify "volmode=none" hides ZVOL device nodes
39# 3. Verify "volmode=full" exposes a fully functional device
40# 4. Verify "volmode=dev" hides partition info on the device
41# 5. Verify "volmode=default" behaves accordingly to "volmode" module parameter
42# 6. Verify "volmode" property is inherited correctly
43# 7. Verify "volmode" behaves correctly at import time
44# 8. Verify "volmode" behaves accordingly to zvol_inhibit_dev (Linux only)
45#
46
47verify_runnable "global"
48
49function cleanup
50{
51	datasetexists $VOLFS && destroy_dataset $VOLFS -r
52	datasetexists $ZVOL && destroy_dataset $ZVOL -r
53	zfs inherit volmode $TESTPOOL
54	sysctl_inhibit_dev 0
55	sysctl_volmode 1
56	is_linux && udev_cleanup
57}
58
59#
60# Set zvol_inhibit_dev tunable to $value
61#
62function sysctl_inhibit_dev # value
63{
64	typeset value="$1"
65
66	if is_linux; then
67		log_note "Setting zvol_inhibit_dev tunable to $value"
68		log_must set_tunable32 VOL_INHIBIT_DEV $value
69	fi
70}
71
72#
73# Set volmode tunable to $value
74#
75function sysctl_volmode # value
76{
77	typeset value="$1"
78
79	log_note "Setting volmode tunable to $value"
80	log_must set_tunable32 VOL_MODE $value
81}
82
83#
84# Exercise open and close, read and write operations
85#
86function test_io # dev
87{
88	typeset dev=$1
89
90	log_must dd if=$dev of=/dev/null count=1
91	log_must dd if=/dev/zero of=$dev count=1
92}
93
94#
95# Changing volmode may need to remove minors, which could be open, so call
96# udev_wait() before we "zfs set volmode=<value>".  This ensures no udev
97# process has the zvol open (i.e. blkid) and the zvol_remove_minor_impl()
98# function won't skip removing the in use device.
99#
100function set_volmode # value ds
101{
102	typeset value="$1"
103	typeset ds="$2"
104
105	is_linux && udev_wait
106	log_must zfs set volmode="$value" "$ds"
107}
108
109log_assert "Verify that ZFS volume property 'volmode' works as intended"
110log_onexit cleanup
111
112VOLFS="$TESTPOOL/volfs"
113ZVOL="$TESTPOOL/vol"
114ZDEV="$ZVOL_DEVDIR/$ZVOL"
115SUBZVOL="$VOLFS/subvol"
116SUBZDEV="$ZVOL_DEVDIR/$SUBZVOL"
117
118# 0. Verify basic ZVOL functionality
119log_must zfs create -o mountpoint=none $VOLFS
120log_must zfs create -V $VOLSIZE -s $SUBZVOL
121log_must zfs create -V $VOLSIZE -s $ZVOL
122blockdev_exists $ZDEV
123blockdev_exists $SUBZDEV
124test_io $ZDEV
125test_io $SUBZDEV
126
127# 1. Verify "volmode" property does not accept invalid values
128typeset badvals=("off" "on" "1" "nope" "-")
129for badval in ${badvals[@]}
130do
131	log_mustnot zfs set volmode="$badval" $ZVOL
132done
133
134# 2. Verify "volmode=none" hides ZVOL device nodes
135set_volmode none $ZVOL
136blockdev_missing $ZDEV
137log_must_busy zfs destroy $ZVOL
138blockdev_missing $ZDEV
139
140# 3. Verify "volmode=full" exposes a fully functional device
141log_must zfs create -V $VOLSIZE -s $ZVOL
142blockdev_exists $ZDEV
143set_volmode full $ZVOL
144blockdev_exists $ZDEV
145test_io $ZDEV
146log_must verify_partition $ZDEV
147# 3.1 Verify "volmode=geom" is an alias for "volmode=full"
148set_volmode geom $ZVOL
149blockdev_exists $ZDEV
150if [[ "$(get_prop 'volmode' $ZVOL)" != "full" ]]; then
151	log_fail " Volmode value 'geom' is not an alias for 'full'"
152fi
153log_must_busy zfs destroy $ZVOL
154blockdev_missing $ZDEV
155
156# 4. Verify "volmode=dev" hides partition info on the device
157log_must zfs create -V $VOLSIZE -s $ZVOL
158blockdev_exists $ZDEV
159set_volmode dev $ZVOL
160blockdev_exists $ZDEV
161test_io $ZDEV
162log_mustnot verify_partition $ZDEV
163log_must_busy zfs destroy $ZVOL
164blockdev_missing $ZDEV
165
166# 5. Verify "volmode=default" behaves accordingly to "volmode" module parameter
167# 5.1 Verify sysctl "volmode=full"
168sysctl_volmode 1
169log_must zfs create -V $VOLSIZE -s $ZVOL
170blockdev_exists $ZDEV
171set_volmode default $ZVOL
172blockdev_exists $ZDEV
173log_must verify_partition $ZDEV
174log_must_busy zfs destroy $ZVOL
175blockdev_missing $ZDEV
176# 5.2 Verify sysctl "volmode=dev"
177sysctl_volmode 2
178log_must zfs create -V $VOLSIZE -s $ZVOL
179blockdev_exists $ZDEV
180set_volmode default $ZVOL
181blockdev_exists $ZDEV
182log_mustnot verify_partition $ZDEV
183log_must_busy zfs destroy $ZVOL
184blockdev_missing $ZDEV
185# 5.2 Verify sysctl "volmode=none"
186sysctl_volmode 3
187log_must zfs create -V $VOLSIZE -s $ZVOL
188blockdev_missing $ZDEV
189set_volmode default $ZVOL
190blockdev_missing $ZDEV
191
192# 6. Verify "volmode" property is inherited correctly
193log_must zfs inherit volmode $ZVOL
194blockdev_missing $ZDEV
195# 6.1 Check volmode=full case
196set_volmode full $TESTPOOL
197verify_inherited 'volmode' 'full' $ZVOL $TESTPOOL
198blockdev_exists $ZDEV
199# 6.2 Check volmode=none case
200set_volmode none $TESTPOOL
201verify_inherited 'volmode' 'none' $ZVOL $TESTPOOL
202blockdev_missing $ZDEV
203# 6.3 Check volmode=dev case
204set_volmode dev $TESTPOOL
205verify_inherited 'volmode' 'dev' $ZVOL $TESTPOOL
206blockdev_exists $ZDEV
207# 6.4 Check volmode=default case
208sysctl_volmode 1
209set_volmode default $TESTPOOL
210verify_inherited 'volmode' 'default' $ZVOL $TESTPOOL
211blockdev_exists $ZDEV
212# 6.5 Check inheritance on multiple levels
213log_must zfs inherit volmode $SUBZVOL
214set_volmode none $VOLFS
215set_volmode full $TESTPOOL
216verify_inherited 'volmode' 'none' $SUBZVOL $VOLFS
217blockdev_missing $SUBZDEV
218blockdev_exists $ZDEV
219
220# 7. Verify "volmode" behaves correctly at import time
221log_must zpool export $TESTPOOL
222blockdev_missing $ZDEV
223blockdev_missing $SUBZDEV
224log_must zpool import $TESTPOOL
225blockdev_exists $ZDEV
226blockdev_missing $SUBZDEV
227log_must_busy zfs destroy $ZVOL
228log_must_busy zfs destroy $SUBZVOL
229blockdev_missing $ZDEV
230blockdev_missing $SUBZDEV
231
232# 8. Verify "volmode" behaves accordingly to zvol_inhibit_dev (Linux only)
233if is_linux; then
234	sysctl_inhibit_dev 1
235	# 7.1 Verify device nodes not are not created with "volmode=full"
236	sysctl_volmode 1
237	log_must zfs create -V $VOLSIZE -s $ZVOL
238	blockdev_missing $ZDEV
239	set_volmode full $ZVOL
240	blockdev_missing $ZDEV
241	log_must_busy zfs destroy $ZVOL
242	blockdev_missing $ZDEV
243	# 7.1 Verify device nodes not are not created with "volmode=dev"
244	sysctl_volmode 2
245	log_must zfs create -V $VOLSIZE -s $ZVOL
246	blockdev_missing $ZDEV
247	set_volmode dev $ZVOL
248	blockdev_missing $ZDEV
249	log_must_busy zfs destroy $ZVOL
250	blockdev_missing $ZDEV
251	# 7.1 Verify device nodes not are not created with "volmode=none"
252	sysctl_volmode 3
253	log_must zfs create -V $VOLSIZE -s $ZVOL
254	blockdev_missing $ZDEV
255	set_volmode none $ZVOL
256	blockdev_missing $ZDEV
257fi
258
259log_pass "Verify that ZFS volume property 'volmode' works as intended"
260