--- block-iscsi 2016-02-10 01:44:19.000000000 +1100
+++ block-iscsi-lock    2016-05-05 15:42:09.557191235 +1000
@@ -31,33 +31,37 @@
     echo $1 | sed "s/^\("$2"\)//"
 }
 
-check_tools()
-{
-    if ! command -v iscsiadm > /dev/null 2>&1; then
-        fatal "Unable to find iscsiadm tool"
-    fi
-    if [ "$multipath" = "y" ] && ! command -v multipath > /dev/null 2>&1; then
-        fatal "Unable to find multipath"
-    fi
-}
-
 # Sets the following global variables based on the params field passed in as
 # a parameter: iqn, portal, auth_method, user, multipath, password
 parse_target()
 {
     # set multipath default value
     multipath="n"
-    for param in $(echo "$1" | tr "," "\n")
-    do
+    for param in $(echo "$1" | tr "," "\n"); do
         case $param in
         iqn=*)
             iqn=$(remove_label $param "iqn=")
+            if ! command -v iscsiadm > /dev/null 2>&1; then
+                fatal "Could not find iscsiadm tool."
+            fi
             ;;
         portal=*)
             portal=$(remove_label $param "portal=")
             ;;
         multipath=*)
             multipath=$(remove_label $param "multipath=")
+            if ! command -v multipath > /dev/null 2>&1; then
+                fatal "Multipath selected, but no multipath tools found"
+            fi
+            ;;
+        locktarget=*)
+            locktarget=$(remove_label $param "locktarget=")
+            if ! command -v sg_persist > /dev/null 2>&1; then
+                fatal "Locking requested but no sg_persist found"
+            fi
+            if ! command -v gethostip > /dev/null 2>&1; then
+                fatal "Locking requested but no gethostip found for key generation"
+            fi
             ;;
         esac
     done
@@ -96,38 +100,29 @@
     fi
 }
 
-# Attaches the target $iqn in $portal and sets $dev to point to the
-# multipath device
-attach()
-{
-    do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --login > /dev/null
-    find_device
-}
 
-# Discovers targets in $portal and checks that $iqn is one of those targets
-# Also sets the auth parameters to attach the device
-prepare()
+lock_device()
 {
-    # Check if target is already opened
-    iscsiadm -m session 2>&1 | grep -q "$iqn" && fatal "Device already opened"
-    # Discover portal targets
-    iscsiadm -m discovery -t st -p $portal 2>&1 | grep -q "$iqn" || \
-        fatal "No matching target iqn found"
-}
-
-# Attaches the device and writes xenstore backend entries to connect
-# the device
-add()
-{
-    attach
-    write_dev $dev
+    ## Lock the iSCSI target as Exclusive Access.
+    key=$(gethostip -x $(uname -n))
+    if ! sg_persist -d ${dev} -o -G -S ${key} > /dev/null; then
+        unlock_device
+        iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null
+        fatal "iSCSI LOCK: Failed to register with target"
+    fi
+    if ! sg_persist -d ${dev} -o -R -K ${key} -T 6 > /dev/null; then
+        unlock_device
+        iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null
+        fatal "iSCSI LOCK: Failed to set persistent reservation"
+    fi
 }
 
-# Disconnects the device
-remove()
+unlock_device()
 {
-    find_device
-    do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null
+    ## Unlock the iSCSI target.
+    key=$(gethostip -x $(uname -n))
+    sg_persist -d ${dev} -o -L -K ${key} -T 6 > /dev/null || true
+    sg_persist -d ${dev} -o -G -K ${key} -S 0 > /dev/null || true
 }

 command=$1
@@ -138,15 +133,28 @@

 parse_target "$target"

-check_tools || exit 1
-
 case $command in
 add)
-    prepare
-    add
+    # Check if target is already opened
+    iscsiadm -m session 2>&1 | grep -q "$iqn" && fatal "Device already opened"
+    # Discover portal targets
+    iscsiadm -m discovery -t st -p $portal 2>&1 | grep -q "$iqn" || \
+        fatal "No matching target iqn found"
+
+    ## Login to the iSCSI target.
+    do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --login > /dev/null
+    find_device
+    if [ "$locktarget" = "y" ]; then
+        lock_device
+    fi
+    write_dev $dev
     ;;
 remove)
-    remove
+    find_device
+    if [ "$locktarget" = "y" ]; then
+        unlock_device
+    fi
+    do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null
     ;;
 *)
     exit 1