From 34baef58db442148b8e067509d2cdd37b7a91ef4 Mon Sep 17 00:00:00 2001
From: "sreejit.mohanan" <sreejit.mohanan@nutanix.com>
Date: Thu, 7 Sep 2023 15:57:51 -0700
Subject: [PATCH] fence_scsi: fix registration handling in device 'off'
 workflows

ISID (Initiator Session ID) belonging to I_T Nexus changes for
RHEL based on the session ID. This means that the connection to
the device can be set up with different ISID on reconnects.

When a device is powered off, fence_scsi assumes that the client
has a registration to the device and sends a preempt-and-abort
request which ends up failing due to reservation conflict.

Fixing this by registering the host key with the device and preempting
the old registration (if it exists). This should make sure that the
host is able to preempt the other key successfully.
---
 agents/scsi/fence_scsi.py | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index 42530ceb..519319bf 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -41,7 +41,7 @@ def set_status(conn, options):
 		for dev in options["devices"]:
 			is_block_device(dev)
 
-			register_dev(options, dev)
+			register_dev(options, dev, options["--key"])
 			if options["--key"] not in get_registration_keys(options, dev):
 				count += 1
 				logging.debug("Failed to register key "\
@@ -62,7 +62,7 @@ def set_status(conn, options):
 			fail_usage("Failed: keys cannot be same. You can not fence yourself.")
 		for dev in options["devices"]:
 			is_block_device(dev)
-
+			register_dev(options, dev, host_key)
 			if options["--key"] in get_registration_keys(options, dev):
 				preempt_abort(options, host_key, dev)
 
@@ -131,11 +131,11 @@ def reset_dev(options, dev):
 	return run_cmd(options, options["--sg_turs-path"] + " " + dev)["rc"]
 
 
-def register_dev(options, dev):
+def register_dev(options, dev, key):
 	dev = os.path.realpath(dev)
 	if re.search(r"^dm", dev[5:]):
 		for slave in get_mpath_slaves(dev):
-			register_dev(options, slave)
+			register_dev(options, slave, key)
 		return True
 
 	# Check if any registration exists for the key already. We track this in
@@ -143,34 +143,35 @@ def register_dev(options, dev):
 	# This is needed since the previous registration could be for a
 	# different I_T nexus (different ISID).
 	registration_key_exists = False
-	if options["--key"] in get_registration_keys(options, dev):
+	if key in get_registration_keys(options, dev):
+		logging.debug("Registration key exists for device " + dev)
 		registration_key_exists = True
-	if not register_helper(options, options["--key"], dev):
+	if not register_helper(options, dev, key):
 		return False
 
 	if registration_key_exists:
 		# If key matches, make sure it matches with the connection that
 		# exists right now. To do this, we can issue a preempt with same key
 		# which should replace the old invalid entries from the target.
-		if not preempt(options, options["--key"], dev):
+		if not preempt(options, key, dev, key):
 			return False
 
 		# If there was no reservation, we need to issue another registration
 		# since the previous preempt would clear registration made above.
-		if get_reservation_key(options, dev, False) != options["--key"]:
-			return register_helper(options, options["--key"], dev)
+		if get_reservation_key(options, dev, False) != key:
+			return register_helper(options, dev, key)
 	return True
 
-# cancel registration without aborting tasks
-def preempt(options, host, dev):
+# helper function to preempt host with 'key' using 'host_key' without aborting tasks
+def preempt(options, host_key, dev, key):
 	reset_dev(options,dev)
-	cmd = options["--sg_persist-path"] + " -n -o -P -T 5 -K " + host + " -S " + options["--key"] + " -d " + dev
+	cmd = options["--sg_persist-path"] + " -n -o -P -T 5 -K " + host_key + " -S " + key + " -d " + dev
 	return not bool(run_cmd(options, cmd)["rc"])
 
 # helper function to send the register command
-def register_helper(options, host, dev):
+def register_helper(options, dev, key):
 	reset_dev(options, dev)
-	cmd = options["--sg_persist-path"] + " -n -o -I -S " + options["--key"] + " -d " + dev
+	cmd = options["--sg_persist-path"] + " -n -o -I -S " + key + " -d " + dev
 	cmd += " -Z" if "--aptpl" in options else ""
 	return not bool(run_cmd(options, cmd)["rc"])
 
-- 
2.25.1

