mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-28 03:49:38 +03:00
100790a8dd
If the LED is being accessed by another process when we try to update it, the update will be lost. Add a retry loop which will read the state of the LED and update it until the LED is in the correct state. The number of times this will occur is limited to ensure that the ZEDlet won't hang ZED. Refactor to remove duplication so setting of the LED occurs in only one place. Cleanup a couple of the warnings generated by shellcheck which weren't the result of specific choices by the author. Several notes and warnings are still present but removing them would make the code less clear or require adding lines to tell shellcheck to ignore the warning. Remove ",i" from the documentation at the top of the file which appears to be a typographic error. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Signed-off-by: Christopher Voltz <christopher.voltz@hpe.com> Closes #5795
164 lines
4.2 KiB
Bash
Executable File
164 lines
4.2 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
|
|
#
|
|
# Turn the VDEV's fault LED on if it becomes FAULTED, DEGRADED or UNAVAIL.
|
|
# Turn the LED off when it's back ONLINE again.
|
|
#
|
|
# This script run in two basic modes:
|
|
#
|
|
# 1. If $ZEVENT_VDEV_ENC_SYSFS_PATH and $ZEVENT_VDEV_STATE_STR are set, then
|
|
# only set the LED for that particular VDEV. This is the case for statechange
|
|
# events and some vdev_* events.
|
|
#
|
|
# 2. If those vars are not set, then check the state of all VDEVs in the pool
|
|
# and set the LEDs accordingly. This is the case for pool_import events.
|
|
#
|
|
# Note that this script requires that your enclosure be supported by the
|
|
# Linux SCSI enclosure services (ses) driver. The script will do nothing
|
|
# if you have no enclosure, or if your enclosure isn't supported.
|
|
#
|
|
# Exit codes:
|
|
# 0: enclosure led successfully set
|
|
# 1: enclosure leds not not available
|
|
# 2: enclosure leds administratively disabled
|
|
# 3: The led sysfs path passed from ZFS does not exist
|
|
# 4: $ZPOOL not set
|
|
|
|
[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
|
|
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
|
|
|
if [ ! -d /sys/class/enclosure ] ; then
|
|
exit 1
|
|
fi
|
|
|
|
if [ "${ZED_USE_ENCLOSURE_LEDS}" != "1" ] ; then
|
|
exit 2
|
|
fi
|
|
|
|
zed_check_cmd "$ZPOOL" || exit 4
|
|
|
|
# Global used in set_led debug print
|
|
vdev=""
|
|
|
|
# check_and_set_led (file, val)
|
|
#
|
|
# Read an enclosure sysfs file, and write it if it's not already set to 'val'
|
|
#
|
|
# Arguments
|
|
# file: sysfs file to set (like /sys/class/enclosure/0:0:1:0/SLOT 10/fault)
|
|
# val: value to set it to
|
|
#
|
|
# Return
|
|
# 0 on success, 3 on missing sysfs path
|
|
#
|
|
function check_and_set_led
|
|
{
|
|
file="$1"
|
|
val="$2"
|
|
|
|
if [ ! -e "$file" ] ; then
|
|
return 3
|
|
fi
|
|
|
|
# If another process is accessing the LED when we attempt to update it,
|
|
# the update will be lost so retry until the LED actually changes or we
|
|
# timeout.
|
|
for _ in $(seq 1 5); do
|
|
# We want to check the current state first, since writing to the
|
|
# 'fault' entry always always causes a SES command, even if the
|
|
# current state is already what you want.
|
|
current=$(cat "${file}")
|
|
|
|
# On some enclosures if you write 1 to fault, and read it back,
|
|
# it will return 2. Treat all non-zero values as 1 for
|
|
# simplicity.
|
|
if [ "$current" != "0" ] ; then
|
|
current=1
|
|
fi
|
|
|
|
if [ "$current" != "$val" ] ; then
|
|
echo "$val" > "$file"
|
|
zed_log_msg "vdev $vdev set '$file' LED to $val"
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
function state_to_val {
|
|
state="$1"
|
|
if [ "$state" == "FAULTED" ] || [ "$state" == "DEGRADED" ] || \
|
|
[ "$state" == "UNAVAIL" ] ; then
|
|
echo 1
|
|
elif [ "$state" == "ONLINE" ] ; then
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# process_pool ([pool])
|
|
#
|
|
# Iterate through a pool (or pools) and set the VDEV's enclosure slot LEDs to
|
|
# the VDEV's state.
|
|
#
|
|
# Arguments
|
|
# pool: Optional pool name. If not specified, iterate though all pools.
|
|
#
|
|
# Return
|
|
# 0 on success, 3 on missing sysfs path
|
|
#
|
|
function process_pool
|
|
{
|
|
pool="$1"
|
|
rc=0
|
|
|
|
# Lookup all the current LED values and paths in parallel
|
|
cmd='echo led_token=$(cat "$VDEV_ENC_SYSFS_PATH/fault"),"$VDEV_ENC_SYSFS_PATH",'
|
|
out=$($ZPOOL status -vc "$cmd" "$pool" | grep 'led_token=')
|
|
while read -r vdev state read write chksum therest ; do
|
|
|
|
# Read out current LED value and path
|
|
tmp=$(echo "$therest" | sed 's/^.*led_token=//g')
|
|
IFS="," read -r current_val vdev_enc_sysfs_path <<< "$tmp"
|
|
|
|
if [ -z "$vdev_enc_sysfs_path" ] ; then
|
|
# Skip anything with no sysfs LED entries
|
|
continue
|
|
fi
|
|
|
|
if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
|
|
rc=1
|
|
zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
|
|
continue;
|
|
fi
|
|
|
|
val=$(state_to_val "$state")
|
|
|
|
if [ "$current_val" == "$val" ] ; then
|
|
# LED is already set correctly
|
|
continue;
|
|
fi
|
|
|
|
check_and_set_led "$vdev_enc_sysfs_path/fault" "$val"
|
|
(( rc |= $? ))
|
|
|
|
done <<< "$out"
|
|
|
|
if [ "$rc" == "0" ] ; then
|
|
return 0
|
|
else
|
|
# We didn't see a sysfs entry that we wanted to set
|
|
return 3
|
|
fi
|
|
}
|
|
|
|
if [ ! -z "$ZEVENT_VDEV_ENC_SYSFS_PATH" ] && [ ! -z "$ZEVENT_VDEV_STATE_STR" ] ; then
|
|
# Got a statechange for an individual VDEV
|
|
val=$(state_to_val "$ZEVENT_VDEV_STATE_STR")
|
|
vdev="$(basename $ZEVENT_VDEV_PATH)"
|
|
check_and_set_led "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" "$val"
|
|
else
|
|
# Process the entire pool
|
|
process_pool "$(zed_guid_to_pool $ZEVENT_POOL_GUID)"
|
|
fi
|