mirror_zfs/cmd/zpool_layout/zpool_layout
Brian Behlendorf 6ee44e32be Fix awk usage
The zpool_id and zpool_layout helper scripts have been updated to
use the more common /usr/bin/awk symlink.  On Fedora/Redhat systems
there are both /bin/awk and /usr/bin/awk symlinks to your installed
version of awk.  On Debian/Ubuntu systems only the /usr/bin/awk
symlink exists.

Additionally, add the '\<' token to the beginning of the regex
pattern to prevent partial matches.  This pattern only appears to
work with gawk despite the mawk man page claiming to support this
extended regex.  Thus you will need to have gawk installed to use
these optional helper scripts.  A comment has been added to the
script to reflect this reality.
2011-05-06 10:16:04 -07:00

161 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
#
# Set BUSES and PORTS to match the topology of your system. As each
# port is enumerated it will be assigned the next channel name. The
# current script enumerates each port on a bus before moving on to
# enumerate the next bus.
#
# Every distribution, version of udev, and type of attached storage
# seems to result in slightly different formatting of the by-path
# name. For this reason you may need to adjust the parsing below
# to suit your needs. This is one of the reasons to use a custom
# /etc/zfs/zdev.conf file, it allows the by-path naming convertion
# to change and still keep the simple <channel><rank> naming.
#
AWK=${AWK:-/usr/bin/awk}
CONFIG=${CONFIG:-/etc/zfs/zdev.conf}
BUSES=( 01 02 03 )
PORTS=( 4 0 )
CHANNELS=( A B C D E F G H I J K L M N O P Q R S T U V W X Y Z )
TRIGGER="no"
MAPPING=linux
usage() {
cat << EOF
Usage: zpool_layout [-th] [-c file] [-b buses] [-p ports] [-n channels] [-m map]
-c Alternate config file [default=${CONFIG}]
-b Enumerate buses [default="${BUSES[*]}"]
-p Enumerate ports [default="${PORTS[*]}"]
-n Channel names [default="A..Z"]
-t Trigger and wait for udev to settle [default=${TRIGGER}]
-m Slot mapping [default=${MAPPING}]
-h Show this message
EOF
exit 0
}
while getopts 'c:b:p:n:m:th' OPTION; do
case ${OPTION} in
c)
CONFIG=${OPTARG}
;;
b)
BUSES=(${OPTARG})
;;
p)
PORTS=(${OPTARG})
;;
n)
CHANNELS=(${OPTARG})
;;
m)
MAPPING=`readlink -e ${OPTARG}`
;;
t)
TRIGGER=yes
;;
h)
usage
;;
esac
done
# Verify mapping file exists if specified.
# Linux-Slot Custom-Slot
if [ ${MAPPING} != "linux" ] && [ ! -e ${MAPPING} ]; then
echo "Error: Mapping file '${MAPPING}' does not exist"
exit 1
fi
# Save stdout as fd #8, then redirect stdout to the config file.
exec 8>&1
exec >${CONFIG}
pushd /dev/disk/by-path >/dev/null
map_slot() {
local LINUX_SLOT=$1
local MAPPED_SLOT=
if [ ${MAPPING} = "linux" ]; then
MAPPED_SLOT=${LINUX_SLOT}
else
MAPPED_SLOT=`${AWK} "\\$1 == ${LINUX_SLOT} && !/^#/ \
{ print \\$2; exit }" $MAPPING`
fi
printf "%d" ${MAPPED_SLOT}
}
# Generate comment header.
echo "#"
echo "# Custom /dev/disk/by-path to /dev/disk/zpool mapping, "
echo "# based of the following physical cable layout."
echo "#"
# Generate host port layout table for comment header.
echo "# ------------------ Host Port Layout ---------------------"
echo -n "# "
for (( i=0; i<${#BUSES[*]}; i++ )); do
printf "%-8d" ${BUSES[$i]}
done
echo
for (( i=0, k=0; i<${#PORTS[*]}; i++ )); do
printf "# Port %-2d " ${PORTS[$i]}
for (( j=0; j<${#BUSES[*]}; j++, k++ )); do
let k=$j*${#PORTS[*]}+$i
printf "%-8s" ${CHANNELS[$k]}
done
echo
done
echo "#"
# Generate channel/disk layout table for comment header.
echo "# ----------------- Channel/Disk Layout -------------------"
echo "# Channel Disks"
for (( i=0, k=0; i<${#BUSES[*]}; i++ )); do
for (( j=0; j<${#PORTS[*]}; j++, k++ )); do
printf "# %-9s" ${CHANNELS[$k]}
ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \
cut -f7 -d'-' | sort -u -n | tr '\n' ','
echo
done
done
echo "#"
# Generate mapping from <channel><rank> to by-path name.
for (( i=0, k=0; i<${#BUSES[*]}; i++ )); do
for (( j=0; j<${#PORTS[*]}; j++, k++ )); do
BYPATH=(`ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \
grep -v part | sort -n -k7 -t'-' | cut -f1-6 -d'-'`)
SLOTS=(`ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \
grep -v part | sort -n -k7 -t'-' | cut -f7 -d'-'`)
TMP_FILE=`mktemp`
for (( l=0; l<${#SLOTS[*]}; l++ )); do
MAPPED_SLOT=`map_slot ${SLOTS[$l]}`
printf "%s%d\t%s-%d\n" \
${CHANNELS[$k]} ${MAPPED_SLOT} \
${BYPATH[$l]} ${SLOTS[$l]} >>${TMP_FILE}
done
echo
echo -n "# Channel ${CHANNELS[$k]}, "
echo "Bus ${BUSES[$i]}, Port ${PORTS[$j]}"
cat ${TMP_FILE} | sort -n -k2 -t${CHANNELS[$k]}
rm -f ${TMP_FILE}
done
done
# Restore stdout from fd #8 and close fd #8.
exec 1>&8 8>&-
popd >/dev/null
if [ ${TRIGGER} = "yes" ]; then
udevadm trigger --action=change --subsystem-match=block
udevadm settle
fi
exit 0