mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
In the final step of the udev rules toolset, we either know that the
current event subject is the re-IPL target, a dm-multipath device with
the re-IPL target, or represents the same volume based on its WWID. As
such it is a candidate to replace the current re-IPL target.
The new helper `chreipl-fcp-mpath-try-change-ipl-path` will use the
subject itself - in case it is a single scsi disk -, or the dm-multipath
device, to test whether there is a path in a good state.
"Good state" is based on the zfcp device driver state
(<SDEV>/zfcp_failed, <SDEV>/zfcp_in_recovery), the scsi_transport_fc
port state (<SDEV>/../../fc_remote_ports/rport-*/port_state), and the
scsi device state (<SDEV>/state). A path is only considered if they all
indicate a device in good conditions.
If such a path is found, the helper will try to set it as new re-IPL
target regardless of whether the current re-IPL is still in good shape
or not. This is by design, and done to reduce complexity in further
state checking, and prevention of races with overlapping events in udev
(when executing in parallel workers).
Whenever a new re-IPL target is selected and set in
/sys/firmware/reipl/fcp/{device,wwpn,lun}, the helper will also update
the records in the ID-file - otherwise they might appear as stale, when
they aren't.
This step in the udev rule processing might also result in log messages
written to the syslog (using the utility `logger` from util-linux;
writing to /dev/log).
In case the re-IPL target is changed, a message with level notice is
logged, informing about the new target.
In case no good path is found as part of a dm-multipath device, a
message with level critical is logged, as it might result in a failed
re-IPL if no path is available.
Lastly, when changing the information in /sys/firmware/reipl/fcp/ fails
for whatever reason, a message with level alert is logged, as the
written information might be inconsistent and must be audited/corrected
manually by an operator.
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>
159 lines
5.5 KiB
Bash
159 lines
5.5 KiB
Bash
#!/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
|
|
# GNU coreutils:
|
|
# - truncate
|
|
# util-linux:
|
|
# - hexdump
|
|
|
|
# Try to change the current re-IPL target to a dfferent, operational path to
|
|
# the same volume.
|
|
#
|
|
# Makes use of udev event environment variables:
|
|
# DM_UUID
|
|
# SUBSYSTEM
|
|
# DEVPATH
|
|
# CHREIPL_FCP_MPATH_IS_TGT
|
|
|
|
# shellcheck disable=SC2034
|
|
declare -gr debug_trace_tag=15tcip
|
|
# shellcheck disable=SC1091
|
|
source '@chreiplzfcpmp-lib@' || exit 127
|
|
|
|
function apply_ipl_information() {
|
|
local sdev_wwid="${1}"
|
|
local sdev_busid="${2}" sdev_wwpn="${3}" sdev_lun="${4}"
|
|
local ipl_type="${5}" ipl_busid="${6}" ipl_wwpn="${7}" ipl_lun="${8}"
|
|
local -a records
|
|
local try_update_id_file=true
|
|
|
|
[ "${ipl_type}" = "fcp" ] || return 1
|
|
|
|
[[ "${sdev_busid}" =~ ^[[:xdigit:]]{1,3}\.[[:xdigit:]]\.[[:xdigit:]]{1,4}$ ]] \
|
|
|| return 2
|
|
[[ "${sdev_wwpn}" =~ ^0x[[:xdigit:]]{16}$ ]] || return 3
|
|
[[ "${sdev_lun}" =~ ^0x[[:xdigit:]]{16}$ ]] || return 4
|
|
|
|
# After updating the firmware re-IPL information below we also try to
|
|
# update the information stored in the ID file (necessary, so it
|
|
# contains the correct Device-Bus-ID/WWPN/LUN after the update). For
|
|
# the update of the ID file we try to grab an exclusive lock, so there
|
|
# are no overlapping reads/writes.
|
|
#
|
|
# In case we can't get the lock because the ID file is missing, but we
|
|
# have a direct TGT match, we may still try to change the re-IPL
|
|
# information, but skip the ID file update.
|
|
#
|
|
# "direct match" means, the event subject is either the SDEV that is
|
|
# currently set as re-IPL target, or it is the dm-multipath device that
|
|
# currently contains the re-IPL target.
|
|
if ! id_file_lock_exclusive_no_create; then
|
|
# rc == 1 --> could not read ${ID_FILE}
|
|
[ "${PIPESTATUS[0]}" -eq 1 ] || return 5
|
|
# if true, we are dealing with a direct TGT match
|
|
[ "${CHREIPL_FCP_MPATH_IS_TGT}" = "true" ] || return 6
|
|
try_update_id_file=false
|
|
fi
|
|
|
|
# If we have a direct match (see in the comment above), we know
|
|
# that we have a path to the current re-IPL volume - no matter of the
|
|
# WWID. Otherwise, we got here by comparing the WWID of the event
|
|
# subject with the one recorded in the ID file; in this case we try to
|
|
# make sure the information is still up-to-date.
|
|
if [ "${CHREIPL_FCP_MPATH_IS_TGT}" != "true" ]; then
|
|
# last bail to make sure we don't overwrite user choices..
|
|
#
|
|
# XXX: this will *NOT* prevent the race completely, but at least
|
|
# make it less likely
|
|
{ readarray -d "" -t -u "${ID_FILE_LOCK}" records; } 2>/dev/null \
|
|
|| return 7
|
|
if '@DEBUG@'; then declare -p records 1>&2; fi
|
|
|
|
[ "${#records[@]}" = "4" ] || return 8
|
|
[ "${records[0]}" = "${sdev_wwid}" ] || return 9
|
|
[ "${records[1]}" = "${ipl_busid}" ] || return 10
|
|
[ "${records[2]}" = "${ipl_wwpn}" ] || return 11
|
|
[ "${records[3]}" = "${ipl_lun}" ] || return 12
|
|
fi
|
|
|
|
# Take lock so we don't see any intermediate state from other helpers
|
|
# running in parallel
|
|
firmware_lock_exclusive || return 13
|
|
|
|
if ! { echo "${sdev_busid}" >| /sys/firmware/reipl/fcp/device \
|
|
&& echo "${sdev_wwpn}" >| /sys/firmware/reipl/fcp/wwpn \
|
|
&& echo "${sdev_lun}" >| /sys/firmware/reipl/fcp/lun; };
|
|
then
|
|
log_alert "Changing the re-IPL device failed. The current re-IPL settings might be inconsistent. Check and correct the settings (see the README.md of chreipl-fcp-mpath) to make sure that the current re-IPL device is valid."
|
|
return 14
|
|
fi
|
|
|
|
firmware_unlock_exclusive
|
|
|
|
if [ "${sdev_busid}" != "${ipl_busid}" ] \
|
|
|| [ "${sdev_wwpn}" != "${ipl_wwpn}" ] \
|
|
|| [ "${sdev_lun}" != "${ipl_lun}" ]; then
|
|
log_note "Changed re-IPL path to: ${sdev_busid}:${sdev_wwpn}:${sdev_lun}."
|
|
fi
|
|
|
|
# Try to update the information in the ID file if we have gotten the
|
|
# lock for it.
|
|
if ${try_update_id_file}; then
|
|
# reset ID without removing the file
|
|
truncate --no-create --size=0 "${ID_FILE}" || return 15
|
|
echo -ne "${sdev_wwid}\x00${sdev_busid}\x00${sdev_wwpn}\x00${sdev_lun}\x00" \
|
|
>>"${ID_FILE}" || return 16
|
|
|
|
id_file_unlock_exclusive_no_create
|
|
|
|
if '@DEBUG@'; then hexdump -vC "${ID_FILE}" 1>&2; fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
declare -g SDEV=""
|
|
if [[ "${DM_UUID}" == mpath-* ]]; then
|
|
# Assume Multipath Device Mapper Device;
|
|
# e.g.: DEVPATH = /devices/virtual/block/dm-0
|
|
|
|
for sdev in /sys/"${DEVPATH}"/slaves/sd*/device; do
|
|
if sdev_test_path_state "${sdev}"; then
|
|
SDEV="${sdev}"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# No path of the multipath-device that represents the IPL volume is
|
|
# online.
|
|
if [ "${SDEV}" = "" ]; then
|
|
log_crit "The re-IPL device cannot be changed because no operational path to the re-IPL volume remains. The next re-IPL might fail unless you re-attach or enable at least one valid path to the re-IPL volume."
|
|
fi
|
|
|
|
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
|
|
if sdev_test_path_state /sys/"${DEVPATH}"/device; then
|
|
SDEV=/sys/"${DEVPATH}"/device
|
|
fi
|
|
|
|
fi
|
|
[ "${SDEV}" != "" ] || exit 0
|
|
|
|
sdev_get_wwid "${SDEV}" || exit 0
|
|
sdev_get_fcp_addressing "${SDEV}" || exit 0
|
|
firmware_get_ipl_information || exit 0
|
|
|
|
# shellcheck disable=SC2153
|
|
apply_ipl_information \
|
|
"${SDEV_WWID}" "${SDEV_BUSID}" "${SDEV_WWPN}" "${SDEV_LUN}" \
|
|
"${IPL_TYPE}" "${IPL_BUSID}" "${IPL_WWPN}" "${IPL_LUN}" || exit 0
|
|
|
|
exit 0
|