chreipl-fcp-mpath: if event subject is not re-IPL target, test if WWID matches

When the first test, whether the current event subject represents the
re-IPL target failed, we attempt a second test, using the recorded WWID
of a previously successful attempt.

The new helper `chreipl-fcp-mpath-is-ipl-vol` utilizes the information
previously stored in the ID-file (read under lock via `flock`).

The recorded WWID is compared with the one of the event subject; if it
matches we know that it addresses the same volume, and might be used as
alternative re-IPL target.

Additionally we also compare the current re-IPL triplet with the one
recorded in the ID-file. If it doesn't match anymore, we assume the
recorded WWID is stale - e.g., because the operator changed the re-IPL
target manually - and the previous check invalid.

If both the WWID match, and the re-IPL triplet is still the same as
previously recorded, the toolset may continue with the subject, and use
it as replacement for the current re-IPL target.

Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Benjamin Block
2021-09-17 13:12:52 +02:00
committed by Jan Höppner
parent cb831aea44
commit 2a29a28f78
5 changed files with 145 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
# build artifacts
/chreipl-fcp-mpath-common.sh
/chreipl-fcp-mpath-is-ipl-tgt
/chreipl-fcp-mpath-is-ipl-vol
/chreipl-fcp-mpath-is-reipl-zfcp
/chreipl-fcp-mpath-record-volume-identifier

View File

@@ -45,6 +45,7 @@ CHREIPL_FCP_MPATH_COMMON := \
chreipl-fcp-mpath-common.sh
CHREIPL_FCP_MPATH_UDEV_HELPER := \
chreipl-fcp-mpath-is-ipl-tgt \
chreipl-fcp-mpath-is-ipl-vol \
chreipl-fcp-mpath-is-reipl-zfcp \
chreipl-fcp-mpath-record-volume-identifier

View File

@@ -112,6 +112,37 @@ function id_file_lock_exclusive_create() {
return 0
}
# Output variables:
# id_file_unlock_shared_no_create() - call to unlock when finished with
# critical section
#
# XXX: `id_file_lock_*` can't be taken recursively
function id_file_lock_shared_no_create() {
declare -g ID_FILE_LOCK=""
# Open the file defined in ${ID_FILE} for reading, and store the
# corresponding file descriptor in ${ID_FILE_LOCK}.
{ exec {ID_FILE_LOCK}<"${ID_FILE}"; } 2>/dev/null || return 1
declare -gf id_file_unlock_shared_no_create 1>/dev/null
function id_file_unlock_shared_no_create() {
if [ -v ID_FILE_LOCK ]; then
# release file and implicitly the lock, if taken
exec {ID_FILE_LOCK}<&-
unset ID_FILE_LOCK
fi
unset "TRAP_EXIT_FN[id_file_unlock_shared_no_create]"
}
TRAP_EXIT_FN+=(
[id_file_unlock_shared_no_create]=id_file_unlock_shared_no_create
)
flock --shared --timeout 5 "${ID_FILE_LOCK}" || return 2
return 0
}
# Output variables:
# firmware_unlock_shared() - call to unlock when finished with critical section
#

View File

@@ -0,0 +1,86 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
# (C) Copyright IBM Corp. 2021
#
# Uses the following system-utilities (and shell-builtins):
# Those necessary for sourced library:
# - chreipl-fcp-mpath-common.sh
# Find out whether the device in environment variable ${DEVPATH} represents the
# _volume_ that we IPL'ed from. We do this by comparing its WWID to the one
# recorded in `@chreiplzfcpmp-id-file@`.
#
# Makes use of udev event environment variables:
# DM_UUID
# SUBSYSTEM
# DEVPATH
# shellcheck disable=SC2034
declare -gr debug_trace_tag=11iilv
# shellcheck disable=SC1091
source '@chreiplzfcpmp-lib@' || exit 127
function id_file_read_ipl_information() {
local -a records
declare -g REC_WWID="" REC_BUSID="" REC_WWPN="" REC_LUN=""
# lock file before reading ID, so we don't see any intermediate state
id_file_lock_shared_no_create || return 1
{ readarray -d "" -t -u "${ID_FILE_LOCK}" records; } 2>/dev/null \
|| return 2
if '@DEBUG@'; then declare -p records 1>&2; fi
id_file_unlock_shared_no_create
[ "${#records[@]}" = "4" ] || return 3
# check that none of the array fields contains whitespace only
[ "${records[0]/#*([[:space:]])}" != "" ] || return 4
[ "${records[1]/#*([[:space:]])}" != "" ] || return 5
[ "${records[2]/#*([[:space:]])}" != "" ] || return 6
[ "${records[3]/#*([[:space:]])}" != "" ] || return 7
REC_WWID="${records[0]}"
REC_BUSID="${records[1]}"
REC_WWPN="${records[2]}"
REC_LUN="${records[3]}"
return 0
}
id_file_read_ipl_information || exit 1
if [[ "${DM_UUID}" == mpath-* ]]; then
# Assume Multipath Device Mapper Device;
# e.g.: DEVPATH = /devices/virtual/block/dm-0
declare sdev found=false
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
if sdev_get_wwid "${sdev}"; then
found=true
break
fi
done
unset sdev
"${found}" || exit 2
elif [ "${SUBSYSTEM}" = block ]; then
# Assume SCSI Disk;
# e.g.: DEVPATH = /devices/css0/0.0.0014/0.0.1700/host0/rport-0:0-0/target0:0:0/0:0:0:1074806808/block/sds
sdev_get_wwid /sys/"${DEVPATH}"/device || exit 3
fi
# set by `sdev_get_wwid` and `id_file_read_ipl_information`
[ "${SDEV_WWID}" = "${REC_WWID}" ] || exit 4
firmware_get_ipl_information || exit 5
# set by `firmware_get_ipl_information` and `id_file_read_ipl_information`
[ "${IPL_BUSID}" = "${REC_BUSID}" ] || exit 6
[ "${IPL_WWPN}" = "${REC_WWPN}" ] || exit 7
[ "${IPL_LUN}" = "${REC_LUN}" ] || exit 8
exit 0

View File

@@ -27,7 +27,9 @@ PROGRAM!="chreipl-fcp-mpath-is-reipl-zfcp", GOTO="chreipl_fcp_mpath_end"
# Either:
#
# (A) We recognized a new SCSI Disk. This might represent:
# (a) the path we want to ReIPL from.
# (a) the path we want to ReIPL from;
# (b) an alternative path to the volume we want to ReIPL from;
# (c) a path to some unrelated volume.
#
# Or:
#
@@ -37,7 +39,8 @@ PROGRAM!="chreipl-fcp-mpath-is-reipl-zfcp", GOTO="chreipl_fcp_mpath_end"
# (b) came back online;
# an alternative path to the volume we want to ReIPL from:
# (c) went away;
# (d) came back online.
# (d) came back online;
# (e) some unrelated multipath device saw an event.
# Test whether the affected device is, or contains, the current IPL target.
#
@@ -68,6 +71,27 @@ GOTO="chreipl_fcp_mpath_try_change_ipl_path"
# ReIPL target, and not a mpath device that contains the current ReIPL target)
LABEL="chreipl_fcp_mpath_not_direct_match"
# While this sdev/mpath device doesn't directly correspond to the path
# currently set as ReIPL target, it might still point to the same volume.
#
# For mpath devices this can happen if the original ReIPL target is completely
# gone from the machine, and so there is no way we can successfully, directly
# compare the ReIPL parameters to the sdevs of the mpath device.
#
# For cases like these we recorded the volume identifier, which we now can
# compare, and so still decide whether we are addressing the correct volume.
#
# This covers scenarios:
# (A) (b)/(c),
# (B) (c)/(d)/(e)
#
# XXX: we recorded WWID, Device-Bus-ID, Remote WWPN, LUN of the ReIPL target at
# the time; if the latter three don't match the current ReIPL setting
# anymore, we have to assume that someone changed the ReIPL target
# manually, and we cannot use the WWID anymore since we can't possibly
# know whether that stayed the same when the change was done.
PROGRAM!="chreipl-fcp-mpath-is-ipl-vol", GOTO="chreipl_fcp_mpath_end"
LABEL="chreipl_fcp_mpath_try_change_ipl_path"
LABEL="chreipl_fcp_mpath_end"