xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_006_pos.ksh (revision 80aae8a3f8aa70712930664572be9e6885dc0be7)
1#!/bin/ksh -p
2# SPDX-License-Identifier: CDDL-1.0
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or https://opensource.org/licenses/CDDL-1.0.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2026 Klara, Inc.
26#
27
28. $STF_SUITE/include/libtest.shlib
29
30verify_runnable "global"
31
32#
33# DESCRIPTION:
34#
35# Several zpool properties exist to expose metaslab allocation class space
36# accounting.
37#
38# STRATEGY:
39# 1. Create a pool with raidz (to validate expansion and deflation metrics).
40# 2. For each allocation class:
41#    - Add any required vdevs for this allocation class.
42#    - Prepare a dataset configured to utilize this allocation class.
43#    - Validate metrics reported by pool properties for allocation classes.
44# 3. For the whole pool, confirm that AVAIL, USABLE and USED report reasonable
45#    values.
46#
47
48bs=128K
49count=100
50
51function writefile
52{
53	dd if=/dev/urandom of=$1 bs=$bs count=$count 2>/dev/null
54}
55
56nfiles=5
57
58function writefiles # datadir [nfiles]
59{
60	typeset datadir=$1
61	typeset -i n=${2:-$nfiles}
62
63	for i in {1..$n}; do
64		log_must writefile $TESTDIR/$datadir/file$i
65	done
66}
67
68pool=$TESTPOOL1
69
70function get_class_prop
71{
72	get_pool_prop "class_${1}_${2}" $pool
73}
74
75# Wrapper for test to give more context to logs
76function check
77{
78	shift 2 # class prop (test args)
79	test "$@"
80}
81
82function check_raidz_used # [mincap=1]
83{
84	typeset -i mincap=${1:-1}
85
86	log_must check $class size $size -gt 0
87	log_must check $class capacity $cap -ge $mincap -a $cap -le 100
88	log_must check $class free $free -gt 0 -a $free -lt $size
89	log_must check $class allocated $alloc -gt 0 -a $alloc -lt $size
90	log_must check $class available $avail -gt 0 -a $avail -lt $free
91	log_must check $class usable $usable -gt 0 -a $usable -lt $size
92	log_must check $class used $used -gt 0 -a $used -lt $alloc
93	log_must check $class expandsize $expandsz = "-"
94	log_must check $class fragmentation $frag -lt 50
95}
96
97function check_raidz_unused
98{
99	log_must check $class size $size -gt 0
100	log_must check $class capacity $cap -eq 0
101	log_must check $class free $free -eq $size
102	log_must check $class allocated $alloc -eq 0
103	log_must check $class available $avail -gt 0 -a $avail -lt $free
104	log_must check $class usable $usable -gt 0 -a $usable -lt $size
105	log_must check $class used $used -eq 0
106	log_must check $class expandsize $expandsz = "-"
107	log_must check $class fragmentation $frag -eq 0
108}
109
110function check_nonraidz_used # [mincap=1]
111{
112	typeset -i mincap=${1:-1}
113
114	log_must check $class size $size -gt 0
115	log_must check $class capacity $cap -ge $mincap -a $cap -le 100
116	log_must check $class free $free -gt 0 -a $free -lt $size
117	log_must check $class allocated $alloc -gt 0 -a $alloc -lt $size
118	log_must check $class available $avail -eq $free
119	log_must check $class usable $usable -eq $size
120	log_must check $class used $used -eq $alloc
121	log_must check $class expandsize $expandsz = "-"
122	log_must check $class fragmentation $frag -lt 50
123}
124
125function check_nonraidz_unused
126{
127	log_must check $class size $size -gt 0
128	log_must check $class capacity $cap -eq 0
129	log_must check $class free $free -eq $size
130	log_must check $class allocated $alloc -eq 0
131	log_must check $class available $avail -eq $free
132	log_must check $class usable $usable -eq $size
133	log_must check $class used $used -eq $alloc
134	log_must check $class expandsize $expandsz = "-"
135	log_must check $class fragmentation $frag -eq 0
136}
137
138# Log capacity tends to be >0% but <1% in these tests, so gets reported as 0.
139# Let that slide and rely on allocated/free checks for sanity, rather than
140# trying to tweak txg sync parameters to widen the race window.
141
142function check_raidz_log_used
143{
144	check_raidz_used 0
145}
146
147function check_nonraidz_log_used
148{
149	check_nonraidz_used 0
150}
151
152function check_unavailable
153{
154	log_must check $class size $size -eq 0
155	log_must check $class capacity $cap -eq 0
156	log_must check $class free $free -eq 0
157	log_must check $class allocated $alloc -eq 0
158	log_must check $class available $avail -eq 0
159	log_must check $class usable $usable -eq 0
160	log_must check $class used $used -eq 0
161	log_must check $class expandsize $expandsz = "-"
162	log_must check $class fragmentation $frag = "-"
163}
164
165typeset -a classes=("normal" "special" "dedup" "log" "elog" "special_elog")
166
167normal_vdevs=$(seq -f $TEST_BASE_DIR/normal-vdev-%g 3)
168normal_vdev_size=$((1 << 30)) # 1 GiB
169
170special_vdevs=$(seq -f $TEST_BASE_DIR/special-vdev-%g 3)
171special_vdev_size=$((512 << 20)) # 512 MiB
172
173# Use a mirror for dedup to test expandsize.
174dedup_vdevs=$(seq -f $TEST_BASE_DIR/dedup-vdev-%g 2)
175dedup_vdev_size=$((256 << 20)) # 256 MiB
176
177# The log class can't be raided or expanded, so we only need one vdev.
178log_vdev="$TEST_BASE_DIR/log-vdev"
179log_vdev_size=$((128 << 20)) # 128 MiB
180
181embedded_slog_min_ms=$(get_tunable EMBEDDED_SLOG_MIN_MS)
182
183function cleanup
184{
185	zpool destroy -f $pool
186	rm -f $normal_vdevs $normal_expand_vdev
187	rm -f $special_vdevs $special_expand_vdev
188	rm -f $dedup_vdevs $dedup_expand_vdev
189	rm -f $log_vdev
190	set_tunable32 EMBEDDED_SLOG_MIN_MS $embedded_slog_min_ms
191}
192log_onexit cleanup
193
194log_assert "zpool allocation class properties report metrics correctly"
195
196# Lower the threshold for provisioning embedded log metaslabs on small vdevs.
197log_must set_tunable32 EMBEDDED_SLOG_MIN_MS 8
198
199log_must truncate -s $normal_vdev_size $normal_vdevs
200log_must zpool create $pool \
201    raidz $normal_vdevs
202log_must zfs set mountpoint=$TESTDIR $pool
203
204log_note "Normal Class"
205log_must zfs create \
206    $pool/normal
207writefiles normal
208sync_pool $pool
209for class in "${classes[@]}"; do
210	typeset -il size=$(get_class_prop $class size)
211	typeset -i cap=$(get_class_prop $class capacity)
212	typeset -il free=$(get_class_prop $class free)
213	typeset -il alloc=$(get_class_prop $class allocated)
214	typeset -il avail=$(get_class_prop $class available)
215	typeset -il usable=$(get_class_prop $class usable)
216	typeset -il used=$(get_class_prop $class used)
217	typeset expandsz=$(get_class_prop $class expandsize)
218	typeset frag=$(get_class_prop $class fragmentation)
219	case $class in
220	normal)
221		check_raidz_used
222		;;
223	elog)
224		check_raidz_unused
225		;;
226	*)
227		check_unavailable
228		;;
229	esac
230done
231
232log_note "Embedded Log Class"
233log_must zfs create \
234    -o sync=always \
235    $pool/elog
236writefiles elog
237for class in "${classes[@]}"; do
238	typeset -il size=$(get_class_prop $class size)
239	typeset -i cap=$(get_class_prop $class capacity)
240	typeset -il free=$(get_class_prop $class free)
241	typeset -il alloc=$(get_class_prop $class allocated)
242	typeset -il avail=$(get_class_prop $class available)
243	typeset -il usable=$(get_class_prop $class usable)
244	typeset -il used=$(get_class_prop $class used)
245	typeset expandsz=$(get_class_prop $class expandsize)
246	typeset frag=$(get_class_prop $class fragmentation)
247	case $class in
248	normal)
249		check_raidz_used
250		;;
251	elog)
252		check_raidz_log_used
253		;;
254	*)
255		check_unavailable
256		;;
257	esac
258done
259
260log_note "Special Class"
261log_must truncate -s $special_vdev_size $special_vdevs
262log_must zpool add $pool \
263    special raidz $special_vdevs
264log_must zfs create \
265    -o recordsize=32K -o special_small_blocks=32K \
266    $pool/special
267writefiles special
268sync_pool $pool
269for class in "${classes[@]}"; do
270	typeset -il size=$(get_class_prop $class size)
271	typeset -i cap=$(get_class_prop $class capacity)
272	typeset -il free=$(get_class_prop $class free)
273	typeset -il alloc=$(get_class_prop $class allocated)
274	typeset -il avail=$(get_class_prop $class available)
275	typeset -il usable=$(get_class_prop $class usable)
276	typeset -il used=$(get_class_prop $class used)
277	typeset expandsz=$(get_class_prop $class expandsize)
278	typeset frag=$(get_class_prop $class fragmentation)
279	case $class in
280	normal|special)
281		check_raidz_used
282		;;
283	elog)
284		check_raidz_log_used
285		;;
286	special_elog)
287		check_raidz_unused
288		;;
289	*)
290		check_unavailable
291		;;
292	esac
293done
294
295log_note "Special Embedded Log Class"
296log_must zfs create \
297    -o recordsize=32K -o special_small_blocks=32K \
298    -o sync=always \
299    $pool/special_elog
300writefiles special_elog
301for class in "${classes[@]}"; do
302	typeset -il size=$(get_class_prop $class size)
303	typeset -i cap=$(get_class_prop $class capacity)
304	typeset -il free=$(get_class_prop $class free)
305	typeset -il alloc=$(get_class_prop $class allocated)
306	typeset -il avail=$(get_class_prop $class available)
307	typeset -il usable=$(get_class_prop $class usable)
308	typeset -il used=$(get_class_prop $class used)
309	typeset expandsz=$(get_class_prop $class expandsize)
310	typeset frag=$(get_class_prop $class fragmentation)
311	case $class in
312	normal|special)
313		check_raidz_used
314		;;
315	elog|special_elog)
316		check_raidz_log_used
317		;;
318	*)
319		check_unavailable
320		;;
321	esac
322done
323
324log_note "Log Class"
325log_must truncate -s $log_vdev_size $log_vdev
326log_must zpool add $pool \
327    log $log_vdev
328log_must zfs create \
329    -o sync=always \
330    $pool/log
331writefiles log
332for class in "${classes[@]}"; do
333	typeset -il size=$(get_class_prop $class size)
334	typeset -i cap=$(get_class_prop $class capacity)
335	typeset -il free=$(get_class_prop $class free)
336	typeset -il alloc=$(get_class_prop $class allocated)
337	typeset -il avail=$(get_class_prop $class available)
338	typeset -il usable=$(get_class_prop $class usable)
339	typeset -il used=$(get_class_prop $class used)
340	typeset expandsz=$(get_class_prop $class expandsize)
341	typeset frag=$(get_class_prop $class fragmentation)
342	case $class in
343	normal|special)
344		check_raidz_used
345		;;
346	elog|special_elog)
347		check_raidz_log_used
348		;;
349	log)
350		check_nonraidz_log_used
351		;;
352	*)
353		check_unavailable
354		;;
355	esac
356done
357
358log_note "Dedup Class"
359log_must truncate -s $dedup_vdev_size $dedup_vdevs
360log_must zpool add $pool \
361    dedup mirror $dedup_vdevs
362log_must zfs create \
363    -o dedup=on -o recordsize=4k \
364    $pool/dedup
365writefiles dedup $((3 * nfiles))
366sync_pool $pool
367for class in "${classes[@]}"; do
368	typeset -il size=$(get_class_prop $class size)
369	typeset -i cap=$(get_class_prop $class capacity)
370	typeset -il free=$(get_class_prop $class free)
371	typeset -il alloc=$(get_class_prop $class allocated)
372	typeset -il avail=$(get_class_prop $class available)
373	typeset -il usable=$(get_class_prop $class usable)
374	typeset -il used=$(get_class_prop $class used)
375	typeset expandsz=$(get_class_prop $class expandsize)
376	typeset frag=$(get_class_prop $class fragmentation)
377	case $class in
378	normal|special)
379		check_raidz_used
380		;;
381	elog|special_elog)
382		check_raidz_log_used
383		;;
384	log)
385		check_nonraidz_log_used
386		;;
387	dedup)
388		check_nonraidz_used
389		;;
390	*)
391		log_fail "unhandled class: $class"
392		;;
393	esac
394done
395
396# Expansion
397typeset -il delta=$((32 << 20)) # 32 MiB
398log_must truncate -s $((dedup_vdev_size + delta)) $dedup_vdevs
399typeset -a vdevs=($dedup_vdevs)
400log_must zpool online -e $pool ${vdevs[0]}
401typeset -il size=$(get_class_prop dedup size)
402typeset -il expandsz=$(get_class_prop dedup expandsize)
403log_must test $expandsz -eq $delta
404
405# Pool-wide AVAIL/USABLE/USED
406typeset -il free=$(get_pool_prop free $pool)
407typeset -il avail=$(get_pool_prop available $pool)
408log_must test $avail -gt 0 -a $avail -lt $free
409typeset -il size=$(get_pool_prop size $pool)
410typeset -il usable=$(get_pool_prop usable $pool)
411log_must test $usable -gt 0 -a $usable -lt $size
412typeset -il alloc=$(get_pool_prop alloc $pool)
413typeset -il used=$(get_pool_prop used $pool)
414log_must test $used -gt 0 -a $used -lt $alloc
415
416cleanup
417