#!/bin/bash # # /etc/init.d/iscsi # ### BEGIN INIT INFO # Provides: iscsi # Required-Start: $network # Should-Start: iscsitarget multipathd # Required-Stop: $network # Should-Stop: multipathd # Default-Start: 3 5 # Default-Stop: # Short-Description: iSCSI initiator daemon # Description: The iSCSI initator is used to create and # manage iSCSI connections to an iSCSI Target. # ### END INIT INFO CONFIG_FILE=/etc/iscsi/iscsid.conf DAEMON=/sbin/iscsid ISCSIADM=/sbin/iscsiadm BRCM_ISCSIUIO=/sbin/brcm_iscsiuio ARGS="-c $CONFIG_FILE -n" # Source LSB init functions . /etc/rc.status # Reset status of this service rc_reset DM_MAJOR=$(sed -n 's/\(.*\) device-mapper/\1/p' /proc/devices) iscsi_login_all_nodes() { echo -n "Setting up iSCSI targets: " $ISCSIADM -m node --loginall=automatic 2> /dev/null if [ $? == 21 ] ; then rc_failed 6 fi rc_status -v } # # Try to load all required modules prior to startup # iscsi_load_transport_modules() { loaded=$(sed -n "/^iscsi_tcp/p" /proc/modules) if [ -z "$loaded" ] ; then modprobe iscsi_tcp if [ $? = 0 ] ; then echo -n " tcp" fi fi for iface in /etc/iscsi/ifaces/*; do [ -f "$iface" ] || continue [ "$iface" = "iface.example" ] && continue # Check if the iface has been configured result=$(sed '/#.*/D;/iface.iscsi_ifacename/D;/iface.hwaddress/D;/iface.transport_name/D' $iface) if [ "$result" ] ; then mod=$(sed -n 's/iface.transport_name *= *\(.*\)/\1/p' $iface) loaded=$(sed -n "/^$mod/p" /proc/modules) if [ -z "$loaded" ] ; then modprobe $mod if [ $? = 0 ] ; then echo -n " $mod" fi fi fi done } # # Set a temporary startmode for ifdown # iscsi_modify_if_startmode() { local ifname=$1 local tmp_ifcfg=/dev/.sysconfig/network/if-$ifname if [ -e "$tmp_ifcfg" ] ; then . $tmp_ifcfg if [ "$startmode" ] ; then return fi fi : disabling shutdown on $ifname echo "startmode=nfsroot" >> $tmp_ifcfg } iscsi_get_ifacename_from_session() { local session=$1 local ifacename ifacename=$(iscsiadm -m session -r ${session##.*/session} 2> /dev/null | \ sed -n 's/iface.iscsi_ifacename = \(.*\)/\1/p') if [ -z "$ifacename" ] ; then # Check for iBFT ifacename=$(iscsiadm -m fw 2> /dev/null) if [ -n "$ifacename" ] ; then ifacename="fw" fi fi echo $ifacename } iscsi_get_hwaddress_from_iface() { local iface=$1 local hwaddress hwaddress=$(iscsiadm -m iface -I "$iface" 2> /dev/null | sed -n 's/iface.hwaddress = \(.*\)/\1/p') [ "$hwaddress" = "" ] && hwaddress= echo $hwaddress } iscsi_get_ifname_from_iface() { local iface=$1 local ifname ifname=$(iscsiadm -m iface -I "$iface" 2> /dev/null | sed -n 's/iface.net_ifacename = \(.*\)/\1/p') [ "$ifname" = "" ] && ifname= echo $ifname } iscsi_get_ipaddr_from_iface() { local iface=$1 local ipaddr ipaddr=$(iscsiadm -m iface -I "$iface" 2> /dev/null | sed -n 's/iface.ipaddress = \(.*\)/\1/p') [ "$ipaddr" = "" ] && ipaddr= echo $ipaddr } iscsi_get_ifname_from_firmware() { local hwaddress hwaddress=$(iscsiadm -m fw 2> /dev/null | sed -n 's/iface.net_ifacename = \(.*\)/\1/p') echo $hwaddress } # # cxgb3i is using the HWAddress to select # the correct interface # iscsi_get_ifname_from_hwaddress() { local hwaddress=$1 for if in /sys/class/net/*; do [ -e "$if" ] || continue read mac < $if/address [ "$mac" = "$hwaddress" ] || continue echo ${if##*/} break done } iscsi_get_ifname_from_ipaddr() { local ipaddr=$1 local ifname ifname=$(ip addr show to $ipaddr | sed -n 's/[0-9]*: \([^ :]*\): .*/\1/p') return $ifname } # # Handle 'default' interface: # It is basically impossible to determine via which # interface the iSCSI traffic will flow, so we take # the easy option and ignore _all_ active interfaces # during shutdown # iscsi_modify_all_interfaces() { ip link show up | sed -n '/.*LOOPBACK.*/d;s/[0-9]*: \(.*\): .*/\1/p' | while read ifname; do iscsi_modify_if_startmode $ifname done } # # Check iface setting and disable # affected network interfaces # iscsi_check_interface() { local session=$1 local i h n i=$(iscsi_get_ifacename_from_session $session) [ -z "$i" ] && continue if [ "$i" = "default" ] ; then iscsi_modify_all_interfaces elif [ "$i" = "fw" ] ; then n=$(iscsi_get_ifname_from_firmware) else n=$(iscsi_get_ifname_from_iface $i) if [ -z "$n" ] ; then h=$(iscsi_get_hwaddress_from_iface $i) if [ -n "$h" ] ; then n=$(iscsi_get_ifname_from_hwaddress $h) fi fi if [ -z "$n" ] ; then h=$(iscsi_get_ipaddr_from_iface $i) if [ -n "$h" ] ; then n=$(iscsi_get_ifname_from_ipaddr $h) fi fi fi if [ "$n" ] ; then iscsi_modify_if_startmode $n fi } # # Check if device 'dev' is mounted # Returns the mount point on success # iscsi_check_if_mounted() { local dev=$1 local d m t o x p cat /proc/mounts | sed -ne '/^\/dev\/.*/p' | while read d m t o x; do if [ -L "$d" ] ; then d=$(readlink -f $d) fi [ -b "$d" ] || continue b=$(ls -l $d | sed -n 's/.* \([0-9]*\), \([0-9]*\) .*/\1:\2/p') p=$(cd -P /sys/dev/block/$b ; echo $PWD) if [ -z "$p" ] ; then d=${d##/dev} p="/sys/block${d%%[0-9]*}" fi [ ! -d ${p} ] && continue if [ -e $p/partition ] ; then p=$(cd -P $p/../; echo $PWD) fi if [ "$dev" = "${p##*/}" ] ; then echo $m fi done } # # Unwind block device stack # # Stops unwinding if either no more 'holders' # are found or if a device is mounted # # Unmounts top-level device and deconfigures # all devices down the stack # # Root fs is not unmounted # iscsi_unwind_stack() { local p=$1 local d=${p##*/} local u local m if [ ! -d ${p} ] ; then return; fi m=$(iscsi_check_if_mounted $d) if [ -z "$m" ] ; then for s in $p/holders/* ; do [ -e $s ] || continue p=$(cd -P $s; echo $PWD) u=$(iscsi_unwind_stack $p) if [ "$u" ] ; then echo -n "$u " fi done else if [ "$m" = "/" ] ; then echo -n "$d " return 1 fi if ! umount $m ; then echo -n "$d " return 1 fi fi if [ "${d#dm-}" != "$d" ] ; then if ! dmsetup remove -j $DM_MAJOR -m ${d#dm-} 2> /dev/null ; then echo -n "$d " return 1 fi fi if [ "${d#md}" != "$d" ] ; then if ! mdadm --manage /dev/$d --stop 2> /dev/null ; then echo -n "$d " return 1 fi fi return 0 } # # Return all targets for a given session # iscsi_get_target() { local session=$1 local d for d in $session/device/target* ; do [ -e "$d" ] || continue echo "$d" done } # # Checks all devices presented by a target # and tries to umount them. # Skip unmounting for the root fs. # Stops on the first device which could not be unmounted # and returns the mount device of that device. # iscsi_check_target() { local t=$1 local d b m for d in $t/* ; do [ -d $d/block ] || continue for b in $d/block/sd* ; do [ -d "$b" ] || continue m=$(iscsi_unwind_stack $b) if [ -n "$m" ] ; then echo $m return 1 fi done done } # # Check all sessions for mounted devices # and shutdown the session if the affected # devices could be umounted cleanly. # If umount fails disable shutdown on all # affected network interfaces # iscsi_stop_sessions() { local t m s i i=0 for session in /sys/class/iscsi_session/session* ; do [ -e "$session" ] || continue; [ -e $session/device ] || continue t=$(iscsi_get_target $session) m=$(iscsi_check_target $t) s=${session##*/session} if [ -z "$m" ] ; then iscsiadm -m session -r ${s} -u i=$(( $i + 1 )) else iscsi_check_interface $s fi done echo $i } iscsi_list_all_nodes() { # Check for active sessions if $ISCSIADM -m session > /dev/null; then return 0 fi echo "Active connections:" $ISCSIADM -m session | while read proto num PORTAL TARGET ; do PORTAL=${PORTAL%,*} echo -e "\t$TARGET at $PORTAL" done } case "$1" in start) if checkproc $DAEMON ; then RETVAL=0 else echo -n "Starting iSCSI initiator service: " iscsi_load_transport_modules if grep -q bnx2i /proc/modules && [ -x $BRCM_ISCSIUIO ] ; then startproc $BRCM_ISCSIUIO fi startproc $DAEMON $ARGS RETVAL=$? rc_status -v fi if [ "$RETVAL" == "0" ]; then iscsi_login_all_nodes fi ;; stop) n=$(iscsi_stop_sessions) echo -n "Stopping iSCSI initiator service: " if [ "$n" ] && [ "$n" != "0" ] ; then m=$(iscsiadm -m session 2> /dev/null) if [ -z "$m" ] ; then killproc -KILL $DAEMON RETVAL=$? if grep -q bnx2i /proc/modules && [ -x $BRCM_ISCSIUIO ]; then killproc -KILL $BRCM_ISCSIUIO fi RETVAL=$? else RETVAL=1 fi rc_failed $RETVAL rc_status -v else # umounting failed, leave initiator running rc_status -s fi ;; status) echo -n "Checking for iSCSI initiator service: " if checkproc $DAEMON ; then rc_status -v iscsi_list_all_nodes else rc_failed 3 rc_status -v fi ;; restart|reload) $0 stop RETVAL=$? if [ "$RETVAL" != "0" ]; then echo "Stopping iSCSI initiator service failed, not starting" exit $RETVAL fi sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|status|restart|reload}" exit 1 ;; esac rc_exit