summaryrefslogtreecommitdiff
path: root/etc
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2011-06-26 17:52:13 -0500
committerMike Christie <michaelc@cs.wisc.edu>2011-06-26 17:52:13 -0500
commitc44bdb5af6ac232adde2390990e96220d642e43d (patch)
treed135c6018c41ccb1bf9101e87f166ac10d92dfc6 /etc
parent1a8d7036d0f923ae0a6a4947f7db5104db4fcaa0 (diff)
downloadopen-iscsi-c44bdb5af6ac232adde2390990e96220d642e43d.tar.gz
Update SUSE init script
From Hannes Reinecke Rework the iSCSI shutdown logic to tear down the block device stack correctly. Signed-off-by: Hannes Reinecke <hare@suse.de> [fix merge issues] Mike Christie
Diffstat (limited to 'etc')
-rw-r--r--etc/initd/initd.suse454
1 files changed, 355 insertions, 99 deletions
diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse
index cc0baa9..a1c515a 100644
--- a/etc/initd/initd.suse
+++ b/etc/initd/initd.suse
@@ -5,20 +5,22 @@
### BEGIN INIT INFO
# Provides: iscsi
# Required-Start: $network
-# Should-Start:
-# Required-Stop:
-# Should-Stop:
+# Should-Start: iscsitarget multipathd
+# Required-Stop: $network
+# Should-Stop: multipathd
# Default-Start: 3 5
# Default-Stop:
-# Short-Description: Starts and stops the iSCSI client initiator
-#
+# Short-Description: iSCSI initiator daemon
+# Description: The iSCSI initator is used to create and
+# manage iSCSI connections to a iSCSI Target.
+#
### END INIT INFO
-PID_FILE=/var/run/iscsi.pid
CONFIG_FILE=/etc/iscsi/iscsid.conf
DAEMON=/sbin/iscsid
ISCSIADM=/sbin/iscsiadm
-ARGS="-c $CONFIG_FILE -p $PID_FILE"
+BRCM_ISCSIUIO=/sbin/brcm_iscsiuio
+ARGS="-c $CONFIG_FILE -n"
# Source LSB init functions
. /etc/rc.status
@@ -26,6 +28,8 @@ ARGS="-c $CONFIG_FILE -p $PID_FILE"
# 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: "
@@ -36,58 +40,349 @@ iscsi_login_all_nodes()
rc_status -v
}
-iscsi_logout_all_nodes()
+#
+# Try to load all required modules prior to startup
+#
+iscsi_load_transport_modules()
{
- echo -n "Closing all iSCSI connections: "
- # Logout from all sessions marked automatic
- if ! $ISCSIADM -m node --logoutall=automatic 2> /dev/null; then
- if [ $? == 21 ] ; then
- RETVAL=6
- else
- RETVAL=1
+ 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
- rc_failed $RETVAL
+ fi
fi
- rc_status -v
+ done
+}
- # Not sure whether this is still needed
- sleep 1
- return ${RETVAL:-0}
+#
+# 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_umount_all_luns()
+iscsi_get_ifacename_from_session()
{
- local d m dev p s
+ local session=$1
+ local ifacename
- cat /proc/mounts | sed -ne '/^\/dev\/.*/p' | while read d m t o x; do
- if [ "$m" = "/" ] ; then
- continue;
+ 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" = "<empty>" ] && 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" = "<empty>" ] && 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" = "<empty>" ] && 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
- dev=${d##/dev}
+ [ -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 [ "${dev##/sd}" = "$dev" ] ; then
- continue;
+ if [ "${d#dm-}" != "$d" ] ; then
+ if ! dmsetup remove -j $DM_MAJOR -m ${d#dm-} 2> /dev/null ; then
+ echo -n "$d "
+ return 1
fi
- p="/sys/block${dev%%[0-9]*}"
+ fi
- if [ ! -d ${p} ] && [ ! -d ${p}/device ] ; then
- continue;
+ if [ "${d#md}" != "$d" ] ; then
+ if ! mdadm --manage /dev/$d --stop 2> /dev/null ; then
+ echo -n "$d "
+ return 1
fi
+ fi
+ return 0
+}
- s=$(cd -P ${p}/device && echo $PWD)
+#
+# Return all targets for a given session
+#
+iscsi_get_target()
+{
+ local session=$1
+ local d
- case "$s" in
- */session[0-9]*/*)
- # This is an iSCSI device
- umount "$m"
- ;;
- esac
+ 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
@@ -101,84 +396,45 @@ iscsi_list_all_nodes()
done
}
-iscsi_discover_all_targets()
-{
- # Strip off any existing ID information
- RAW_NODE_LIST=`iscsiadm -m node | sed -nre 's/^(\[[0-9a-f]*\] )?(.*)$/\2/p'`
- # Obtain IPv4 list
- IPV4_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9]{1,3}(\.[0-9]{1,3}){3}):[^: ]* (.*)$/\1 \3/p'`
- # Now obtain IPv6 list
- IPV6_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9a-f]{1,4}(:[0-9a-f]{0,4}){6}:[0-9a-f]{1,4}):[^: ]* (.*)$/\1 \3/p'`
-
- DISC_TARGETS=""
- while read NODE_ADDR NODE_NAME; do
- [ -z "$NODE_ADDR" -a -z "$NODE_NAME" ] && continue
- NODE_ATTRS=`iscsiadm -m node -p "$NODE_ADDR" -T "$NODE_NAME"`
- NODE_STATUS=`echo "$NODE_ATTRS" | sed -nre 's/^.*node\.conn\[0\]\.startup = ([a-z]*).*$/\1/p'`
-
- if [ "$NODE_STATUS" == 'automatic' ]; then
- DISC_TARGETS=`echo "$DISC_TARGETS" | sed -re '/'"$NODE_ADDR"'/!{s/(.*)/\1 '"$NODE_ADDR"'/}'`
- fi
- done < <(echo "$IPV4_NODE_LIST"; echo "$IPV6_NODE_LIST")
-
- for TARGET_ADDR in $DISC_TARGETS; do
- echo -n "Attempting discovery on target at ${TARGET_ADDR}: "
- iscsiadm -m discovery -t st -p "$TARGET_ADDR" > /dev/null 2>&1
- if [ "$?" -ne 0 ]; then
- rc_failed 1
- rc_status -v
- return 1
- fi
- rc_status -v
- done
-}
-
case "$1" in
start)
- [ ! -d /var/lib/iscsi ] && mkdir -p /var/lib/iscsi
if checkproc $DAEMON ; then
RETVAL=0
else
echo -n "Starting iSCSI initiator service: "
- modprobe iscsi_tcp
- modprobe -q ib_iser
+ 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_discover_all_targets
- RETVAL=$?
- fi
- if [ "$RETVAL" == "0" ]; then
iscsi_login_all_nodes
fi
;;
stop)
- iscsi_umount_all_luns
- if iscsi_logout_all_nodes ; then
- iscsiadm -k 0
- RETVAL=$?
- else
- RETVAL=1
- fi
+ n=$(iscsi_stop_sessions)
echo -n "Stopping iSCSI initiator service: "
- if [ "$RETVAL" == "0" ]; then
- rm -f $PID_FILE
- status=0
- modprobe -r iscsi_tcp
- if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
- status=1
+ 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
- modprobe -q -r ib_iser
- if [ "$?" -ne "0" -a "$?" -ne "1" ]; then
- status=1
- fi
- rc_failed $status
- else
rc_failed $RETVAL
+ rc_status -v
+ else
+ # umounting failed, leave initiator running
+ rc_status -s
fi
- rc_status -v
;;
status)
echo -n "Checking for iSCSI initiator service: "
@@ -190,7 +446,7 @@ case "$1" in
rc_status -v
fi
;;
- restart)
+ restart|reload)
$0 stop
RETVAL=$?
if [ "$RETVAL" != "0" ]; then
@@ -201,7 +457,7 @@ case "$1" in
$0 start
;;
*)
- echo "Usage: $0 {start|stop|status|restart}"
+ echo "Usage: $0 {start|stop|status|restart|reload}"
exit 1
;;
esac