Skip to content

Commit

Permalink
ZTS: Fix list_file_blocks for mirror vdevs, level > 0
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Ryan Moeller <[email protected]>
Closes #11141
  • Loading branch information
Ryan Moeller authored and behlendorf committed Nov 11, 2020
1 parent 957b4e9 commit 5ecbea6
Showing 1 changed file with 37 additions and 21 deletions.
58 changes: 37 additions & 21 deletions tests/zfs-tests/include/blkdev.shlib
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}

Expand Down

0 comments on commit 5ecbea6

Please sign in to comment.