ZTS: Fix list_file_blocks for mirror vdevs, level > 0

The first part of list_file_blocks transforms the pool configuration
output by zdb -C $pool into shell code to set up a shell variable,
VDEV_MAP, that maps from vdev id to the underlying vdev path. This
variable is a simple indexed array. However, the vdev id in a DVA is
only the id of the top level vdev.

When the pool is mirrored, the top level vdev is a mirror and its
children are the mirrored devices. So, what we need is to map from
the top level vdev id to a list of the underlying vdev paths.
ist_file_blocks does not need to work for raidz vdevs, so we can
disregard that case.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
Closes #11141
This commit is contained in:
Ryan Moeller 2020-10-28 20:29:31 +00:00 committed by Brian Behlendorf
parent ae37ceadaa
commit 94deb47872
1 changed files with 37 additions and 21 deletions

View File

@ -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;
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/ {
id = $1;
looking = 1;
# 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
}
/path: / && looking == 1 {
print id" "$2;
looking = 0;
/^ children/ {
# entering a nested vdev (e.g. child of a top level mirror)
child = subscript($0)
}
' | sed -n 's/^children\[\([0-9]\)\]: \(.*\)$/VDEV_MAP[\1]=\2/p')
')
#
# The awk below parses the output of zdb, printing out the level
@ -576,17 +591,18 @@ function list_file_blocks # input_file
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
/^Indirect blocks:/ { looking = 1 }
/^\t\tsegment / { looking = 0 }
/L[0-8]/ && looking { print }
' | sed -n 's/^.*\(L[0-9]\) *\([0-9]*\):\([0-9a-f]*\):\([0-9a-f]*\) .*$/\1 \2 \3 \4/p' | \
while read level vdev 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"
for path in ${VDEV_MAP[$vdev][@]}; do
echo "$level $path $offset $length"
done
done 2>/dev/null
}