xref: /freebsd/usr.sbin/zonectl/tests/zonectl_test.sh (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2026 voidanix <voidanix@FreeBSD.org>
4#
5
6MD_DEV_FILE="md.dev"
7
8alloc_zoned_md()
9{
10	atf_check truncate -s 1025m backing_file
11	md=$(mdconfig -a -t vnode -f backing_file) || \
12	    atf_fail "mdconfig -a failed"
13	echo ${md} > $MD_DEV_FILE
14}
15
16# Print the number of zones matching a report option.
17zone_count()
18{
19	zonectl -d /dev/${md}.zoned -c rz -o $1 -P summary | \
20	    awk '/zones,/ {print $1}'
21}
22
23zoned_md_cleanup()
24{
25	if [ -f "$MD_DEV_FILE" ]; then
26		read md < $MD_DEV_FILE
27		[ -c /dev/${md}.zoned ] && \
28		    gzoned destroy ${md}.zoned 2>/dev/null
29		mdconfig -d -u ${md} 2>/dev/null
30	fi
31	true
32}
33
34atf_test_case report_filter cleanup
35report_filter_head()
36{
37	atf_set "descr" "zonectl -o only reports zones matching the filter"
38	atf_set "require.user" "root"
39	atf_set "require.kmods" "g_md g_zoned"
40}
41report_filter_body()
42{
43	alloc_zoned_md
44	atf_check gzoned create -s 256m -c 0-1 ${md}
45
46	atf_check_equal "2" \
47	    "$(zonectl -d /dev/${md}.zoned -c rz -o nonwp -P summary | \
48	    awk '/zones,/ {print $1}')"
49	atf_check_equal "2" \
50	    "$(zonectl -d /dev/${md}.zoned -c rz -o empty -P summary | \
51	    awk '/zones,/ {print $1}')"
52	atf_check_equal "0" \
53	    "$(zonectl -d /dev/${md}.zoned -c rz -o full -P summary | \
54	    awk '/zones,/ {print $1}')"
55}
56report_filter_cleanup()
57{
58	zoned_md_cleanup
59}
60
61atf_test_case report_zones cleanup
62report_zones_head()
63{
64	atf_set "descr" "zonectl -c rz reports every zone"
65	atf_set "require.user" "root"
66	atf_set "require.kmods" "g_md g_zoned"
67}
68report_zones_body()
69{
70	alloc_zoned_md
71	atf_check gzoned create -s 256m ${md}
72	atf_check -o match:"^4 zones," \
73	    zonectl -d /dev/${md}.zoned -c rz -P summary
74	atf_check_equal "4" \
75	    "$(zonectl -d /dev/${md}.zoned -c rz -P script | \
76	    awk 'END {print NR}')"
77}
78report_zones_cleanup()
79{
80	zoned_md_cleanup
81}
82
83atf_test_case report_starting_lba cleanup
84report_starting_lba_head()
85{
86	atf_set "descr" "zonectl -c rz -l reports zones from a starting LBA"
87	atf_set "require.user" "root"
88	atf_set "require.kmods" "g_md g_zoned"
89}
90report_starting_lba_body()
91{
92	alloc_zoned_md
93	atf_check gzoned create -s 256m ${md}
94	# Only zones 2 and 3 lie at or past LBA 0x100000 (512m).
95	atf_check_equal "2" \
96	    "$(zonectl -d /dev/${md}.zoned -c rz -l 0x100000 -P summary | \
97	    awk '/zones,/ {print $1}')"
98	atf_check_equal "0x100000" \
99	    "$(zonectl -d /dev/${md}.zoned -c rz -l 0x100000 -P script | \
100	    awk -F',' 'NR == 1 {gsub(/ /, "", $1); print $1}')"
101}
102report_starting_lba_cleanup()
103{
104	zoned_md_cleanup
105}
106
107atf_test_case report_params cleanup
108report_params_head()
109{
110	atf_set "descr" "zonectl -c params reports the device parameters"
111	atf_set "require.user" "root"
112	atf_set "require.kmods" "g_md g_zoned"
113}
114report_params_body()
115{
116	alloc_zoned_md
117	atf_check gzoned create -s 256m -m 3 ${md}
118	atf_check -o match:"Zone Mode: Host Managed" \
119	    -o match:"URSWRZ.*: Yes" \
120	    -o match:"Open Sequential Write Required Zones: 3" \
121	    zonectl -d /dev/${md}.zoned -c params
122}
123report_params_cleanup()
124{
125	zoned_md_cleanup
126}
127
128atf_test_case open_zone cleanup
129open_zone_head()
130{
131	atf_set "descr" "zonectl -c open explicitly opens a zone"
132	atf_set "require.user" "root"
133	atf_set "require.kmods" "g_md g_zoned"
134}
135open_zone_body()
136{
137	alloc_zoned_md
138	atf_check gzoned create -s 256m ${md}
139	atf_check zonectl -d /dev/${md}.zoned -c open -l 0
140	atf_check_equal "1" "$(zone_count exp_open)"
141}
142open_zone_cleanup()
143{
144	zoned_md_cleanup
145}
146
147atf_test_case close_zone cleanup
148close_zone_head()
149{
150	atf_set "descr" "zonectl -c close closes an open zone"
151	atf_set "require.user" "root"
152	atf_set "require.kmods" "g_md g_zoned"
153}
154close_zone_body()
155{
156	alloc_zoned_md
157	atf_check gzoned create -s 256m ${md}
158	atf_check -e ignore dd if=/dev/zero of=/dev/${md}.zoned bs=1m count=1
159	atf_check_equal "1" "$(zone_count imp_open)"
160	atf_check zonectl -d /dev/${md}.zoned -c close -l 0
161	atf_check_equal "1" "$(zone_count closed)"
162	atf_check_equal "0" "$(zone_count imp_open)"
163}
164close_zone_cleanup()
165{
166	zoned_md_cleanup
167}
168
169atf_test_case finish_zone cleanup
170finish_zone_head()
171{
172	atf_set "descr" "zonectl -c finish transitions a zone to full"
173	atf_set "require.user" "root"
174	atf_set "require.kmods" "g_md g_zoned"
175}
176finish_zone_body()
177{
178	alloc_zoned_md
179	atf_check gzoned create -s 256m ${md}
180	atf_check -e ignore dd if=/dev/zero of=/dev/${md}.zoned bs=1m count=1
181	atf_check zonectl -d /dev/${md}.zoned -c finish -l 0
182	atf_check_equal "1" "$(zone_count full)"
183}
184finish_zone_cleanup()
185{
186	zoned_md_cleanup
187}
188
189atf_test_case zone_state_handling cleanup
190zone_state_handling_head()
191{
192	atf_set "descr" \
193	    "zone commands follow ZBC spec outside their transition states"
194	atf_set "require.user" "root"
195	atf_set "require.kmods" "g_md g_zoned"
196}
197zone_state_handling_body()
198{
199	alloc_zoned_md
200	atf_check gzoned create -s 256m -c 0 ${md}
201
202	# Explicitly targeting a conventional zone is the caller's error.
203	atf_check -s not-exit:0 -e ignore \
204	    zonectl -d /dev/${md}.zoned -c finish -l 0
205	# Closing an empty zone is a no-op.
206	atf_check zonectl -d /dev/${md}.zoned -c close -l 0x80000
207	atf_check_equal "3" "$(zone_count empty)"
208	# So is opening a full zone: it must stay full.
209	atf_check zonectl -d /dev/${md}.zoned -c finish -l 0x100000
210	atf_check zonectl -d /dev/${md}.zoned -c open -l 0x100000
211	atf_check_equal "1" "$(zone_count full)"
212	atf_check_equal "0" "$(zone_count exp_open)"
213}
214zone_state_handling_cleanup()
215{
216	zoned_md_cleanup
217}
218
219atf_init_test_cases()
220{
221	atf_add_test_case report_filter
222	atf_add_test_case report_zones
223	atf_add_test_case report_starting_lba
224	atf_add_test_case report_params
225	atf_add_test_case open_zone
226	atf_add_test_case close_zone
227	atf_add_test_case finish_zone
228	atf_add_test_case zone_state_handling
229}
230