1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16# Copyright (c) 2020 Lawrence Livermore National Security, LLC.
17
18. $STF_SUITE/include/libtest.shlib
19
20#
21# Description:
22# Object range parameters passed to zdb -dd work correctly.
23#
24# Strategy:
25# 1. Create a pool
26# 2. Create some files
27# 3. Run zdb -dd with assorted object range arguments and verify output
28
29function cleanup
30{
31	datasetexists $TESTPOOL && destroy_pool $TESTPOOL
32}
33
34#
35# Print objects in @dataset with identifiers greater than or equal to
36# @begin and less than or equal to @end, without using object range
37# parameters.
38#
39function get_object_list_range
40{
41	dataset=$1
42	begin=$2
43	end=$3
44	get_object_list $dataset |
45	while read -r line; do
46		read -r obj _ <<<"$line"
47		if [[ $obj -ge $begin && $obj -le $end ]] ; then
48			echo "$line"
49		elif [[ $obj -gt $end ]] ; then
50			break
51		fi
52	done
53}
54
55#
56# Print just the list of objects from 'zdb -dd' with leading whitespace
57# trimmed, discarding other zdb output, sorted by object identifier.
58# Caller must pass in the dataset argument at minimum.
59#
60function get_object_list
61{
62	zdb -P -dd $@ 2>/dev/null |
63	sed -E '/^ +-?([0-9]+ +){7}/!d;s/^[[:space:]]*//' |
64	sort -n
65}
66
67log_assert "Verify zdb -dd object range arguments work correctly."
68log_onexit cleanup
69verify_runnable "both"
70verify_disk_count "$DISKS" 2
71default_mirror_setup_noexit $DISKS
72
73for x in $(seq 0 7); do
74	touch $TESTDIR/file$x
75	mkdir $TESTDIR/dir$x
76done
77
78sync_all_pools
79
80# Get list of all objects, but filter out user/group objects which don't
81# appear when using object or object range arguments
82all_objects=$(get_object_list $TESTPOOL/$TESTFS | grep -v 'used$')
83
84# Range 0:-1 gets all objects
85expected=$all_objects
86actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1)
87log_must test "\n$actual\n" == "\n$expected\n"
88
89# Range 0:-1:A gets all objects
90expected=$all_objects
91actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1:A)
92log_must test "\n$actual\n" == "\n$expected\n"
93
94# Range 0:-1:f must output all file objects
95expected=$(grep "ZFS plain file" <<< $all_objects)
96actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1:f)
97log_must test "\n$actual\n" == "\n$expected\n"
98
99# Range 0:-1:d must output all directory objects
100expected=$(grep "ZFS directory" <<< $all_objects)
101actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1:d)
102log_must test "\n$actual\n" == "\n$expected\n"
103
104# Range 0:-1:df must output all directory and file objects
105expected=$(grep -e "ZFS directory" -e "ZFS plain file" <<< $all_objects)
106actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1:df)
107log_must test "\n$actual\n" == "\n$expected\n"
108
109# Range 0:-1:A-f-d must output all non-files and non-directories
110expected=$(grep -v -e "ZFS plain file" -e "ZFS directory" <<< $all_objects)
111actual=$(get_object_list $TESTPOOL/$TESTFS 0:-1:A-f-d)
112log_must test "\n$actual\n" == "\n$expected\n"
113
114# Specifying multiple ranges works
115set -A obj_ids $(ls -i $TESTDIR | awk '{print $1}' | sort -n)
116start1=${obj_ids[0]}
117end1=${obj_ids[5]}
118start2=${obj_ids[8]}
119end2=${obj_ids[13]}
120expected=$(get_object_list_range $TESTPOOL/$TESTFS $start1 $end1;
121    get_object_list_range $TESTPOOL/$TESTFS $start2 $end2)
122actual=$(get_object_list $TESTPOOL/$TESTFS $start1:$end1 $start2:$end2)
123log_must test "\n$actual\n" == "\n$expected\n"
124
125# Combining ranges with individual object IDs works
126expected=$(get_object_list_range $TESTPOOL/$TESTFS $start1 $end1;
127    get_object_list $TESTPOOL/$TESTFS $start2 $end2)
128actual=$(get_object_list $TESTPOOL/$TESTFS $start1:$end1 $start2 $end2)
129log_must test "\n$actual\n" == "\n$expected\n"
130
131# Hex conversion must work for ranges and individual object identifiers
132# (this test uses expected result from previous test).
133start1_hex=$(printf "0x%x" $start1)
134end1_hex=$(printf "0x%x" $end1)
135start2_hex=$(printf "0x%x" $start2)
136end2_hex=$(printf "0x%x" $end2)
137actual=$(get_object_list $TESTPOOL/$TESTFS $start1_hex:$end1_hex \
138    $start2_hex $end2_hex)
139log_must test "\n$actual\n" == "\n$expected\n"
140
141# Specifying individual object IDs works
142objects="$start1 $end1 $start2 $end2"
143expected="$objects"
144actual=$(get_object_list $TESTPOOL/$TESTFS $objects | awk '{printf("%s ", $1)}' | tr '\n' ' ')
145log_must test "${actual% }" == "$expected"
146
147# Get all objects in the meta-objset to test m (spacemap) and z (zap) flags
148all_mos_objects=$(get_object_list $TESTPOOL 0:-1)
149
150# Range 0:-1:m must output all space map objects
151expected=$(grep "SPA space map" <<< $all_mos_objects)
152actual=$(get_object_list $TESTPOOL 0:-1:m)
153log_must test "\n$actual\n" == "\n$expected\n"
154
155# Range 0:-1:z must output all zap objects
156expected=$(grep "zap" <<< $all_mos_objects)
157actual=$(get_object_list $TESTPOOL 0:-1:z)
158log_must test "\n$actual\n" == "\n$expected\n"
159
160# Range 0:-1:A-m-z must output all non-space maps and non-zaps
161expected=$(grep -v -e "zap" -e "SPA space map" <<< $all_mos_objects)
162actual=$(get_object_list $TESTPOOL 0:-1:A-m-z)
163log_must test "\n$actual\n" == "\n$expected\n"
164
165# Range 0:-1:mz must output all space maps and zaps
166expected=$(grep -e "SPA space map" -e "zap" <<< $all_mos_objects)
167actual=$(get_object_list $TESTPOOL 0:-1:mz)
168log_must test "\n$actual\n" == "\n$expected\n"
169
170log_pass "zdb -dd object range arguments work correctly"
171