From b31f3fe0d1bea66078ef65c736df03a150f74607 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Thu, 26 Apr 2018 15:03:29 +0200 Subject: [PATCH] 95iscsi: Replace iscsistart with iscsid This allows to setup multiple paths to targets, which is required for iscsi multipath. --- modules.d/95iscsi/cleanup-iscsi.sh | 2 +- modules.d/95iscsi/iscsiroot.sh | 161 +++++++++++++++--------- modules.d/95iscsi/iscsistart-flocked.sh | 5 - modules.d/95iscsi/module-setup.sh | 81 ++++++++++-- modules.d/95iscsi/parse-iscsiroot.sh | 12 +- 5 files changed, 187 insertions(+), 74 deletions(-) delete mode 100755 modules.d/95iscsi/iscsistart-flocked.sh diff --git a/modules.d/95iscsi/cleanup-iscsi.sh b/modules.d/95iscsi/cleanup-iscsi.sh index e97d65ac..bfc8aefc 100755 --- a/modules.d/95iscsi/cleanup-iscsi.sh +++ b/modules.d/95iscsi/cleanup-iscsi.sh @@ -1,4 +1,4 @@ #!/bin/sh -[ -e /sys/module/bnx2i ] && killproc iscsiuio +[ -z "${DRACUT_SYSTEMD}" ] && [ -e /sys/module/bnx2i ] && killproc iscsiuio diff --git a/modules.d/95iscsi/iscsiroot.sh b/modules.d/95iscsi/iscsiroot.sh index f7c99a60..3a2463f5 100755 --- a/modules.d/95iscsi/iscsiroot.sh +++ b/modules.d/95iscsi/iscsiroot.sh @@ -36,31 +36,52 @@ iroot=${iroot#:} # figured out a way how to check whether this is built-in or not modprobe crc32c 2>/dev/null -if [ -e /sys/module/bnx2i ] && ! [ -e /tmp/iscsiuio-started ]; then +if [ -z "${DRACUT_SYSTEMD}" ] && [ -e /sys/module/bnx2i ] && ! [ -e /tmp/iscsiuio-started ]; then iscsiuio > /tmp/iscsiuio-started fi +#set value for initial login retry +set_login_retries() { + local default retries + default=2 + retries=$(getarg rd.iscsilogin.retries) + return ${retries:-$default} +} + handle_firmware() { - if ! iscsistart-flocked -f; then - warn "iscistart: Could not get list of targets from firmware. Skipping." - echo 'skipped' > "/tmp/iscsistarted-firmware" - return 0 + local ifaces retry + + # 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=( $(echo /sys/firmware/ibft/ethernet*) ) + retry=$(cat /tmp/session-retry) + + if [ $retry -lt ${#ifaces[*]} ]; then + let retry++ + echo $retry > /tmp/session-retry + return 1 + else + rm /tmp/session-retry + fi + + if ! iscsiadm -m fw -l; then + warn "iscsiadm: Log-in to iscsi target failed" + else + need_shutdown + fi fi - - for p in $(getargs rd.iscsi.param -d iscsi_param); do - iscsi_param="$iscsi_param --param $p" - done - - if ! iscsistart-flocked -b $iscsi_param; then - warn "'iscsistart -b $iscsi_param' failed with return code $?" - fi - + [ -d /sys/class/iscsi_session ] || return 1 echo 'started' > "/tmp/iscsistarted-iscsi:" echo 'started' > "/tmp/iscsistarted-firmware" - need_shutdown return 0 } @@ -72,13 +93,13 @@ handle_netroot() local iscsi_username iscsi_password local iscsi_in_username iscsi_in_password local iscsi_iface_name iscsi_netdev_name - local iscsi_param + local iscsi_param param local p # 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.name -d iscsi_target_name=) + arg=$(getargs rd.iscsi.target.name -d iscsi_target_name=) [ -n "$arg" ] && iscsi_target_name=$arg arg=$(getarg rd.iscsi.target.ip -d iscsi_target_ip) [ -n "$arg" ] && iscsi_target_ip=$arg @@ -95,7 +116,7 @@ handle_netroot() 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 - iscsi_param="$iscsi_param --param $p" + iscsi_param="$iscsi_param $p" done parse_iscsi_root "$1" || return 1 @@ -105,6 +126,15 @@ handle_netroot() ip route get "$iscsi_target_ip" >/dev/null 2>&1 || return 0 fi + #limit iscsistart login retries + if [[ ! "$iscsi_param" =~ "node.session.initial_login_retry_max" ]]; then + set_login_retries + retries=$? + 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 @@ -117,6 +147,11 @@ handle_netroot() 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 @@ -133,6 +168,11 @@ handle_netroot() 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 @@ -153,6 +193,11 @@ handle_netroot() 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 # FIXME $iscsi_protocol?? @@ -168,46 +213,37 @@ handle_netroot() echo "iscsi_lun=$iscsi_lun . /bin/mount-lun.sh " > $hookdir/mount/01-$$-iscsi.sh fi - if [ -n "$DRACUT_SYSTEMD" ] && command -v systemd-run >/dev/null 2>&1; then - netroot_enc=$(systemd-escape "iscsistart_${1}") - status=$(systemctl is-active "$netroot_enc" 2>/dev/null) - is_active=$? - if [ $is_active -ne 0 ]; then - if [ "$status" != "activating" ] && ! systemctl is-failed "$netroot_enc" >/dev/null 2>&1; then - systemd-run --no-block --service-type=oneshot --remain-after-exit --quiet \ - --description="Login iSCSI Target $iscsi_target_name" \ - -p 'DefaultDependencies=no' \ - --unit="$netroot_enc" -- \ - $(command -v iscsistart-flocked) \ - -i "$iscsi_initiator" -t "$iscsi_target_name" \ - -g "$iscsi_target_group" -a "$iscsi_target_ip" \ - -p "$iscsi_target_port" \ - ${iscsi_username:+-u "$iscsi_username"} \ - ${iscsi_password:+-w "$iscsi_password"} \ - ${iscsi_in_username:+-U "$iscsi_in_username"} \ - ${iscsi_in_password:+-W "$iscsi_in_password"} \ - ${iscsi_iface_name:+--param "iface.iscsi_ifacename=$iscsi_iface_name"} \ - ${iscsi_netdev_name:+--param "iface.net_ifacename=$iscsi_netdev_name"} \ - ${iscsi_param} >/dev/null 2>&1 \ - && { > $hookdir/initqueue/work ; } - else - systemctl --no-block restart "$netroot_enc" >/dev/null 2>&1 \ - && { > $hookdir/initqueue/work ; } - fi - fi + ### ToDo: Upstream calls systemd-run - Shall we, do we have to port this? + + if iscsiadm -m node; then + targets=$(iscsiadm -m node | sed 's/^.*iqn/iqn/') else - iscsistart-flocked -i "$iscsi_initiator" -t "$iscsi_target_name" \ - -g "$iscsi_target_group" -a "$iscsi_target_ip" \ - -p "$iscsi_target_port" \ - ${iscsi_username:+-u "$iscsi_username"} \ - ${iscsi_password:+-w "$iscsi_password"} \ - ${iscsi_in_username:+-U "$iscsi_in_username"} \ - ${iscsi_in_password:+-W "$iscsi_in_password"} \ - ${iscsi_iface_name:+--param "iface.iscsi_ifacename=$iscsi_iface_name"} \ - ${iscsi_netdev_name:+--param "iface.net_ifacename=$iscsi_netdev_name"} \ - ${iscsi_param} \ - && { > $hookdir/initqueue/work ; } + targets=$(iscsiadm -m discovery -t st -p $iscsi_target_ip:${iscsi_target_port:+$iscsi_target_port} | sed 's/^.*iqn/iqn/') + [ -z "$targets" ] && echo "Target discovery to $iscsi_target_ip:${iscsi_target_port:+$iscsi_target_port} failed with status $?" && exit 1 fi + + for target in $iscsi_target_name; do + if [[ "$targets" =~ "$target" ]]; then + if [ -n "$iscsi_iface_name" ]; then + $(iscsiadm -m iface -I $iscsi_iface_name --op=new) + [ -n "$iscsi_initiator" ] && $(iscsiadm -m iface -I $iscsi_iface_name --op=update --name=iface.initiatorname --value=$iscsi_initiator) + [ -n "$iscsi_netdev_name" ] && $(iscsiadm -m iface -I $iscsi_iface_name --op=update --name=iface.net_ifacename --value=$iscsi_netdev_name) + COMMAND="iscsiadm -m node -T $target -p $iscsi_target_ip${iscsi_target_port:+:$iscsi_target_port} -I $iscsi_iface_name --op=update" + else + COMMAND="iscsiadm -m node -T $target -p $iscsi_target_ip${iscsi_target_port:+:$iscsi_target_port} --op=update" + fi + $($COMMAND --name=node.startup --value=onboot) + [ -n "$iscsi_username" ] && $($COMMAND --name=node.session.auth.username --value=$iscsi_username) + [ -n "$iscsi_password" ] && $($COMMAND --name=node.session.auth.password --value=$iscsi_password) + [ -n "$iscsi_in_username" ] && $($COMMAND --name=node.session.auth.username_in --value=$iscsi_in_username) + [ -n "$iscsi_in_password" ] && $($COMMAND --name=node.session.auth.password_in --value=$iscsi_in_password) + [ -n "$iscsi_param" ] && for param in $iscsi_param; do $($COMMAND --name=${param%=*} --value=${param#*=}); done + fi + done + + iscsiadm -m node -L onboot || : + > $hookdir/initqueue/work + netroot_enc=$(str_replace "$1" '/' '\2f') echo 'started' > "/tmp/iscsistarted-iscsi:${netroot_enc}" return 0 @@ -215,12 +251,21 @@ handle_netroot() ret=0 -if [ "$netif" != "timeout" ] && getargbool 1 rd.iscsi.waitnet; then +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" ]; then + if [ "$netif" = "timeout" ] || [ "$netif" = "online" ] || [ "$netif" = "dummy" ]; then + [ -f /tmp/session-retry ] || echo 1 > /tmp/session-retry handle_firmware ret=$? fi diff --git a/modules.d/95iscsi/iscsistart-flocked.sh b/modules.d/95iscsi/iscsistart-flocked.sh deleted file mode 100755 index 6366335d..00000000 --- a/modules.d/95iscsi/iscsistart-flocked.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -{ - flock -e 9 - iscsistart "$@" -} 9>/tmp/.iscsi_lock diff --git a/modules.d/95iscsi/module-setup.sh b/modules.d/95iscsi/module-setup.sh index 5c47750a..d8405fce 100755 --- a/modules.d/95iscsi/module-setup.sh +++ b/modules.d/95iscsi/module-setup.sh @@ -4,7 +4,7 @@ check() { local _rootdev # If our prerequisites are not met, fail anyways. - require_binaries iscsistart hostname iscsi-iname || return 1 + require_binaries hostname iscsi-iname iscsiadm iscsid || return 1 # If hostonly was requested, fail the check if we are not actually # booting from root. @@ -61,7 +61,7 @@ install_ibft() { fi if [ -d ${d}/initiator ] ; then if [ ${d##*/} = "ibft" ] && [ "$ibft_mod" != "bnx2i" ] ; then - echo -n "ip=ibft " + echo -n "rd.iscsi.ibft=1 " fi echo -n "rd.iscsi.firmware=1" fi @@ -70,7 +70,7 @@ install_ibft() { install_iscsiroot() { local devpath=$1 - local scsi_path iscsi_lun session c d conn + local scsi_path iscsi_lun session c d conn host flash local iscsi_session iscsi_address iscsi_port iscsi_targetname iscsi_tpgt scsi_path=${devpath%%/block*} @@ -81,6 +81,19 @@ install_iscsiroot() { [ "$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 + is_boot=$(cat $flash/is_boot_target) + if [ $is_boot -eq 1 ] ; then + # qla4xxx flashnode session; skip iBFT discovery + iscsi_initiator=$(cat /sys/class/iscsi_host/${iscsi_host}/initiatorname) + echo "rd.iscsi.initiator=${iscsi_initiator}" + return; + fi + done for d in ${session}/* ; do case $d in @@ -104,7 +117,14 @@ install_iscsiroot() { [ -z "$iscsi_address" ] && return local_address=$(ip -o route get to $iscsi_address | sed -n 's/.*src \([0-9a-f.:]*\).*/\1/p') ifname=$(ip -o route get to $iscsi_address | sed -n 's/.*dev \([^ ]*\).*/\1/p') - printf 'ip=%s:static ' ${ifname} + + #follow ifcfg settings for boot protocol + bootproto=$(sed -n "/BOOTPROTO/s/BOOTPROTO='\([[:alpha:]]*6\?\)4\?'/\1/p" /etc/sysconfig/network/ifcfg-$ifname) + if [ $bootproto ]; then + printf 'ip=%s:%s ' ${ifname} ${bootproto} + else + printf 'ip=%s:static ' ${ifname} + fi if [ -e /sys/class/net/$ifname/address ] ; then ifmac=$(cat /sys/class/net/$ifname/address) @@ -128,6 +148,7 @@ install_iscsiroot() { # 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 } @@ -159,15 +180,14 @@ installkernel() { local _arch=$(uname -m) local _funcs='iscsi_register_transport' - instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi + instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi qedi hostonly="" instmods iscsi_tcp iscsi_ibft crc32c iscsi_boot_sysfs if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then _s390drivers="=drivers/s390/scsi" fi - dracut_instmods -o -s "$_funcs" "=drivers/scsi" ${_s390drivers:+"$_s390drivers"} - + dracut_instmods -o -s ${_funcs} =drivers/scsi ${_s390drivers:+"$_s390drivers"} } # called by dracut @@ -184,9 +204,22 @@ cmdline() { # called by dracut install() { - inst_multiple umount iscsistart hostname iscsi-iname inst_multiple -o iscsiuio inst_libdir_file 'libgcc_s.so*' + inst_multiple umount hostname iscsi-iname iscsiadm iscsid + + ln -sf $systemdsystemunitdir/iscsid.socket $systemdsystemunitdir/sockets.target.wants/iscsid.socket + ln -sf $systemdsystemunitdir/iscsiuio.socket $systemdsystemunitdir/sockets.target.wants/iscsiuio.socket + + 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 + + [[ -d /etc/iscsi ]] && inst_dir $(/usr/bin/find /etc/iscsi) # Detect iBFT and perform mandatory steps if [[ $hostonly_cmdline == "yes" ]] ; then @@ -194,12 +227,42 @@ install() { [[ $_iscsiconf ]] && printf "%s\n" "$_iscsiconf" >> "${initdir}/etc/cmdline.d/95iscsi.conf" fi - inst "$moddir/iscsistart-flocked.sh" "/bin/iscsistart-flocked" 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/iscsid.service \ + $systemdsystemunitdir/iscsid.socket \ + $systemdsystemunitdir/iscsiuio.service \ + $systemdsystemunitdir/iscsiuio.socket \ + iscsiadm iscsid + + mkdir -p "${initdir}/$systemdsystemunitdir/sockets.target.wants" + for i in \ + iscsiuio.socket \ + ; do + ln_r "$systemdsystemunitdir/${i}" "$systemdsystemunitdir/sockets.target.wants/${i}" + done + + mkdir -p "${initdir}/$systemdsystemunitdir/basic.target.wants" + for i in \ + iscsid.service \ + iscsiuio.service \ + ; do + ln_r "$systemdsystemunitdir/${i}" "$systemdsystemunitdir/basic.target.wants/${i}" + done + + # Make sure iscsid is started after dracut-cmdline and ready for the initqueue + mkdir -p "${initdir}/$systemdsystemunitdir/iscsid.service.d" + ( + echo "[Unit]" + echo "After=dracut-cmdline.service" + echo "Before=dracut-initqueue.service" + ) > "${initdir}/$systemdsystemunitdir/iscsid.service.d/dracut.conf" fi inst_dir /var/lib/iscsi dracut_need_initqueue diff --git a/modules.d/95iscsi/parse-iscsiroot.sh b/modules.d/95iscsi/parse-iscsiroot.sh index c8c66ccf..f884e684 100755 --- a/modules.d/95iscsi/parse-iscsiroot.sh +++ b/modules.d/95iscsi/parse-iscsiroot.sh @@ -96,7 +96,7 @@ fi initqueue --unique --onetime --timeout /sbin/iscsiroot timeout "$netroot" "$NEWROOT" -initqueue --onetime modprobe --all -b -q qla4xxx cxgb3i cxgb4i bnx2i be2iscsi +initqueue --onetime modprobe --all -b -q qla4xxx cxgb3i cxgb4i bnx2i be2iscsi qedi # ISCSI actually supported? if ! [ -e /sys/module/iscsi_tcp ]; then @@ -116,6 +116,11 @@ if arg=$(getarg rd.iscsi.initiator -d iscsi_initiator=) && [ -n "$arg" ] && ! [ 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 fi @@ -128,6 +133,11 @@ if [ -z $iscsi_initiator ] && [ -f /sys/firmware/ibft/initiator/initiator-name ] 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