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 # 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 ' eval $(zdb -C $pool | awk '
BEGIN { BEGIN { printf "typeset -a VDEV_MAP;" }
printf("typeset VDEV_MAP\n"); function subscript(s) {
looking = 0; # "[#]" 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/ { /^ children/ {
id = $1; # entering a top level vdev
looking = 1; id = subscript($0)
child = "[0]" # default in case there is no nested vdev
printf "typeset -a VDEV_MAP%s;", id
} }
/path: / && looking == 1 { /^ children/ {
print id" "$2; # entering a nested vdev (e.g. child of a top level mirror)
looking = 0; 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 # 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 log_must zpool sync -f
typeset level path offset length typeset level path offset length
zdb -ddddd $ds $objnum | awk -F: ' zdb -ddddd $ds $objnum | awk -F: '
BEGIN { looking = 0 } /^Indirect blocks:/ { looking = 1 }
/^Indirect blocks:/ { looking = 1} /^\t\tsegment / { looking = 0 }
/^\t\tsegment / { looking = 0} /L[0-8]/ && looking { print }
/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' | \
' | 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
while read level path offset length; do
offset=$((16#$offset)) # Conversion from hex offset=$((16#$offset)) # Conversion from hex
length=$((16#$length)) length=$((16#$length))
offset="$(((offset + 4 * 1024 * 1024) / 512))" offset="$(((offset + 4 * 1024 * 1024) / 512))"
length="$((length / 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 done 2>/dev/null
} }