diff options
Diffstat (limited to 'modules.d/95iscsi')
-rwxr-xr-x | modules.d/95iscsi/cleanup-iscsi.sh | 5 | ||||
-rwxr-xr-x | modules.d/95iscsi/iscsiroot.sh | 322 | ||||
-rwxr-xr-x | modules.d/95iscsi/module-setup.sh | 294 | ||||
-rwxr-xr-x | modules.d/95iscsi/mount-lun.sh | 15 | ||||
-rwxr-xr-x | modules.d/95iscsi/parse-iscsiroot.sh | 156 |
5 files changed, 792 insertions, 0 deletions
diff --git a/modules.d/95iscsi/cleanup-iscsi.sh b/modules.d/95iscsi/cleanup-iscsi.sh new file mode 100755 index 0000000..8338503 --- /dev/null +++ b/modules.d/95iscsi/cleanup-iscsi.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ -z "${DRACUT_SYSTEMD}" ] && { [ -e /sys/module/bnx2i ] || [ -e /sys/module/qedi ]; }; then + killproc iscsiuio +fi diff --git a/modules.d/95iscsi/iscsiroot.sh b/modules.d/95iscsi/iscsiroot.sh new file mode 100755 index 0000000..b6af7f4 --- /dev/null +++ b/modules.d/95iscsi/iscsiroot.sh @@ -0,0 +1,322 @@ +#!/bin/sh +# +# This implementation is incomplete: Discovery mode is not implemented and +# the argument handling doesn't follow currently agreed formats. This is mainly +# because rfc4173 does not say anything about iscsi_initiator but open-iscsi's +# iscsistart needs this. +# + +type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh +type parse_iscsi_root > /dev/null 2>&1 || . /lib/net-lib.sh +type write_fs_tab > /dev/null 2>&1 || . /lib/fs-lib.sh + +PATH=/usr/sbin:/usr/bin:/sbin:/bin + +# Huh? Empty $1? +[ -z "$1" ] && exit 1 + +# Huh? Empty $2? +[ -z "$2" ] && exit 1 + +# Huh? Empty $3? This isn't really necessary, since NEWROOT isn't +# used here. But let's be consistent +[ -z "$3" ] && exit 1 + +# root is in the form root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname> +netif="$1" +iroot="$2" + +# If it's not iscsi we don't continue +[ "${iroot%%:*}" = "iscsi" ] || exit 1 + +iroot=${iroot#iscsi} +iroot=${iroot#:} + +# XXX modprobe crc32c should go in the cmdline parser, but I haven't yet +# figured out a way how to check whether this is built-in or not +modprobe crc32c 2> /dev/null + +# start iscsiuio if needed +if [ -z "${DRACUT_SYSTEMD}" ] \ + && { [ -e /sys/module/bnx2i ] || [ -e /sys/module/qedi ]; } \ + && ! [ -e /tmp/iscsiuio-started ]; then + iscsiuio + : > /tmp/iscsiuio-started +fi + +handle_firmware() { + local ifaces retry _res + + # Depending on the 'ql4xdisablesysfsboot' qla4xxx + # will be autostarting sessions without presenting + # them via the firmware interface. + # In these cases 'iscsiadm -m fw' will fail, but + # the iSCSI sessions will still be present. + if ! iscsiadm -m fw; then + warn "iscsiadm: Could not get list of targets from firmware." + else + ifaces=$( + set -- /sys/firmware/ibft/ethernet* + echo $# + ) + read -r retry < /tmp/session-retry + + if [ "$retry" -lt "$ifaces" ]; then + retry=$((retry + 1)) + echo $retry > /tmp/session-retry + return 1 + else + rm /tmp/session-retry + fi + + # check to see if we have the new iscsiadm command, + # that supports the "no-wait" (-W) flag. If so, use it. + iscsiadm -m fw -l -W 2> /dev/null + _res=$? + if [ $_res -eq 7 ]; then + # ISCSI_ERR_INVALID (7) => "-W" not supported + info "iscsiadm does not support no-wait firmware logins" + iscsiadm -m fw -l + _res=$? + fi + if [ $_res -ne 0 ]; then + warn "iscsiadm: Log-in to iscsi target failed" + else + need_shutdown + fi + fi + [ -d /sys/class/iscsi_session ] || return 1 + echo 'started' > "/tmp/iscsistarted-iscsi:" + echo 'started' > "/tmp/iscsistarted-firmware" + + return 0 +} + +handle_netroot() { + local iscsi_initiator iscsi_target_name iscsi_target_ip iscsi_target_port + local iscsi_target_group iscsirw iscsi_lun + local iscsi_username iscsi_password + local iscsi_in_username iscsi_in_password + local iscsi_iface_name iscsi_netdev_name + local iscsi_param param + local p found + local login_retry_max_seen= + + # override conf settings by command line options + arg=$(getarg rd.iscsi.initiator -d iscsi_initiator=) + [ -n "$arg" ] && iscsi_initiator=$arg + arg=$(getarg rd.iscsi.target.group -d iscsi_target_group=) + [ -n "$arg" ] && iscsi_target_group=$arg + arg=$(getarg rd.iscsi.username -d iscsi_username=) + [ -n "$arg" ] && iscsi_username=$arg + arg=$(getarg rd.iscsi.password -d iscsi_password) + [ -n "$arg" ] && iscsi_password=$arg + arg=$(getarg rd.iscsi.in.username -d iscsi_in_username=) + [ -n "$arg" ] && iscsi_in_username=$arg + arg=$(getarg rd.iscsi.in.password -d iscsi_in_password=) + [ -n "$arg" ] && iscsi_in_password=$arg + for p in $(getargs rd.iscsi.param -d iscsi_param); do + [ "${p%=*}" = node.session.initial_login_retry_max ] \ + && login_retry_max_seen=yes + iscsi_param="$iscsi_param $p" + done + + # this sets iscsi_target_name and possibly overwrites most + # parameters read from the command line above + parse_iscsi_root "$1" || return 1 + + # Bail out early, if there is no route to the destination + if is_ip "$iscsi_target_ip" && [ "$netif" != "timeout" ] && ! all_ifaces_setup && getargbool 1 rd.iscsi.testroute; then + ip route get "$iscsi_target_ip" > /dev/null 2>&1 || return 0 + fi + + #limit iscsistart login retries + if [ "$login_retry_max_seen" != yes ]; then + retries=$(getargnum 3 0 10000 rd.iscsi.login_retry_max) + if [ "$retries" -gt 0 ]; then + iscsi_param="${iscsi_param% } node.session.initial_login_retry_max=$retries" + fi + fi + + # XXX is this needed? + getarg ro && iscsirw=ro + getarg rw && iscsirw=rw + fsopts=${fsopts:+$fsopts,}${iscsirw} + + if [ -z "$iscsi_initiator" ] && [ -f /sys/firmware/ibft/initiator/initiator-name ] && ! [ -f /tmp/iscsi_set_initiator ]; then + iscsi_initiator=$(while read -r line || [ -n "$line" ]; do echo "$line"; done < /sys/firmware/ibft/initiator/initiator-name) + echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi + rm -f /etc/iscsi/initiatorname.iscsi + mkdir -p /etc/iscsi + ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi + : > /tmp/iscsi_set_initiator + if [ -n "$DRACUT_SYSTEMD" ]; then + systemctl try-restart iscsid + # FIXME: iscsid is not yet ready, when the service is :-/ + sleep 1 + fi + fi + + if [ -z "$iscsi_initiator" ]; then + [ -f /run/initiatorname.iscsi ] && . /run/initiatorname.iscsi + [ -f /etc/initiatorname.iscsi ] && . /etc/initiatorname.iscsi + [ -f /etc/iscsi/initiatorname.iscsi ] && . /etc/iscsi/initiatorname.iscsi + iscsi_initiator=$InitiatorName + fi + + if [ -z "$iscsi_initiator" ]; then + iscsi_initiator=$(iscsi-iname) + echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi + rm -f /etc/iscsi/initiatorname.iscsi + mkdir -p /etc/iscsi + ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi + : > /tmp/iscsi_set_initiator + if [ -n "$DRACUT_SYSTEMD" ]; then + systemctl try-restart iscsid + # FIXME: iscsid is not yet ready, when the service is :-/ + sleep 1 + fi + fi + + if [ -z "$iscsi_target_port" ]; then + iscsi_target_port=3260 + fi + + if [ -z "$iscsi_target_group" ]; then + iscsi_target_group=1 + fi + + if [ -z "$iscsi_lun" ]; then + iscsi_lun=0 + fi + + echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi + ln -fs /run/initiatorname.iscsi /dev/.initiatorname.iscsi + if ! [ -e /etc/iscsi/initiatorname.iscsi ]; then + mkdir -p /etc/iscsi + ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi + if [ -n "$DRACUT_SYSTEMD" ]; then + systemctl try-restart iscsid + # FIXME: iscsid is not yet ready, when the service is :-/ + sleep 1 + fi + fi + + if [ -z "$DRACUT_SYSTEMD" ]; then + iscsid + sleep 2 + fi + + # FIXME $iscsi_protocol?? + + if [ "$root" = "dhcp" ] || [ "$netroot" = "dhcp" ]; then + # if root is not specified try to mount the whole iSCSI LUN + printf 'SYMLINK=="disk/by-path/*-iscsi-*-%s", SYMLINK+="root"\n' "$iscsi_lun" >> /etc/udev/rules.d/99-iscsi-root.rules + udevadm control --reload + write_fs_tab /dev/root + wait_for_dev -n /dev/root + + # install mount script + [ -z "$DRACUT_SYSTEMD" ] \ + && echo "iscsi_lun=$iscsi_lun . /bin/mount-lun.sh " > "$hookdir"/mount/01-$$-iscsi.sh + fi + + if strglobin "$iscsi_target_ip" '*:*:*' && ! strglobin "$iscsi_target_ip" '['; then + iscsi_target_ip="[$iscsi_target_ip]" + fi + targets=$(iscsiadm -m discovery -t st -p "$iscsi_target_ip":${iscsi_target_port:+$iscsi_target_port} | { + while read -r _ target _ || [ -n "$target" ]; do + echo "$target" + done + }) + [ -z "$targets" ] && warn "Target discovery to $iscsi_target_ip:${iscsi_target_port:+$iscsi_target_port} failed with status $?" && return 1 + + found= + for target in $targets; do + if [ "$target" = "$iscsi_target_name" ]; then + if [ -n "$iscsi_iface_name" ]; then + iscsiadm -m iface -I "$iscsi_iface_name" --op=new + EXTRA=" ${iscsi_netdev_name:+--name=iface.net_ifacename --value=$iscsi_netdev_name} " + EXTRA="$EXTRA ${iscsi_initiator:+--name=iface.initiatorname --value=$iscsi_initiator} " + fi + [ -n "$iscsi_param" ] && for param in $iscsi_param; do EXTRA="$EXTRA --name=${param%=*} --value=${param#*=}"; done + + CMD="iscsiadm -m node -T $target \ + ${iscsi_iface_name:+-I $iscsi_iface_name} \ + -p $iscsi_target_ip${iscsi_target_port:+:$iscsi_target_port}" + __op="--op=update \ + --name=node.startup --value=onboot \ + ${iscsi_username:+ --name=node.session.auth.username --value=$iscsi_username} \ + ${iscsi_password:+ --name=node.session.auth.password --value=$iscsi_password} \ + ${iscsi_in_username:+--name=node.session.auth.username_in --value=$iscsi_in_username} \ + ${iscsi_in_password:+--name=node.session.auth.password_in --value=$iscsi_in_password} \ + $EXTRA" + # shellcheck disable=SC2086 + $CMD $__op + if [ "$netif" != "timeout" ]; then + $CMD --login + fi + found=yes + break + fi + done + + if [ "$netif" = "timeout" ]; then + iscsiadm -m node -L onboot || : + elif [ "$found" != yes ]; then + warn "iSCSI target \"$iscsi_target_name\" not found on portal $iscsi_target_ip:$iscsi_target_port" + return 1 + fi + : > "$hookdir"/initqueue/work + + netroot_enc=$(str_replace "$1" '/' '\2f') + echo 'started' > "/tmp/iscsistarted-iscsi:${netroot_enc}" + return 0 +} + +ret=0 + +if [ "$netif" != "timeout" ] && getargbool 0 rd.iscsi.waitnet; then + all_ifaces_setup || exit 0 +fi + +if [ "$netif" = "timeout" ] && all_ifaces_setup; then + # s.th. went wrong and the timeout script hits + # restart + systemctl restart iscsid + # damn iscsid is not ready after unit says it's ready + sleep 2 +fi + +if getargbool 0 rd.iscsi.firmware -d -y iscsi_firmware; then + if [ "$netif" = "timeout" ] || [ "$netif" = "online" ] || [ "$netif" = "dummy" ]; then + [ -f /tmp/session-retry ] || echo 1 > /tmp/session-retry + handle_firmware + ret=$? + fi +fi + +if ! [ "$netif" = "online" ]; then + # loop over all netroot parameter + if nroot=$(getarg netroot) && [ "$nroot" != "dhcp" ]; then + for nroot in $(getargs netroot); do + [ "${nroot%%:*}" = "iscsi" ] || continue + nroot="${nroot##iscsi:}" + if [ -n "$nroot" ]; then + handle_netroot "$nroot" + ret=$((ret + $?)) + fi + done + else + if [ -n "$iroot" ]; then + handle_netroot "$iroot" + ret=$? + fi + fi +fi + +need_shutdown + +# now we have a root filesystem somewhere in /dev/sd* +# let the normal block handler handle root= +exit $ret diff --git a/modules.d/95iscsi/module-setup.sh b/modules.d/95iscsi/module-setup.sh new file mode 100755 index 0000000..2bea2fc --- /dev/null +++ b/modules.d/95iscsi/module-setup.sh @@ -0,0 +1,294 @@ +#!/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 " + 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" -a -n "$iscsi_targetname" ]; then + if [ -n "$iscsi_port" -a "$iscsi_port" -eq 3260 ]; then + iscsi_port= + fi + if [ -n "$iscsi_lun" -a "$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 + + 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 +} + +# called by dracut +installkernel() { + local _arch=${DRACUT_ARCH:-$(uname -m)} + local _funcs='iscsi_register_transport' + + instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi qedi + hostonly="" instmods iscsi_tcp iscsi_ibft crc32c iscsi_boot_sysfs 8021q + + if [ "$_arch" = "s390" -o "$_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 + + inst_multiple -o \ + "$systemdsystemunitdir"/iscsid.socket \ + "$systemdsystemunitdir"/iscsid.service \ + "$systemdsystemunitdir"/iscsiuio.service \ + "$systemdsystemunitdir"/iscsiuio.socket \ + "$systemdsystemunitdir"/sockets.target.wants/iscsid.socket \ + "$systemdsystemunitdir"/sockets.target.wants/iscsiuio.socket + + if [[ $hostonly ]]; then + local -a _filenames + + inst_dir /etc/iscsi + mapfile -t -d '' _filenames < <(find /etc/iscsi -type f -print0) + inst_multiple "${_filenames[@]}" + else + inst_simple /etc/iscsi/iscsid.conf + 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/95iscsi.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 \ + iscsiadm iscsid + + for i in \ + iscsid.socket \ + iscsiuio.socket; do + $SYSTEMCTL -q --root "$initdir" enable "$i" + done + + mkdir -p "${initdir}/$systemdsystemunitdir/iscsid.service.d" + { + echo "[Unit]" + echo "DefaultDependencies=no" + echo "Conflicts=shutdown.target" + echo "Before=shutdown.target" + } > "${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" + echo "Before=shutdown.target" + } > "${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" + dracut_need_initqueue +} diff --git a/modules.d/95iscsi/mount-lun.sh b/modules.d/95iscsi/mount-lun.sh new file mode 100755 index 0000000..c186984 --- /dev/null +++ b/modules.d/95iscsi/mount-lun.sh @@ -0,0 +1,15 @@ +#!/bin/sh +if [ -z "$iscsi_lun" ]; then + iscsi_lun=0 +fi +NEWROOT=${NEWROOT:-/sysroot} + +for disk in /dev/disk/by-path/*-iscsi-*-"$iscsi_lun"; do + if mount -t "${fstype:-auto}" -o "$rflags" "$disk" "$NEWROOT"; then + if [ ! -d "$NEWROOT"/proc ]; then + umount "$disk" + continue + fi + break + fi +done diff --git a/modules.d/95iscsi/parse-iscsiroot.sh b/modules.d/95iscsi/parse-iscsiroot.sh new file mode 100755 index 0000000..7574711 --- /dev/null +++ b/modules.d/95iscsi/parse-iscsiroot.sh @@ -0,0 +1,156 @@ +#!/bin/sh +# +# Preferred format: +# root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname> +# [root=*] netroot=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname> +# +# Legacy formats: +# [net]root=[iscsi] iscsiroot=[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname> +# [net]root=[iscsi] iscsi_firmware +# +# root= takes precedence over netroot= if root=iscsi[...] +# + +# This script is sourced, so root should be set. But let's be paranoid +[ -z "$root" ] && root=$(getarg root=) +if [ -z "$netroot" ]; then + for nroot in $(getargs netroot=); do + [ "${nroot%%:*}" = "iscsi" ] && break + done + if [ "${nroot%%:*}" = "iscsi" ]; then + netroot="$nroot" + else + for nroot in $(getargs netroot=); do + [ "${nroot%%:*}" = "dhcp" ] && break + done + netroot="$nroot" + fi +fi +[ -z "$iscsiroot" ] && iscsiroot=$(getarg iscsiroot=) +[ -z "$iscsi_firmware" ] && getargbool 0 rd.iscsi.firmware -y iscsi_firmware && iscsi_firmware="1" + +[ -n "$iscsiroot" ] && [ -n "$iscsi_firmware" ] && die "Mixing iscsiroot and iscsi_firmware is dangerous" + +type write_fs_tab > /dev/null 2>&1 || . /lib/fs-lib.sh + +# Root takes precedence over netroot +if [ "${root%%:*}" = "iscsi" ]; then + if [ -n "$netroot" ]; then + echo "Warning: root takes precedence over netroot. Ignoring netroot" + fi + netroot=$root + # if root is not specified try to mount the whole iSCSI LUN + printf 'ENV{DEVTYPE}!="partition", SYMLINK=="disk/by-path/*-iscsi-*-*", SYMLINK+="root"\n' >> /etc/udev/rules.d/99-iscsi-root.rules + [ -n "$DRACUT_SYSTEMD" ] && systemctl is-active systemd-udevd && udevadm control --reload-rules + root=/dev/root + + write_fs_tab /dev/root +fi + +# If it's not empty or iscsi we don't continue +for nroot in $(getargs netroot); do + [ "${nroot%%:*}" = "iscsi" ] || continue + netroot="$nroot" + break +done + +# Root takes precedence over netroot +if [ "${root}" = "/dev/root" ] && getarg "netroot=dhcp"; then + # if root is not specified try to mount the whole iSCSI LUN + printf 'ENV{DEVTYPE}!="partition", SYMLINK=="disk/by-path/*-iscsi-*-*", SYMLINK+="root"\n' >> /etc/udev/rules.d/99-iscsi-root.rules + [ -n "$DRACUT_SYSTEMD" ] && systemctl is-active systemd-udevd && udevadm control --reload-rules +fi + +if [ -n "$iscsiroot" ]; then + [ -z "$netroot" ] && netroot=$root + + # @deprecated + echo "Warning: Argument iscsiroot is deprecated and might be removed in a future" + echo "release. See 'man dracut.kernel' for more information." + + # Accept iscsiroot argument? + [ -z "$netroot" ] || [ "$netroot" = "iscsi" ] \ + || die "Argument iscsiroot only accepted for empty root= or [net]root=iscsi" + + # Override root with iscsiroot content? + [ -z "$netroot" ] || [ "$netroot" = "iscsi" ] && netroot=iscsi:$iscsiroot +fi + +# iscsi_firmware does not need argument checking +if [ -n "$iscsi_firmware" ]; then + if [ "$root" != "dhcp" ] && [ "$netroot" != "dhcp" ]; then + [ -z "$netroot" ] && netroot=iscsi: + fi + modprobe -b -q iscsi_boot_sysfs 2> /dev/null + modprobe -b -q iscsi_ibft + # if no ip= is given, but firmware + echo "${DRACUT_SYSTEMD+systemctl is-active initrd-root-device.target || }[ -f '/tmp/iscsistarted-firmware' ]" > "$hookdir"/initqueue/finished/iscsi_started.sh + initqueue --unique --online /sbin/iscsiroot online "iscsi:" "$NEWROOT" + initqueue --unique --onetime --timeout /sbin/iscsiroot timeout "iscsi:" "$NEWROOT" + initqueue --unique --onetime --settled /sbin/iscsiroot online "iscsi:" "'$NEWROOT'" +fi + +# ISCSI actually supported? +if ! [ -e /sys/module/iscsi_tcp ]; then + modprobe -b -q iscsi_tcp || die "iscsiroot requested but kernel/initrd does not support iscsi" +fi + +modprobe --all -b -q qla4xxx cxgb3i cxgb4i bnx2i be2iscsi + +if [ -n "$netroot" ] && [ "$root" != "/dev/root" ] && [ "$root" != "dhcp" ]; then + if ! getargbool 1 rd.neednet > /dev/null || ! getarg "ip="; then + initqueue --unique --onetime --settled /sbin/iscsiroot dummy "'$netroot'" "'$NEWROOT'" + fi +fi + +if arg=$(getarg rd.iscsi.initiator -d iscsi_initiator=) && [ -n "$arg" ] && ! [ -f /run/initiatorname.iscsi ]; then + iscsi_initiator=$arg + echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi + ln -fs /run/initiatorname.iscsi /dev/.initiatorname.iscsi + rm -f /etc/iscsi/initiatorname.iscsi + mkdir -p /etc/iscsi + ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi + if [ -n "$DRACUT_SYSTEMD" ]; then + systemctl try-restart iscsid + # FIXME: iscsid is not yet ready, when the service is :-/ + sleep 1 + fi +fi + +# If not given on the cmdline and initiator-name available via iBFT +if [ -z "$iscsi_initiator" ] && [ -f /sys/firmware/ibft/initiator/initiator-name ] && ! [ -f /tmp/iscsi_set_initiator ]; then + iscsi_initiator=$(while read -r line || [ -n "$line" ]; do echo "$line"; done < /sys/firmware/ibft/initiator/initiator-name) + if [ -n "$iscsi_initiator" ]; then + echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi + rm -f /etc/iscsi/initiatorname.iscsi + mkdir -p /etc/iscsi + ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi + : > /tmp/iscsi_set_initiator + if [ -n "$DRACUT_SYSTEMD" ]; then + systemctl try-restart iscsid + # FIXME: iscsid is not yet ready, when the service is :-/ + sleep 1 + fi + fi +fi + +if [ -z "$netroot" ] || ! [ "${netroot%%:*}" = "iscsi" ]; then + return 1 +fi + +initqueue --unique --onetime --timeout /sbin/iscsiroot timeout "$netroot" "$NEWROOT" + +for nroot in $(getargs netroot); do + [ "${nroot%%:*}" = "iscsi" ] || continue + type parse_iscsi_root > /dev/null 2>&1 || . /lib/net-lib.sh + parse_iscsi_root "$nroot" || return 1 + netroot_enc=$(str_replace "$nroot" '/' '\2f') + echo "${DRACUT_SYSTEMD+systemctl is-active initrd-root-device.target || }[ -f '/tmp/iscsistarted-$netroot_enc' ]" > "$hookdir"/initqueue/finished/iscsi_started.sh +done + +# Done, all good! +# shellcheck disable=SC2034 +rootok=1 + +# Shut up init error check +[ -z "$root" ] && root="iscsi" |