summaryrefslogtreecommitdiffstats
path: root/modules.d/95iscsi/iscsiroot.sh
diff options
context:
space:
mode:
Diffstat (limited to 'modules.d/95iscsi/iscsiroot.sh')
-rwxr-xr-xmodules.d/95iscsi/iscsiroot.sh322
1 files changed, 322 insertions, 0 deletions
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