1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
|
#!/bin/bash
# called by dracut
check() {
# If our prerequisites are not met, fail anyways.
require_binaries iscsi-iname iscsiadm iscsid || return 1
require_kernel_modules iscsi_tcp || return 1
# If hostonly was requested, fail the check if we are not actually
# booting from root.
[[ $hostonly ]] || [[ $mount_needs ]] && {
pushd . > /dev/null
for_each_host_dev_and_slaves block_is_iscsi
local _is_iscsi=$?
popd > /dev/null || exit
[[ $_is_iscsi == 0 ]] || return 255
}
return 0
}
get_ibft_mod() {
local ibft_mac=$1
local iface_mac iface_mod
# Return the iSCSI offload module for a given MAC address
for iface_desc in $(iscsiadm -m iface | cut -f 2 -d ' '); do
iface_mod=${iface_desc%%,*}
iface_mac=${iface_desc#*,}
iface_mac=${iface_mac%%,*}
if [ "$ibft_mac" = "$iface_mac" ]; then
echo "$iface_mod"
return 0
fi
done
}
install_ibft() {
# When iBFT / iscsi_boot is detected:
# - Use 'ip=ibft' to set up iBFT network interface
# Note: bnx2i is using a different MAC address of iSCSI offloading
# so the 'ip=ibft' parameter must not be set
# - specify firmware booting cmdline parameter
for d in /sys/firmware/*; do
if [ -d "${d}"/ethernet0 ]; then
read -r ibft_mac < "${d}"/ethernet0/mac
ibft_mod=$(get_ibft_mod "$ibft_mac")
fi
if [ -z "$ibft_mod" ] && [ -d "${d}"/ethernet1 ]; then
read -r ibft_mac < "${d}"/ethernet1/mac
ibft_mod=$(get_ibft_mod "$ibft_mac")
fi
if [ -d "${d}"/initiator ]; then
if [ "${d##*/}" = "ibft" ] && [ "$ibft_mod" != "bnx2i" ]; then
echo -n "rd.iscsi.ibft=1 "
fi
echo -n "rd.iscsi.firmware=1 "
[ -z "$ibft_mod" ] || echo -n "rd.iscsi.transport=$ibft_mod "
fi
done
}
install_iscsiroot() {
local devpath=$1
local scsi_path iscsi_lun session c d conn host flash
local iscsi_session iscsi_address iscsi_port iscsi_targetname
scsi_path=${devpath%%/block*}
[ "$scsi_path" = "$devpath" ] && return 1
iscsi_lun=${scsi_path##*:}
[ "$iscsi_lun" = "$scsi_path" ] && return 1
session=${devpath%%/target*}
[ "$session" = "$devpath" ] && return 1
iscsi_session=${session##*/}
[ "$iscsi_session" = "$session" ] && return 1
host=${session%%/session*}
[ "$host" = "$session" ] && return 1
iscsi_host=${host##*/}
for flash in "${host}"/flashnode_sess-*; do
[ -f "$flash" ] || continue
[ ! -e "$flash/is_boot_target" ] && continue
read -r is_boot < "$flash"/is_boot_target
if [ "$is_boot" -eq 1 ]; then
# qla4xxx flashnode session; skip iBFT discovery
read -r iscsi_initiator < /sys/class/iscsi_host/"${iscsi_host}"/initiatorname
echo "rd.iscsi.initiator=${iscsi_initiator}"
return
fi
done
for d in "${session}"/*; do
case $d in
*connection*)
c=${d##*/}
conn=${d}/iscsi_connection/${c}
if [ -d "${conn}" ]; then
read -r iscsi_address < "${conn}"/persistent_address
read -r iscsi_port < "${conn}"/persistent_port
fi
;;
*session)
if [ -d "${d}"/"${iscsi_session}" ]; then
read -r iscsi_initiator < "${d}"/"${iscsi_session}"/initiatorname
read -r iscsi_targetname < "${d}"/"${iscsi_session}"/targetname
fi
;;
esac
done
[ -z "$iscsi_address" ] && return
ip_params_for_remote_addr "$iscsi_address"
if [ -n "$iscsi_address" ] && [ -n "$iscsi_targetname" ]; then
if [ -n "$iscsi_port" ] && [ "$iscsi_port" -eq 3260 ]; then
iscsi_port=
fi
if [ -n "$iscsi_lun" ] && [ "$iscsi_lun" -eq 0 ]; then
iscsi_lun=
fi
# In IPv6 case rd.iscsi.initatior= must pass address in [] brackets
case "$iscsi_address" in
*:*)
iscsi_address="[$iscsi_address]"
;;
esac
# Must be two separate lines, so that "sort | uniq" commands later
# can sort out rd.iscsi.initiator= duplicates
echo "rd.iscsi.initiator=${iscsi_initiator}"
echo "netroot=iscsi:${iscsi_address}::${iscsi_port}:${iscsi_lun}:${iscsi_targetname}"
echo "rd.neednet=1"
fi
return 0
}
install_softiscsi() {
[ -d /sys/firmware/ibft ] && return 0
# shellcheck disable=SC2317,SC2329 # called later by for_each_host_dev_and_slaves
is_softiscsi() {
local _dev=$1
local iscsi_dev
[[ -L "/sys/dev/block/$_dev" ]] || return
iscsi_dev=$(
cd -P /sys/dev/block/"$_dev" || exit
echo "$PWD"
)
install_iscsiroot "$iscsi_dev"
}
for_each_host_dev_and_slaves_all is_softiscsi || return 255
return 0
}
# called by dracut
depends() {
echo network rootfs-block initqueue
}
# called by dracut
installkernel() {
local _arch=${DRACUT_ARCH:-$(uname -m)}
local _funcs='iscsi_register_transport'
hostonly=$(optional_hostonly) instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi qedi
hostonly="" instmods iscsi_tcp iscsi_ibft crc32c iscsi_boot_sysfs 8021q
if [ "$_arch" = "s390" ] || [ "$_arch" = "s390x" ]; then
_s390drivers="=drivers/s390/scsi"
fi
dracut_instmods -o -s ${_funcs} =drivers/scsi ${_s390drivers:+"$_s390drivers"}
}
# called by dracut
cmdline() {
local _iscsiconf
_iscsiconf=$(install_ibft)
{
if [ "$_iscsiconf" ]; then
echo "${_iscsiconf}"
else
install_softiscsi
fi
} | sort | uniq
}
# called by dracut
install() {
inst_multiple -o iscsiuio
inst_libdir_file 'libgcc_s.so*'
inst_multiple umount iscsi-iname iscsiadm iscsid
inst_binary sort
if [[ $hostonly ]]; then
inst_simple /etc/iscsi/iscsid.conf
inst_simple /etc/iscsi/initiatorname.iscsi
fi
# Detect iBFT and perform mandatory steps
if [[ $hostonly_cmdline == "yes" ]]; then
local _iscsiconf
_iscsiconf=$(cmdline)
[[ $_iscsiconf ]] && printf "%s\n" "$_iscsiconf" >> "${initdir}/etc/cmdline.d/20-iscsi.conf"
fi
inst_hook cmdline 90 "$moddir/parse-iscsiroot.sh"
inst_hook cleanup 90 "$moddir/cleanup-iscsi.sh"
inst "$moddir/iscsiroot.sh" "/sbin/iscsiroot"
if ! dracut_module_included "systemd"; then
inst "$moddir/mount-lun.sh" "/bin/mount-lun.sh"
else
inst_multiple -o \
"$systemdsystemunitdir"/iscsi.service \
"$systemdsystemunitdir"/iscsi-init.service \
"$systemdsystemunitdir"/iscsid.service \
"$systemdsystemunitdir"/iscsid.socket \
"$systemdsystemunitdir"/iscsiuio.service \
"$systemdsystemunitdir"/iscsiuio.socket \
"$systemdsystemunitdir"/sockets.target.wants/iscsid.socket \
"$systemdsystemunitdir"/sockets.target.wants/iscsiuio.socket
sed -i '/ExecStartPre=\/usr\/lib\/open-iscsi\/startup-checks.sh/d' \
"${initdir}$systemdsystemunitdir/iscsid.service"
for i in iscsid.socket iscsiuio.socket; do
if [[ -e "${initdir}$systemdsystemunitdir/$i" ]]; then
$SYSTEMCTL -q --root "$initdir" enable "$i"
fi
done
mkdir -p "${initdir}/$systemdsystemunitdir/iscsid.service.d"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Conflicts=shutdown.target initrd-cleanup.service"
echo "Before=shutdown.target initrd-cleanup.service"
} > "${initdir}/$systemdsystemunitdir/iscsid.service.d/dracut.conf"
mkdir -p "${initdir}/$systemdsystemunitdir/iscsid.socket.d"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Conflicts=shutdown.target"
echo "Before=shutdown.target sockets.target"
} > "${initdir}/$systemdsystemunitdir/iscsid.socket.d/dracut.conf"
mkdir -p "${initdir}/$systemdsystemunitdir/iscsiuio.service.d"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Conflicts=shutdown.target initrd-cleanup.service"
echo "Before=shutdown.target initrd-cleanup.service"
} > "${initdir}/$systemdsystemunitdir/iscsiuio.service.d/dracut.conf"
mkdir -p "${initdir}/$systemdsystemunitdir/iscsiuio.socket.d"
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Conflicts=shutdown.target"
echo "Before=shutdown.target sockets.target"
} > "${initdir}/$systemdsystemunitdir/iscsiuio.socket.d/dracut.conf"
# Fedora 34 iscsid requires iscsi-shutdown.service
# which would terminate all iSCSI connections on switch root
cat > "${initdir}/$systemdsystemunitdir/iscsi-shutdown.service" << EOF
[Unit]
Description=Dummy iscsi-shutdown.service for the initrd
Documentation=man:iscsid(8) man:iscsiadm(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-remount-fs.service network.target iscsid.service iscsiuio.service
Before=remote-fs-pre.target
[Service]
Type=oneshot
RemainAfterExit=false
ExecStart=-/usr/bin/true
EOF
fi
inst_dir /var/lib/iscsi
mkdir -p "${initdir}/var/lib/iscsi/nodes"
# Fedora 34 iscsid wants a non-empty /var/lib/iscsi/nodes directory
: > "${initdir}/var/lib/iscsi/nodes/.dracut"
}
|