From 2a29a28f781f0477fce4bc437a040520d63ab776 Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 17 Sep 2021 13:12:52 +0200 Subject: [PATCH] chreipl-fcp-mpath: if event subject is not re-IPL target, test if WWID matches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Benjamin Block Signed-off-by: Jan Höppner --- chreipl-fcp-mpath/.gitignore | 1 + chreipl-fcp-mpath/Makefile | 1 + .../chreipl-fcp-mpath-common.sh.in | 31 +++++++ .../chreipl-fcp-mpath-is-ipl-vol.in | 86 +++++++++++++++++++ .../udev/rules.d/70-chreipl-fcp-mpath.rules | 28 +++++- 5 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 chreipl-fcp-mpath/chreipl-fcp-mpath-is-ipl-vol.in diff --git a/chreipl-fcp-mpath/.gitignore b/chreipl-fcp-mpath/.gitignore index 704bf5f5..73304510 100644 --- a/chreipl-fcp-mpath/.gitignore +++ b/chreipl-fcp-mpath/.gitignore @@ -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 diff --git a/chreipl-fcp-mpath/Makefile b/chreipl-fcp-mpath/Makefile index 299ab389..dee68449 100644 --- a/chreipl-fcp-mpath/Makefile +++ b/chreipl-fcp-mpath/Makefile @@ -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 diff --git a/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh.in b/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh.in index 1ef9c25c..1b157e3a 100644 --- a/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh.in +++ b/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh.in @@ -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 # diff --git a/chreipl-fcp-mpath/chreipl-fcp-mpath-is-ipl-vol.in b/chreipl-fcp-mpath/chreipl-fcp-mpath-is-ipl-vol.in new file mode 100644 index 00000000..850357dc --- /dev/null +++ b/chreipl-fcp-mpath/chreipl-fcp-mpath-is-ipl-vol.in @@ -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 diff --git a/chreipl-fcp-mpath/udev/rules.d/70-chreipl-fcp-mpath.rules b/chreipl-fcp-mpath/udev/rules.d/70-chreipl-fcp-mpath.rules index 682a88ba..05f74c05 100644 --- a/chreipl-fcp-mpath/udev/rules.d/70-chreipl-fcp-mpath.rules +++ b/chreipl-fcp-mpath/udev/rules.d/70-chreipl-fcp-mpath.rules @@ -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"