From 9d0d0d013c7edae43a4ebc5f46bf2e7a4f127654 Mon Sep 17 00:00:00 2001
From: "sreejit.mohanan" <sreejit.mohanan@nutanix.com>
Date: Fri, 17 Feb 2023 18:04:03 -0800
Subject: [PATCH] fence_scsi: fix registration handling if ISID conflicts 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.

fence_scsi treats same key as a tip to ignore issuing registration
to the device but if the device was registered using a different
ISID, the key would be the same but the I_T Nexus (new ISID) would
not have access to the device.

Fixing this by preempting the old key and replacing with the current
one.
---
 agents/scsi/fence_scsi.py | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index f9e6823b..85e4f29e 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -137,12 +137,41 @@ def register_dev(options, dev):
 		for slave in get_mpath_slaves(dev):
 			register_dev(options, slave)
 		return True
-	if get_reservation_key(options, dev, False) == options["--key"]:
-		return True
+
+	# Check if any registration exists for the key already. We track this in
+	# order to decide whether the existing registration needs to be cleared.
+	# 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):
+		registration_key_exists = True
+	if not register_helper(options, options["--key"], dev):
+		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):
+			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)
+	return True
+
+# cancel registration without aborting tasks
+def preempt(options, host, dev):
+	reset_dev(options,dev)
+	cmd = options["--sg_persist-path"] + " -n -o -P -T 5 -K " + host + " -S " + options["--key"] + " -d " + dev
+	return not bool(run_cmd(options, cmd)["rc"])
+
+# helper function to send the register command
+def register_helper(options, host, dev):
 	reset_dev(options, dev)
 	cmd = options["--sg_persist-path"] + " -n -o -I -S " + options["--key"] + " -d " + dev
 	cmd += " -Z" if "--aptpl" in options else ""
-	#cmd return code != 0 but registration can be successful
 	return not bool(run_cmd(options, cmd)["rc"])
 
 
-- 
2.25.1

