Enclosure LED fixes
- Pass $VDEV_ENC_SYSFS_PATH to 'zpool [iostat|status] -c' to include enclosure LED sysfs path. - Set LEDs correctly after import. This includes clearing any erroniously set LEDs prior to the import, and setting the LED for any UNAVAIL drives. - Include symlink for vdev_attach-led.sh in Makefile.am. - Print the VDEV path in all-syslog.sh, and fix it so the pool GUID actually prints. Reviewed-by: Don Brady <don.brady@intel.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Closes #5716 Closes #5751
This commit is contained in:
parent
65a736bc0d
commit
b291029e86
@ -67,7 +67,9 @@ dist_zedexec_SCRIPTS = \
|
||||
zed.d/scrub_finish-notify.sh \
|
||||
zed.d/statechange-led.sh \
|
||||
zed.d/statechange-notify.sh \
|
||||
zed.d/vdev_clear-led.sh
|
||||
zed.d/vdev_clear-led.sh \
|
||||
zed.d/vdev_attach-led.sh \
|
||||
zed.d/pool_import-led.sh
|
||||
|
||||
zedconfdefaults = \
|
||||
all-syslog.sh \
|
||||
@ -76,7 +78,9 @@ zedconfdefaults = \
|
||||
scrub_finish-notify.sh \
|
||||
statechange-led.sh \
|
||||
statechange-notify.sh \
|
||||
vdev_clear-led.sh
|
||||
vdev_clear-led.sh \
|
||||
vdev_attach-led.sh \
|
||||
pool_import-led.sh
|
||||
|
||||
install-data-hook:
|
||||
$(MKDIR_P) "$(DESTDIR)$(zedconfdir)"
|
||||
|
@ -6,6 +6,7 @@
|
||||
. "${ZED_ZEDLET_DIR}/zed-functions.sh"
|
||||
|
||||
zed_log_msg "eid=${ZEVENT_EID}" "class=${ZEVENT_SUBCLASS}" \
|
||||
"${ZEVENT_POOL:+"pool=${ZEVENT_POOL}"}" \
|
||||
"${ZEVENT_POOL_GUID:+"pool_guid=${ZEVENT_POOL_GUID}"}" \
|
||||
"${ZEVENT_VDEV_PATH:+"vdev_path=${ZEVENT_VDEV_PATH}"}" \
|
||||
"${ZEVENT_VDEV_STATE_STR:+"vdev_state=${ZEVENT_VDEV_STATE_STR}"}"
|
||||
exit 0
|
||||
|
1
cmd/zed/zed.d/pool_import-led.sh
Symbolic link
1
cmd/zed/zed.d/pool_import-led.sh
Symbolic link
@ -0,0 +1 @@
|
||||
statechange-led.sh
|
@ -2,13 +2,19 @@
|
||||
#
|
||||
# Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
|
||||
#
|
||||
# Turn LED on if the VDEV becomes faulted or degraded, and turn it back off
|
||||
# when it's online again. It will also turn on the LED (or keep it on) if
|
||||
# the drive becomes unavailable, unless the drive was in was a previously
|
||||
# online state (online->unavail is a normal state transition during an
|
||||
# autoreplace).
|
||||
# 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 requires that your enclosure be supported by the
|
||||
# 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,i
|
||||
# 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.
|
||||
#
|
||||
@ -16,8 +22,8 @@
|
||||
# 0: enclosure led successfully set
|
||||
# 1: enclosure leds not not available
|
||||
# 2: enclosure leds administratively disabled
|
||||
# 3: ZED didn't pass enclosure sysfs path
|
||||
# 4: Enclosure sysfs path doesn't exist
|
||||
# 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"
|
||||
@ -30,15 +36,54 @@ if [ "${ZED_USE_ENCLOSURE_LEDS}" != "1" ] ; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
[ -n "${ZEVENT_VDEV_ENC_SYSFS_PATH}" ] || exit 3
|
||||
zed_check_cmd "$ZPOOL" || exit 4
|
||||
|
||||
[ -e "${ZEVENT_VDEV_ENC_SYSFS_PATH}/fault" ] || exit 4
|
||||
# Global used in set_led debug print
|
||||
vdev=""
|
||||
|
||||
# Turn on/off enclosure LEDs
|
||||
function led
|
||||
# set_led (file)
|
||||
#
|
||||
# Write an enclosure sysfs file
|
||||
#
|
||||
# Arguments
|
||||
# file: sysfs file to set (like /sys/class/enclosure/0:0:1:0/SLOT 10/fault)
|
||||
# val: value to set it to
|
||||
#
|
||||
# Globals
|
||||
# vdev: VDEV name for debug printing
|
||||
#
|
||||
# Return
|
||||
# nothing
|
||||
#
|
||||
function set_led {
|
||||
file="$1"
|
||||
val="$2"
|
||||
|
||||
# Set the value twice. I've seen enclosures that were
|
||||
# flakey about setting it the first time.
|
||||
echo "$val" > "$file"
|
||||
echo "$val" > "$file"
|
||||
zed_log_msg "vdev $vdev set '$file' LED to $val"
|
||||
}
|
||||
|
||||
# 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/fault"
|
||||
val=$2
|
||||
file="$1"
|
||||
val="$2"
|
||||
if [ ! -e "$ZEVENT_VDEV_ENC_SYSFS_PATH/fault" ] ; then
|
||||
return 3
|
||||
fi
|
||||
|
||||
# We want to check the current state first, since writing to the
|
||||
# 'fault' entry always always causes a SES command, even if the
|
||||
@ -53,28 +98,88 @@ function led
|
||||
fi
|
||||
|
||||
if [ "$current" != "$val" ] ; then
|
||||
# Set the value twice. I've seen enclosures that were
|
||||
# flakey about setting it the first time.
|
||||
echo "$val" > "$file"
|
||||
echo "$val" > "$file"
|
||||
set_led "$file" "$val"
|
||||
fi
|
||||
}
|
||||
|
||||
# Decide whether to turn on/off an LED based on the state
|
||||
# Pass in path name and fault string ("ONLINE"/"FAULTED"/"DEGRADED"...etc)
|
||||
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])
|
||||
#
|
||||
# We only turn on LEDs when a drive becomes FAULTED, DEGRADED, or UNAVAIL and
|
||||
# only turn it on when it comes back ONLINE. All other states are ignored, and
|
||||
# keep the previous LED state.
|
||||
function process {
|
||||
path="$1"
|
||||
fault=$2
|
||||
if [ "$fault" == "FAULTED" ] || [ "$fault" == "DEGRADED" ] || \
|
||||
[ "$fault" == "UNAVAIL" ] ; then
|
||||
led "$path" 1
|
||||
elif [ "$fault" == "ONLINE" ] ; then
|
||||
led "$path" 0
|
||||
# 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
|
||||
|
||||
# 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_val" != "0" ] ; then
|
||||
current_val=1
|
||||
fi
|
||||
|
||||
val=$(state_to_val "$state")
|
||||
|
||||
if [ "$current_val" == "$val" ] ; then
|
||||
# LED is already set correctly
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -e "$vdev_enc_sysfs_path/fault" ] ; then
|
||||
rc=1
|
||||
zed_log_msg "vdev $vdev '$file/fault' doesn't exist"
|
||||
continue;
|
||||
fi
|
||||
|
||||
set_led "$vdev_enc_sysfs_path/fault" $val
|
||||
|
||||
done <<< "$out"
|
||||
if [ "$rc" == "0" ] ; then
|
||||
return 0
|
||||
else
|
||||
# We didn't see a sysfs entry that we wanted to set
|
||||
return 3
|
||||
fi
|
||||
}
|
||||
|
||||
process "$ZEVENT_VDEV_ENC_SYSFS_PATH" "$ZEVENT_VDEV_STATE_STR"
|
||||
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
|
||||
|
@ -413,3 +413,25 @@ zed_rate_limit()
|
||||
zed_unlock "${lockfile}" "${lockfile_fd}"
|
||||
return "${rv}"
|
||||
}
|
||||
|
||||
|
||||
# zed_guid_to_pool (guid)
|
||||
#
|
||||
# Convert a pool GUID into its pool name (like "tank")
|
||||
# Arguments
|
||||
# guid: pool GUID (decimal or hex)
|
||||
#
|
||||
# Return
|
||||
# Pool name
|
||||
#
|
||||
function zed_guid_to_pool
|
||||
{
|
||||
if [ -z "$1" ] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
guid=$(printf "%llu" $1)
|
||||
if [ ! -z "$guid" ] ; then
|
||||
$ZPOOL get -H -ovalue,name guid | awk '$1=='$guid' {print $2}'
|
||||
fi
|
||||
}
|
||||
|
@ -332,9 +332,11 @@ vdev_run_cmd_thread(void *cb_cmd_data)
|
||||
char cmd[_POSIX_ARG_MAX];
|
||||
|
||||
/* Set our VDEV_PATH and VDEV_UPATH env vars and run command */
|
||||
if (snprintf(cmd, sizeof (cmd), "VDEV_PATH=%s && VDEV_UPATH=%s && %s",
|
||||
data->path, data->upath ? data->upath : "\"\"", data->cmd) >=
|
||||
sizeof (cmd)) {
|
||||
if (snprintf(cmd, sizeof (cmd), "VDEV_PATH=%s && VDEV_UPATH=\"%s\" && "
|
||||
"VDEV_ENC_SYSFS_PATH=\"%s\" && %s", data->path ? data->path : "",
|
||||
data->upath ? data->upath : "",
|
||||
data->vdev_enc_sysfs_path ? data->vdev_enc_sysfs_path : "",
|
||||
data->cmd) >= sizeof (cmd)) {
|
||||
/* Our string was truncated */
|
||||
return;
|
||||
}
|
||||
@ -364,11 +366,15 @@ for_each_vdev_run_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_vcdl)
|
||||
vdev_cmd_data_t *data;
|
||||
char *path = NULL;
|
||||
char *vname = NULL;
|
||||
char *vdev_enc_sysfs_path = NULL;
|
||||
int i, match = 0;
|
||||
|
||||
if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
|
||||
return (1);
|
||||
|
||||
nvlist_lookup_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
|
||||
&vdev_enc_sysfs_path);
|
||||
|
||||
/* Spares show more than once if they're in use, so skip if exists */
|
||||
for (i = 0; i < vcdl->count; i++) {
|
||||
if ((strcmp(vcdl->data[i].path, path) == 0) &&
|
||||
@ -406,6 +412,10 @@ for_each_vdev_run_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_vcdl)
|
||||
data->path = strdup(path);
|
||||
data->upath = zfs_get_underlying_path(path);
|
||||
data->cmd = vcdl->cmd;
|
||||
if (vdev_enc_sysfs_path)
|
||||
data->vdev_enc_sysfs_path = strdup(vdev_enc_sysfs_path);
|
||||
else
|
||||
data->vdev_enc_sysfs_path = NULL;
|
||||
|
||||
vcdl->count++;
|
||||
|
||||
@ -500,6 +510,7 @@ free_vdev_cmd_data_list(vdev_cmd_data_list_t *vcdl)
|
||||
free(vcdl->data[i].pool);
|
||||
free(vcdl->data[i].upath);
|
||||
free(vcdl->data[i].line);
|
||||
free(vcdl->data[i].vdev_enc_sysfs_path);
|
||||
}
|
||||
free(vcdl->data);
|
||||
free(vcdl);
|
||||
|
@ -80,6 +80,7 @@ typedef struct vdev_cmd_data
|
||||
char *upath; /* vdev underlying path */
|
||||
char *pool; /* Pool name */
|
||||
char *cmd; /* backpointer to cmd */
|
||||
char *vdev_enc_sysfs_path; /* enclosure sysfs path (if any) */
|
||||
} vdev_cmd_data_t;
|
||||
|
||||
typedef struct vdev_cmd_data_list
|
||||
|
@ -1548,12 +1548,16 @@ base 1024. To get the raw values, use the \fB-p\fR flag.
|
||||
Run a command on each vdev and include first line of output
|
||||
.sp
|
||||
The \fB-c\fR option allows you to run an arbitrary command on each vdev and
|
||||
display the first line of output in zpool iostat. The environment vars
|
||||
\fBVDEV_PATH\fR and \fBVDEV_UPATH\fR are set to the vdev's path and "underlying
|
||||
path" before running the command. For device mapper, multipath, or partitioned
|
||||
vdevs, \fBVDEV_UPATH\fR is the actual underlying /dev/sd* disk. This can be
|
||||
useful if the command you're running requires a /dev/sd* device. Commands run
|
||||
in parallel for each vdev for performance.
|
||||
display the first line of output in zpool iostat. The following environment
|
||||
vars are set before running each command:
|
||||
.sp
|
||||
\fB$VDEV_PATH\fR: Full path to the vdev.
|
||||
.LP
|
||||
\fB$VDEV_UPATH\fR: "Underlying path" to the vdev. For device mapper, multipath, or
|
||||
partitioned vdevs, \fBVDEV_UPATH\fR is the actual underlying /dev/sd* disk.
|
||||
This can be useful if the command you're running requires a /dev/sd* device.
|
||||
.LP
|
||||
\fB$VDEV_ENC_SYSFS_PATH\fR: The sysfs path to the vdev's enclosure LEDs (if any).
|
||||
.RE
|
||||
|
||||
.sp
|
||||
@ -2116,12 +2120,16 @@ If a scrub or resilver is in progress, this command reports the percentage done
|
||||
Run a command on each vdev and include first line of output
|
||||
.sp
|
||||
The \fB-c\fR option allows you to run an arbitrary command on each vdev and
|
||||
display the first line of output in zpool status. The environment vars
|
||||
\fBVDEV_PATH\fR and \fBVDEV_UPATH\fR are set to the vdev's path and "underlying
|
||||
path" before running the command. For device mapper, multipath, or partitioned
|
||||
vdevs, \fBVDEV_UPATH\fR is the actual underlying /dev/sd* disk. This can be
|
||||
useful if the command you're running requires a /dev/sd* device. Commands run
|
||||
in parallel for each vdev for performance.
|
||||
display the first line of output in zpool iostat. The following environment
|
||||
vars are set before running each command:
|
||||
.sp
|
||||
\fB$VDEV_PATH\fR: Full path to the vdev.
|
||||
.LP
|
||||
\fB$VDEV_UPATH\fR: "Underlying path" to the vdev. For device mapper, multipath, or
|
||||
partitioned vdevs, \fBVDEV_UPATH\fR is the actual underlying /dev/sd* disk.
|
||||
This can be useful if the command you're running requires a /dev/sd* device.
|
||||
.LP
|
||||
\fB$VDEV_ENC_SYSFS_PATH\fR: The sysfs path to the vdev's enclosure LEDs (if any).
|
||||
.RE
|
||||
|
||||
.sp
|
||||
|
Loading…
Reference in New Issue
Block a user