aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib')
-rw-r--r--sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib89
1 files changed, 61 insertions, 28 deletions
diff --git a/sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib b/sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib
index b34f2c04d743..3f29d4f594a1 100644
--- a/sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib
+++ b/sys/contrib/openzfs/tests/zfs-tests/include/blkdev.shlib
@@ -548,22 +548,37 @@ function list_file_blocks # input_file
#
# Establish a mapping between vdev ids as shown in a DVA and the
- # pathnames they correspond to in ${VDEV_MAP[]}.
+ # pathnames they correspond to in ${VDEV_MAP[][]}.
+ #
+ # The vdev bits in a DVA refer to the top level vdev id.
+ # ${VDEV_MAP[$id]} is an array of the vdev paths within that vdev.
#
eval $(zdb -C $pool | awk '
- BEGIN {
- printf("typeset VDEV_MAP\n");
- looking = 0;
- }
- /^ children/ {
- id = $1;
- looking = 1;
- }
- /path: / && looking == 1 {
- print id" "$2;
- looking = 0;
- }
- ' | sed -n 's/^children\[\([0-9]\)\]: \(.*\)$/VDEV_MAP[\1]=\2/p')
+ BEGIN { printf "typeset -a VDEV_MAP;" }
+ function subscript(s) {
+ # "[#]" is more convenient than the bare "#"
+ match(s, /\[[0-9]*\]/)
+ return substr(s, RSTART, RLENGTH)
+ }
+ id && !/^ / {
+ # left a top level vdev
+ id = 0
+ }
+ id && $1 ~ /^path:$/ {
+ # found a vdev path; save it in the map
+ printf "VDEV_MAP%s%s=%s;", id, child, $2
+ }
+ /^ children/ {
+ # entering a top level vdev
+ id = subscript($0)
+ child = "[0]" # default in case there is no nested vdev
+ printf "typeset -a VDEV_MAP%s;", id
+ }
+ /^ children/ {
+ # entering a nested vdev (e.g. child of a top level mirror)
+ child = subscript($0)
+ }
+ ')
#
# The awk below parses the output of zdb, printing out the level
@@ -571,22 +586,40 @@ function list_file_blocks # input_file
# two are converted to decimal in the while loop. 4M is added to
# the offset to compensate for the first two labels and boot
# block. Lastly, the offset and length are printed in units of
- # 512b blocks for ease of use with dd.
+ # 512B blocks for ease of use with dd.
#
+ typeset level vdev path offset length
+ if awk -n '' 2>/dev/null; then
+ # gawk needs -n to decode hex
+ AWK='awk -n'
+ else
+ AWK='awk'
+ fi
log_must zpool sync -f
- typeset level path offset length
- zdb -ddddd $ds $objnum | awk -F: '
- BEGIN { looking = 0 }
- /^Indirect blocks:/ { looking = 1}
- /^\t\tsegment / { looking = 0}
- /L[0-8]/ && looking == 1 { print $0}
- ' | sed -n 's/^.*\(L[0-9]\) \([0-9]*\):\([0-9a-f]*\):\([0-9a-f]*\) .*$/\1 \2 \3 \4/p' | \
- while read level path offset length; do
- offset=$((16#$offset)) # Conversion from hex
- length=$((16#$length))
- offset="$(((offset + 4 * 1024 * 1024) / 512))"
- length="$((length / 512))"
- echo "$level ${VDEV_MAP[$path]} $offset $length"
+ zdb -dddddd $ds $objnum | $AWK -v pad=$((4<<20)) -v bs=512 '
+ /^$/ { looking = 0 }
+ looking {
+ level = $2
+ field = 3
+ while (split($field, dva, ":") == 3) {
+ # top level vdev id
+ vdev = int(dva[1])
+ # offset + 4M label/boot pad in 512B blocks
+ offset = (int("0x"dva[2]) + pad) / bs
+ # length in 512B blocks
+ len = int("0x"dva[3]) / bs
+
+ print level, vdev, offset, len
+
+ ++field
+ }
+ }
+ /^Indirect blocks:/ { looking = 1 }
+ ' | \
+ while read level vdev offset length; do
+ for path in ${VDEV_MAP[$vdev][@]}; do
+ echo "$level $path $offset $length"
+ done
done 2>/dev/null
}