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} 40report_filter_body() 41{ 42 alloc_zoned_md 43 atf_check gzoned create -s 256m -c 0-1 ${md} 44 45 atf_check_equal "2" \ 46 "$(zonectl -d /dev/${md}.zoned -c rz -o nonwp -P summary | \ 47 awk '/zones,/ {print $1}')" 48 atf_check_equal "2" \ 49 "$(zonectl -d /dev/${md}.zoned -c rz -o empty -P summary | \ 50 awk '/zones,/ {print $1}')" 51 atf_check_equal "0" \ 52 "$(zonectl -d /dev/${md}.zoned -c rz -o full -P summary | \ 53 awk '/zones,/ {print $1}')" 54} 55report_filter_cleanup() 56{ 57 zoned_md_cleanup 58} 59 60atf_test_case report_zones cleanup 61report_zones_head() 62{ 63 atf_set "descr" "zonectl -c rz reports every zone" 64 atf_set "require.user" "root" 65} 66report_zones_body() 67{ 68 alloc_zoned_md 69 atf_check gzoned create -s 256m ${md} 70 atf_check -o match:"^4 zones," \ 71 zonectl -d /dev/${md}.zoned -c rz -P summary 72 atf_check_equal "4" \ 73 "$(zonectl -d /dev/${md}.zoned -c rz -P script | \ 74 awk 'END {print NR}')" 75} 76report_zones_cleanup() 77{ 78 zoned_md_cleanup 79} 80 81atf_test_case report_starting_lba cleanup 82report_starting_lba_head() 83{ 84 atf_set "descr" "zonectl -c rz -l reports zones from a starting LBA" 85 atf_set "require.user" "root" 86} 87report_starting_lba_body() 88{ 89 alloc_zoned_md 90 atf_check gzoned create -s 256m ${md} 91 # Only zones 2 and 3 lie at or past LBA 0x100000 (512m). 92 atf_check_equal "2" \ 93 "$(zonectl -d /dev/${md}.zoned -c rz -l 0x100000 -P summary | \ 94 awk '/zones,/ {print $1}')" 95 atf_check_equal "0x100000" \ 96 "$(zonectl -d /dev/${md}.zoned -c rz -l 0x100000 -P script | \ 97 awk -F',' 'NR == 1 {gsub(/ /, "", $1); print $1}')" 98} 99report_starting_lba_cleanup() 100{ 101 zoned_md_cleanup 102} 103 104atf_test_case report_params cleanup 105report_params_head() 106{ 107 atf_set "descr" "zonectl -c params reports the device parameters" 108 atf_set "require.user" "root" 109} 110report_params_body() 111{ 112 alloc_zoned_md 113 atf_check gzoned create -s 256m -m 3 ${md} 114 atf_check -o match:"Zone Mode: Host Managed" \ 115 -o match:"URSWRZ.*: Yes" \ 116 -o match:"Open Sequential Write Required Zones: 3" \ 117 zonectl -d /dev/${md}.zoned -c params 118} 119report_params_cleanup() 120{ 121 zoned_md_cleanup 122} 123 124atf_test_case open_zone cleanup 125open_zone_head() 126{ 127 atf_set "descr" "zonectl -c open explicitly opens a zone" 128 atf_set "require.user" "root" 129} 130open_zone_body() 131{ 132 alloc_zoned_md 133 atf_check gzoned create -s 256m ${md} 134 atf_check zonectl -d /dev/${md}.zoned -c open -l 0 135 atf_check_equal "1" "$(zone_count exp_open)" 136} 137open_zone_cleanup() 138{ 139 zoned_md_cleanup 140} 141 142atf_test_case close_zone cleanup 143close_zone_head() 144{ 145 atf_set "descr" "zonectl -c close closes an open zone" 146 atf_set "require.user" "root" 147} 148close_zone_body() 149{ 150 alloc_zoned_md 151 atf_check gzoned create -s 256m ${md} 152 atf_check -e ignore dd if=/dev/zero of=/dev/${md}.zoned bs=1m count=1 153 atf_check_equal "1" "$(zone_count imp_open)" 154 atf_check zonectl -d /dev/${md}.zoned -c close -l 0 155 atf_check_equal "1" "$(zone_count closed)" 156 atf_check_equal "0" "$(zone_count imp_open)" 157} 158close_zone_cleanup() 159{ 160 zoned_md_cleanup 161} 162 163atf_test_case finish_zone cleanup 164finish_zone_head() 165{ 166 atf_set "descr" "zonectl -c finish transitions a zone to full" 167 atf_set "require.user" "root" 168} 169finish_zone_body() 170{ 171 alloc_zoned_md 172 atf_check gzoned create -s 256m ${md} 173 atf_check -e ignore dd if=/dev/zero of=/dev/${md}.zoned bs=1m count=1 174 atf_check zonectl -d /dev/${md}.zoned -c finish -l 0 175 atf_check_equal "1" "$(zone_count full)" 176} 177finish_zone_cleanup() 178{ 179 zoned_md_cleanup 180} 181 182atf_test_case zone_state_handling cleanup 183zone_state_handling_head() 184{ 185 atf_set "descr" \ 186 "zone commands follow ZBC spec outside their transition states" 187 atf_set "require.user" "root" 188} 189zone_state_handling_body() 190{ 191 alloc_zoned_md 192 atf_check gzoned create -s 256m -c 0 ${md} 193 194 # Explicitly targeting a conventional zone is the caller's error. 195 atf_check -s not-exit:0 -e ignore \ 196 zonectl -d /dev/${md}.zoned -c finish -l 0 197 # Closing an empty zone is a no-op. 198 atf_check zonectl -d /dev/${md}.zoned -c close -l 0x80000 199 atf_check_equal "3" "$(zone_count empty)" 200 # So is opening a full zone: it must stay full. 201 atf_check zonectl -d /dev/${md}.zoned -c finish -l 0x100000 202 atf_check zonectl -d /dev/${md}.zoned -c open -l 0x100000 203 atf_check_equal "1" "$(zone_count full)" 204 atf_check_equal "0" "$(zone_count exp_open)" 205} 206zone_state_handling_cleanup() 207{ 208 zoned_md_cleanup 209} 210 211atf_init_test_cases() 212{ 213 atf_add_test_case report_filter 214 atf_add_test_case report_zones 215 atf_add_test_case report_starting_lba 216 atf_add_test_case report_params 217 atf_add_test_case open_zone 218 atf_add_test_case close_zone 219 atf_add_test_case finish_zone 220 atf_add_test_case zone_state_handling 221} 222