All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] target: Fixes for AllRegistrants reservation handling
@ 2014-12-16  0:09 Nicholas A. Bellinger
  2014-12-16  0:09 ` [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants Nicholas A. Bellinger
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Nicholas A. Bellinger @ 2014-12-16  0:09 UTC (permalink / raw)
  To: target-devel
  Cc: linux-scsi, Ilias Tsitsimpis, James Bottomley, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

Hi all,

This series addresses two issues raised recently by Ilias wrt
AllRegistrants reservation handling in target code that does not
adhere to SPC-4 specification requirements.

This first is a informational change to PR-IN READ_FULL_STATUS,
that when an AllRegistrants reservation is in place, all active
registrations should be setting R_HOLDER=1 within their respective
descriptors.

The second is a functional change to PR-OUT REGISTER w/ SARK=0
operation, to avoid dropping the AllRegistrants reservation until
the last registered I_T nexus has been released.  It also ensures
that the correct reservation type + scope is retained when the
new reservation is set within __core_scsi3_complete_pro_release()
for this AllRegistrants special case.

Also, thanks to James for the extra SPC-4 clarifications.

Please review.

--nab

Nicholas Bellinger (2):
  target: Fix R_HOLDER bit usage for AllRegistrants
  target: Avoid dropping AllRegistrants reservation during unregister

 drivers/target/target_core_pr.c | 113 +++++++++++++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 25 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants
  2014-12-16  0:09 [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Nicholas A. Bellinger
@ 2014-12-16  0:09 ` Nicholas A. Bellinger
  2014-12-18  7:01   ` Lee Duncan
  2014-12-16  0:09 ` [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister Nicholas A. Bellinger
  2014-12-18 14:54 ` [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Ilias Tsitsimpis
  2 siblings, 1 reply; 9+ messages in thread
From: Nicholas A. Bellinger @ 2014-12-16  0:09 UTC (permalink / raw)
  To: target-devel
  Cc: linux-scsi, Ilias Tsitsimpis, James Bottomley, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch fixes the usage of R_HOLDER bit for an All Registrants
reservation in READ_FULL_STATUS, where only the registration who
issued RESERVE was being reported as having an active reservation.

It changes core_scsi3_pri_read_full_status() to check ahead of the
list walk of active registrations to see if All Registrants is active,
and if so set R_HOLDER bit and scope/type fields for all active
registrations.

Reported-by: Ilias Tsitsimpis <i.tsitsimpis@gmail.com>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_pr.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index f91b6a1..c4a8da5 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -3834,7 +3834,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
 	unsigned char *buf;
 	u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
 	u32 off = 8; /* off into first Full Status descriptor */
-	int format_code = 0;
+	int format_code = 0, pr_res_type = 0, pr_res_scope = 0;
+	bool all_reg = false;
 
 	if (cmd->data_length < 8) {
 		pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u"
@@ -3851,6 +3852,19 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
 	buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff);
 	buf[3] = (dev->t10_pr.pr_generation & 0xff);
 
+	spin_lock(&dev->dev_reservation_lock);
+	if (dev->dev_pr_res_holder) {
+		struct t10_pr_registration *pr_holder = dev->dev_pr_res_holder;
+
+		if (pr_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
+		    pr_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) {
+			all_reg = true;
+			pr_res_type = pr_holder->pr_res_type;
+			pr_res_scope = pr_holder->pr_res_scope;
+		}
+	}
+	spin_unlock(&dev->dev_reservation_lock);
+
 	spin_lock(&pr_tmpl->registration_lock);
 	list_for_each_entry_safe(pr_reg, pr_reg_tmp,
 			&pr_tmpl->registration_list, pr_reg_list) {
@@ -3898,14 +3912,20 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
 		 * reservation holder for PR_HOLDER bit.
 		 *
 		 * Also, if this registration is the reservation
-		 * holder, fill in SCOPE and TYPE in the next byte.
+		 * holder or there is an All Registrants reservation
+		 * active, fill in SCOPE and TYPE in the next byte.
 		 */
 		if (pr_reg->pr_res_holder) {
 			buf[off++] |= 0x01;
 			buf[off++] = (pr_reg->pr_res_scope & 0xf0) |
 				     (pr_reg->pr_res_type & 0x0f);
-		} else
+		} else if (all_reg) {
+			buf[off++] |= 0x01;
+			buf[off++] = (pr_res_scope & 0xf0) |
+				     (pr_res_type & 0x0f);
+		} else {
 			off += 2;
+		}
 
 		off += 4; /* Skip over reserved area */
 		/*
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister
  2014-12-16  0:09 [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Nicholas A. Bellinger
  2014-12-16  0:09 ` [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants Nicholas A. Bellinger
@ 2014-12-16  0:09 ` Nicholas A. Bellinger
  2014-12-18  7:02   ` Lee Duncan
  2014-12-18 14:54 ` [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Ilias Tsitsimpis
  2 siblings, 1 reply; 9+ messages in thread
From: Nicholas A. Bellinger @ 2014-12-16  0:09 UTC (permalink / raw)
  To: target-devel
  Cc: linux-scsi, Ilias Tsitsimpis, James Bottomley, Nicholas Bellinger

From: Nicholas Bellinger <nab@linux-iscsi.org>

This patch fixes an issue with AllRegistrants reservations where
an unregister operation by the I_T nexus reservation holder would
incorrectly drop the reservation, instead of waiting until the
last active I_T nexus is unregistered as per SPC-4.

This includes updating __core_scsi3_complete_pro_release() to reset
dev->dev_pr_res_holder with another pr_reg for this special case,
as well as a new 'unreg' parameter to determine when the release
is occuring from an implicit unregister, vs. explicit RELEASE.

It also adds special handling in core_scsi3_free_pr_reg_from_nacl()
to release the left-over pr_res_holder, now that pr_reg is deleted
from pr_reg_list within __core_scsi3_complete_pro_release().

Reported-by: Ilias Tsitsimpis <i.tsitsimpis@gmail.com>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/target_core_pr.c | 87 ++++++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 22 deletions(-)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index c4a8da5..703890c 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -76,7 +76,7 @@ enum preempt_type {
 };
 
 static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
-			struct t10_pr_registration *, int);
+					      struct t10_pr_registration *, int, int);
 
 static sense_reason_t
 target_scsi2_reservation_check(struct se_cmd *cmd)
@@ -1177,7 +1177,7 @@ static int core_scsi3_check_implicit_release(
 		 *    service action with the SERVICE ACTION RESERVATION KEY
 		 *    field set to zero (see 5.7.11.3).
 		 */
-		__core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0);
+		__core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0, 1);
 		ret = 1;
 		/*
 		 * For 'All Registrants' reservation types, all existing
@@ -1219,7 +1219,8 @@ static void __core_scsi3_free_registration(
 
 	pr_reg->pr_reg_deve->def_pr_registered = 0;
 	pr_reg->pr_reg_deve->pr_res_key = 0;
-	list_del(&pr_reg->pr_reg_list);
+	if (!list_empty(&pr_reg->pr_reg_list))
+		list_del(&pr_reg->pr_reg_list);
 	/*
 	 * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(),
 	 * so call core_scsi3_put_pr_reg() to decrement our reference.
@@ -1271,6 +1272,7 @@ void core_scsi3_free_pr_reg_from_nacl(
 {
 	struct t10_reservation *pr_tmpl = &dev->t10_pr;
 	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
+	bool free_reg = false;
 	/*
 	 * If the passed se_node_acl matches the reservation holder,
 	 * release the reservation.
@@ -1278,13 +1280,18 @@ void core_scsi3_free_pr_reg_from_nacl(
 	spin_lock(&dev->dev_reservation_lock);
 	pr_res_holder = dev->dev_pr_res_holder;
 	if ((pr_res_holder != NULL) &&
-	    (pr_res_holder->pr_reg_nacl == nacl))
-		__core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0);
+	    (pr_res_holder->pr_reg_nacl == nacl)) {
+		__core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0, 1);
+		free_reg = true;
+	}
 	spin_unlock(&dev->dev_reservation_lock);
 	/*
 	 * Release any registration associated with the struct se_node_acl.
 	 */
 	spin_lock(&pr_tmpl->registration_lock);
+	if (pr_res_holder && free_reg)
+		__core_scsi3_free_registration(dev, pr_res_holder, NULL, 0);
+
 	list_for_each_entry_safe(pr_reg, pr_reg_tmp,
 			&pr_tmpl->registration_list, pr_reg_list) {
 
@@ -1307,7 +1314,7 @@ void core_scsi3_free_all_registrations(
 	if (pr_res_holder != NULL) {
 		struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
 		__core_scsi3_complete_pro_release(dev, pr_res_nacl,
-				pr_res_holder, 0);
+						  pr_res_holder, 0, 0);
 	}
 	spin_unlock(&dev->dev_reservation_lock);
 
@@ -2103,13 +2110,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
 		/*
 		 * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus.
 		 */
-		pr_holder = core_scsi3_check_implicit_release(
-				cmd->se_dev, pr_reg);
+		type = pr_reg->pr_res_type;
+		pr_holder = core_scsi3_check_implicit_release(cmd->se_dev,
+							      pr_reg);
 		if (pr_holder < 0) {
 			ret = TCM_RESERVATION_CONFLICT;
 			goto out;
 		}
-		type = pr_reg->pr_res_type;
 
 		spin_lock(&pr_tmpl->registration_lock);
 		/*
@@ -2383,23 +2390,59 @@ static void __core_scsi3_complete_pro_release(
 	struct se_device *dev,
 	struct se_node_acl *se_nacl,
 	struct t10_pr_registration *pr_reg,
-	int explicit)
+	int explicit,
+	int unreg)
 {
 	struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
 	char i_buf[PR_REG_ISID_ID_LEN];
+	int pr_res_type = 0, pr_res_scope = 0;
 
 	memset(i_buf, 0, PR_REG_ISID_ID_LEN);
 	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
 	/*
 	 * Go ahead and release the current PR reservation holder.
+	 * If an All Registrants reservation is currently active and
+	 * a unregister operation is requested, replace the current
+	 * dev_pr_res_holder with another active registration.
 	 */
-	dev->dev_pr_res_holder = NULL;
+	if (dev->dev_pr_res_holder) {
+		pr_res_type = dev->dev_pr_res_holder->pr_res_type;
+		pr_res_scope = dev->dev_pr_res_holder->pr_res_scope;
+		dev->dev_pr_res_holder->pr_res_type = 0;
+		dev->dev_pr_res_holder->pr_res_scope = 0;
+		dev->dev_pr_res_holder->pr_res_holder = 0;
+		dev->dev_pr_res_holder = NULL;
+	}
+	if (!unreg)
+		goto out;
 
-	pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared"
-		" reservation holder TYPE: %s ALL_TG_PT: %d\n",
-		tfo->get_fabric_name(), (explicit) ? "explicit" : "implicit",
-		core_scsi3_pr_dump_type(pr_reg->pr_res_type),
-		(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+	spin_lock(&dev->t10_pr.registration_lock);
+	list_del_init(&pr_reg->pr_reg_list);
+	/*
+	 * If the I_T nexus is a reservation holder, the persistent reservation
+	 * is of an all registrants type, and the I_T nexus is the last remaining
+	 * registered I_T nexus, then the device server shall also release the
+	 * persistent reservation.
+	 */
+	if (!list_empty(&dev->t10_pr.registration_list) &&
+	    ((pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+	     (pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) {
+		dev->dev_pr_res_holder =
+			list_entry(dev->t10_pr.registration_list.next,
+				   struct t10_pr_registration, pr_reg_list);
+		dev->dev_pr_res_holder->pr_res_type = pr_res_type;
+		dev->dev_pr_res_holder->pr_res_scope = pr_res_scope;
+		dev->dev_pr_res_holder->pr_res_holder = 1;
+	}
+	spin_unlock(&dev->t10_pr.registration_lock);
+out:
+	if (!dev->dev_pr_res_holder) {
+		pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared"
+			" reservation holder TYPE: %s ALL_TG_PT: %d\n",
+			tfo->get_fabric_name(), (explicit) ? "explicit" :
+			"implicit", core_scsi3_pr_dump_type(pr_res_type),
+			(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+	}
 	pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n",
 		tfo->get_fabric_name(), se_nacl->initiatorname,
 		i_buf);
@@ -2530,7 +2573,7 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
 	 *    server shall not establish a unit attention condition.
 	 */
 	__core_scsi3_complete_pro_release(dev, se_sess->se_node_acl,
-			pr_reg, 1);
+					  pr_reg, 1, 0);
 
 	spin_unlock(&dev->dev_reservation_lock);
 
@@ -2618,7 +2661,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)
 	if (pr_res_holder) {
 		struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
 		__core_scsi3_complete_pro_release(dev, pr_res_nacl,
-			pr_res_holder, 0);
+						  pr_res_holder, 0, 0);
 	}
 	spin_unlock(&dev->dev_reservation_lock);
 	/*
@@ -2677,7 +2720,7 @@ static void __core_scsi3_complete_pro_preempt(
 	 */
 	if (dev->dev_pr_res_holder)
 		__core_scsi3_complete_pro_release(dev, nacl,
-				dev->dev_pr_res_holder, 0);
+						  dev->dev_pr_res_holder, 0, 0);
 
 	dev->dev_pr_res_holder = pr_reg;
 	pr_reg->pr_res_holder = 1;
@@ -2922,8 +2965,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
 	 */
 	if (pr_reg_n != pr_res_holder)
 		__core_scsi3_complete_pro_release(dev,
-				pr_res_holder->pr_reg_nacl,
-				dev->dev_pr_res_holder, 0);
+						  pr_res_holder->pr_reg_nacl,
+						  dev->dev_pr_res_holder, 0, 0);
 	/*
 	 * b) Remove the registrations for all I_T nexuses identified
 	 *    by the SERVICE ACTION RESERVATION KEY field, except the
@@ -3386,7 +3429,7 @@ after_iport_check:
 	 *    holder (i.e., the I_T nexus on which the
 	 */
 	__core_scsi3_complete_pro_release(dev, pr_res_nacl,
-			dev->dev_pr_res_holder, 0);
+					  dev->dev_pr_res_holder, 0, 0);
 	/*
 	 * g) Move the persistent reservation to the specified I_T nexus using
 	 *    the same scope and type as the persistent reservation released in
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants
  2014-12-16  0:09 ` [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants Nicholas A. Bellinger
@ 2014-12-18  7:01   ` Lee Duncan
  0 siblings, 0 replies; 9+ messages in thread
From: Lee Duncan @ 2014-12-18  7:01 UTC (permalink / raw)
  To: Nicholas A. Bellinger, target-devel
  Cc: linux-scsi, Ilias Tsitsimpis, James Bottomley, Nicholas Bellinger

On 12/15/2014 04:09 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
> 
> This patch fixes the usage of R_HOLDER bit for an All Registrants
> reservation in READ_FULL_STATUS, where only the registration who
> issued RESERVE was being reported as having an active reservation.
> 
> It changes core_scsi3_pri_read_full_status() to check ahead of the
> list walk of active registrations to see if All Registrants is active,
> and if so set R_HOLDER bit and scope/type fields for all active
> registrations.
> 
> Reported-by: Ilias Tsitsimpis <i.tsitsimpis@gmail.com>
> Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
>  drivers/target/target_core_pr.c | 26 +++++++++++++++++++++++---
>  1 file changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
> index f91b6a1..c4a8da5 100644
> --- a/drivers/target/target_core_pr.c
> +++ b/drivers/target/target_core_pr.c
> @@ -3834,7 +3834,8 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
>  	unsigned char *buf;
>  	u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
>  	u32 off = 8; /* off into first Full Status descriptor */
> -	int format_code = 0;
> +	int format_code = 0, pr_res_type = 0, pr_res_scope = 0;
> +	bool all_reg = false;
>  
>  	if (cmd->data_length < 8) {
>  		pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u"
> @@ -3851,6 +3852,19 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
>  	buf[2] = ((dev->t10_pr.pr_generation >> 8) & 0xff);
>  	buf[3] = (dev->t10_pr.pr_generation & 0xff);
>  
> +	spin_lock(&dev->dev_reservation_lock);
> +	if (dev->dev_pr_res_holder) {
> +		struct t10_pr_registration *pr_holder = dev->dev_pr_res_holder;
> +
> +		if (pr_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
> +		    pr_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) {
> +			all_reg = true;
> +			pr_res_type = pr_holder->pr_res_type;
> +			pr_res_scope = pr_holder->pr_res_scope;
> +		}
> +	}
> +	spin_unlock(&dev->dev_reservation_lock);
> +
>  	spin_lock(&pr_tmpl->registration_lock);
>  	list_for_each_entry_safe(pr_reg, pr_reg_tmp,
>  			&pr_tmpl->registration_list, pr_reg_list) {
> @@ -3898,14 +3912,20 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
>  		 * reservation holder for PR_HOLDER bit.
>  		 *
>  		 * Also, if this registration is the reservation
> -		 * holder, fill in SCOPE and TYPE in the next byte.
> +		 * holder or there is an All Registrants reservation
> +		 * active, fill in SCOPE and TYPE in the next byte.
>  		 */
>  		if (pr_reg->pr_res_holder) {
>  			buf[off++] |= 0x01;
>  			buf[off++] = (pr_reg->pr_res_scope & 0xf0) |
>  				     (pr_reg->pr_res_type & 0x0f);
> -		} else
> +		} else if (all_reg) {
> +			buf[off++] |= 0x01;
> +			buf[off++] = (pr_res_scope & 0xf0) |
> +				     (pr_res_type & 0x0f);
> +		} else {
>  			off += 2;
> +		}
>  
>  		off += 4; /* Skip over reserved area */
>  		/*
> 
Passes my test suite now for All Registrants.

Tested-by: Lee Duncan <lduncan@suse.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister
  2014-12-16  0:09 ` [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister Nicholas A. Bellinger
@ 2014-12-18  7:02   ` Lee Duncan
  0 siblings, 0 replies; 9+ messages in thread
From: Lee Duncan @ 2014-12-18  7:02 UTC (permalink / raw)
  To: Nicholas A. Bellinger, target-devel
  Cc: linux-scsi, Ilias Tsitsimpis, James Bottomley, Nicholas Bellinger

On 12/15/2014 04:09 PM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
> 
> This patch fixes an issue with AllRegistrants reservations where
> an unregister operation by the I_T nexus reservation holder would
> incorrectly drop the reservation, instead of waiting until the
> last active I_T nexus is unregistered as per SPC-4.
> 
> This includes updating __core_scsi3_complete_pro_release() to reset
> dev->dev_pr_res_holder with another pr_reg for this special case,
> as well as a new 'unreg' parameter to determine when the release
> is occuring from an implicit unregister, vs. explicit RELEASE.
> 
> It also adds special handling in core_scsi3_free_pr_reg_from_nacl()
> to release the left-over pr_res_holder, now that pr_reg is deleted
> from pr_reg_list within __core_scsi3_complete_pro_release().
> 
> Reported-by: Ilias Tsitsimpis <i.tsitsimpis@gmail.com>
> Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
>  drivers/target/target_core_pr.c | 87 ++++++++++++++++++++++++++++++-----------
>  1 file changed, 65 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
> index c4a8da5..703890c 100644
> --- a/drivers/target/target_core_pr.c
> +++ b/drivers/target/target_core_pr.c
> @@ -76,7 +76,7 @@ enum preempt_type {
>  };
>  
>  static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
> -			struct t10_pr_registration *, int);
> +					      struct t10_pr_registration *, int, int);
>  
>  static sense_reason_t
>  target_scsi2_reservation_check(struct se_cmd *cmd)
> @@ -1177,7 +1177,7 @@ static int core_scsi3_check_implicit_release(
>  		 *    service action with the SERVICE ACTION RESERVATION KEY
>  		 *    field set to zero (see 5.7.11.3).
>  		 */
> -		__core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0);
> +		__core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0, 1);
>  		ret = 1;
>  		/*
>  		 * For 'All Registrants' reservation types, all existing
> @@ -1219,7 +1219,8 @@ static void __core_scsi3_free_registration(
>  
>  	pr_reg->pr_reg_deve->def_pr_registered = 0;
>  	pr_reg->pr_reg_deve->pr_res_key = 0;
> -	list_del(&pr_reg->pr_reg_list);
> +	if (!list_empty(&pr_reg->pr_reg_list))
> +		list_del(&pr_reg->pr_reg_list);
>  	/*
>  	 * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(),
>  	 * so call core_scsi3_put_pr_reg() to decrement our reference.
> @@ -1271,6 +1272,7 @@ void core_scsi3_free_pr_reg_from_nacl(
>  {
>  	struct t10_reservation *pr_tmpl = &dev->t10_pr;
>  	struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
> +	bool free_reg = false;
>  	/*
>  	 * If the passed se_node_acl matches the reservation holder,
>  	 * release the reservation.
> @@ -1278,13 +1280,18 @@ void core_scsi3_free_pr_reg_from_nacl(
>  	spin_lock(&dev->dev_reservation_lock);
>  	pr_res_holder = dev->dev_pr_res_holder;
>  	if ((pr_res_holder != NULL) &&
> -	    (pr_res_holder->pr_reg_nacl == nacl))
> -		__core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0);
> +	    (pr_res_holder->pr_reg_nacl == nacl)) {
> +		__core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0, 1);
> +		free_reg = true;
> +	}
>  	spin_unlock(&dev->dev_reservation_lock);
>  	/*
>  	 * Release any registration associated with the struct se_node_acl.
>  	 */
>  	spin_lock(&pr_tmpl->registration_lock);
> +	if (pr_res_holder && free_reg)
> +		__core_scsi3_free_registration(dev, pr_res_holder, NULL, 0);
> +
>  	list_for_each_entry_safe(pr_reg, pr_reg_tmp,
>  			&pr_tmpl->registration_list, pr_reg_list) {
>  
> @@ -1307,7 +1314,7 @@ void core_scsi3_free_all_registrations(
>  	if (pr_res_holder != NULL) {
>  		struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
>  		__core_scsi3_complete_pro_release(dev, pr_res_nacl,
> -				pr_res_holder, 0);
> +						  pr_res_holder, 0, 0);
>  	}
>  	spin_unlock(&dev->dev_reservation_lock);
>  
> @@ -2103,13 +2110,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
>  		/*
>  		 * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus.
>  		 */
> -		pr_holder = core_scsi3_check_implicit_release(
> -				cmd->se_dev, pr_reg);
> +		type = pr_reg->pr_res_type;
> +		pr_holder = core_scsi3_check_implicit_release(cmd->se_dev,
> +							      pr_reg);
>  		if (pr_holder < 0) {
>  			ret = TCM_RESERVATION_CONFLICT;
>  			goto out;
>  		}
> -		type = pr_reg->pr_res_type;
>  
>  		spin_lock(&pr_tmpl->registration_lock);
>  		/*
> @@ -2383,23 +2390,59 @@ static void __core_scsi3_complete_pro_release(
>  	struct se_device *dev,
>  	struct se_node_acl *se_nacl,
>  	struct t10_pr_registration *pr_reg,
> -	int explicit)
> +	int explicit,
> +	int unreg)
>  {
>  	struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
>  	char i_buf[PR_REG_ISID_ID_LEN];
> +	int pr_res_type = 0, pr_res_scope = 0;
>  
>  	memset(i_buf, 0, PR_REG_ISID_ID_LEN);
>  	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);
>  	/*
>  	 * Go ahead and release the current PR reservation holder.
> +	 * If an All Registrants reservation is currently active and
> +	 * a unregister operation is requested, replace the current
> +	 * dev_pr_res_holder with another active registration.
>  	 */
> -	dev->dev_pr_res_holder = NULL;
> +	if (dev->dev_pr_res_holder) {
> +		pr_res_type = dev->dev_pr_res_holder->pr_res_type;
> +		pr_res_scope = dev->dev_pr_res_holder->pr_res_scope;
> +		dev->dev_pr_res_holder->pr_res_type = 0;
> +		dev->dev_pr_res_holder->pr_res_scope = 0;
> +		dev->dev_pr_res_holder->pr_res_holder = 0;
> +		dev->dev_pr_res_holder = NULL;
> +	}
> +	if (!unreg)
> +		goto out;
>  
> -	pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared"
> -		" reservation holder TYPE: %s ALL_TG_PT: %d\n",
> -		tfo->get_fabric_name(), (explicit) ? "explicit" : "implicit",
> -		core_scsi3_pr_dump_type(pr_reg->pr_res_type),
> -		(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
> +	spin_lock(&dev->t10_pr.registration_lock);
> +	list_del_init(&pr_reg->pr_reg_list);
> +	/*
> +	 * If the I_T nexus is a reservation holder, the persistent reservation
> +	 * is of an all registrants type, and the I_T nexus is the last remaining
> +	 * registered I_T nexus, then the device server shall also release the
> +	 * persistent reservation.
> +	 */
> +	if (!list_empty(&dev->t10_pr.registration_list) &&
> +	    ((pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
> +	     (pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) {
> +		dev->dev_pr_res_holder =
> +			list_entry(dev->t10_pr.registration_list.next,
> +				   struct t10_pr_registration, pr_reg_list);
> +		dev->dev_pr_res_holder->pr_res_type = pr_res_type;
> +		dev->dev_pr_res_holder->pr_res_scope = pr_res_scope;
> +		dev->dev_pr_res_holder->pr_res_holder = 1;
> +	}
> +	spin_unlock(&dev->t10_pr.registration_lock);
> +out:
> +	if (!dev->dev_pr_res_holder) {
> +		pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared"
> +			" reservation holder TYPE: %s ALL_TG_PT: %d\n",
> +			tfo->get_fabric_name(), (explicit) ? "explicit" :
> +			"implicit", core_scsi3_pr_dump_type(pr_res_type),
> +			(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
> +	}
>  	pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n",
>  		tfo->get_fabric_name(), se_nacl->initiatorname,
>  		i_buf);
> @@ -2530,7 +2573,7 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,
>  	 *    server shall not establish a unit attention condition.
>  	 */
>  	__core_scsi3_complete_pro_release(dev, se_sess->se_node_acl,
> -			pr_reg, 1);
> +					  pr_reg, 1, 0);
>  
>  	spin_unlock(&dev->dev_reservation_lock);
>  
> @@ -2618,7 +2661,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)
>  	if (pr_res_holder) {
>  		struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
>  		__core_scsi3_complete_pro_release(dev, pr_res_nacl,
> -			pr_res_holder, 0);
> +						  pr_res_holder, 0, 0);
>  	}
>  	spin_unlock(&dev->dev_reservation_lock);
>  	/*
> @@ -2677,7 +2720,7 @@ static void __core_scsi3_complete_pro_preempt(
>  	 */
>  	if (dev->dev_pr_res_holder)
>  		__core_scsi3_complete_pro_release(dev, nacl,
> -				dev->dev_pr_res_holder, 0);
> +						  dev->dev_pr_res_holder, 0, 0);
>  
>  	dev->dev_pr_res_holder = pr_reg;
>  	pr_reg->pr_res_holder = 1;
> @@ -2922,8 +2965,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
>  	 */
>  	if (pr_reg_n != pr_res_holder)
>  		__core_scsi3_complete_pro_release(dev,
> -				pr_res_holder->pr_reg_nacl,
> -				dev->dev_pr_res_holder, 0);
> +						  pr_res_holder->pr_reg_nacl,
> +						  dev->dev_pr_res_holder, 0, 0);
>  	/*
>  	 * b) Remove the registrations for all I_T nexuses identified
>  	 *    by the SERVICE ACTION RESERVATION KEY field, except the
> @@ -3386,7 +3429,7 @@ after_iport_check:
>  	 *    holder (i.e., the I_T nexus on which the
>  	 */
>  	__core_scsi3_complete_pro_release(dev, pr_res_nacl,
> -			dev->dev_pr_res_holder, 0);
> +					  dev->dev_pr_res_holder, 0, 0);
>  	/*
>  	 * g) Move the persistent reservation to the specified I_T nexus using
>  	 *    the same scope and type as the persistent reservation released in
> 


Tested-by: Lee Duncan <lduncan@suse.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/2] target: Fixes for AllRegistrants reservation handling
  2014-12-16  0:09 [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Nicholas A. Bellinger
  2014-12-16  0:09 ` [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants Nicholas A. Bellinger
  2014-12-16  0:09 ` [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister Nicholas A. Bellinger
@ 2014-12-18 14:54 ` Ilias Tsitsimpis
  2014-12-18 16:53   ` Douglas Gilbert
  2014-12-19  1:06   ` Nicholas A. Bellinger
  2 siblings, 2 replies; 9+ messages in thread
From: Ilias Tsitsimpis @ 2014-12-18 14:54 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: target-devel, linux-scsi, James Bottomley, Nicholas Bellinger

[-- Attachment #1: Type: text/plain, Size: 6233 bytes --]

On Tue, Dec 16, 2014 at 12:09AM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
> 
> Hi all,
> 
> This series addresses two issues raised recently by Ilias wrt
> AllRegistrants reservation handling in target code that does not
> adhere to SPC-4 specification requirements.
> 
> This first is a informational change to PR-IN READ_FULL_STATUS,
> that when an AllRegistrants reservation is in place, all active
> registrations should be setting R_HOLDER=1 within their respective
> descriptors.
> 
> The second is a functional change to PR-OUT REGISTER w/ SARK=0
> operation, to avoid dropping the AllRegistrants reservation until
> the last registered I_T nexus has been released.  It also ensures
> that the correct reservation type + scope is retained when the
> new reservation is set within __core_scsi3_complete_pro_release()
> for this AllRegistrants special case.
> 
> Also, thanks to James for the extra SPC-4 clarifications.
> 
> Please review.

Hi Nicholas,

Thanks for the quick fix. These patches address the two issues that I
raised in my previous email but they don't seem to fix all the problems
with AllRegistrants reservation handling in target code. Please see my
example below.

I have set up an iSCSI target, using the Linux SCSI Target
implementation with your patches applied, and I am connecting to it from
two different nodes using the open-iscsi project.

    root@node1:~# sg_inq /dev/sdc
    standard INQUIRY:
      PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3]
      [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
      SCCS=1  ACC=0  TPGS=3  3PC=1  Protect=0  BQue=0
      EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0
      [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1
        length=36 (0x24)   Peripheral device type: disk
     Vendor identification: LIO-ORG 
     Product identification: FILEIO          
     Product revision level: 4.0
     Unit serial number: 853ea439-7fcf-4aaa-9de2-1399e06b45be

    root@node2:~# sg_inq /dev/sdc
    standard INQUIRY:
      PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3]
      [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
      SCCS=1  ACC=0  TPGS=3  3PC=1  Protect=0  BQue=0
      EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0
      [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1
        length=36 (0x24)   Peripheral device type: disk
     Vendor identification: LIO-ORG 
     Product identification: FILEIO          
     Product revision level: 4.0
     Unit serial number: 853ea439-7fcf-4aaa-9de2-1399e06b45be

I register both of the I_T nexuses with the target.

    root@node1:~# sg_persist --out --register --param-sark 0x1 /dev/sdc

    root@node2:~# sg_persist --out --register --param-sark 0x2 /dev/sdc

    root@node1:~# sg_persist --in --read-full-status /dev/sdc
      LIO-ORG   FILEIO            4.0
      Peripheral device type: disk
      PR generation=0x17
        Key=0x1
          All target ports bit clear
          Relative port address: 0x5
          not reservation holder
          Transport Id of initiator:
            iSCSI name and session id: iqn.1993-08.org.debian:01:node1
        Key=0x2
          All target ports bit clear
          Relative port address: 0x5
          not reservation holder
          Transport Id of initiator:
            iSCSI name and session id: iqn.1993-08.org.debian:01:node2

Then I get a persistent reservation with type 'Exclusive Access - All
Registrants' from node1.

    root@node1:~# sg_persist --out --reserve -T 8 --param-rk 0x1 /dev/sdc
    root@node1:~# sg_persist --in --read-full-status /dev/sdc
      LIO-ORG   FILEIO            4.0
      Peripheral device type: disk
      PR generation=0x17
        Key=0x1
          All target ports bit clear
          Relative port address: 0x5
          << Reservation holder >>
          scope: LU_SCOPE,  type: Exclusive Access, all registrants
          Transport Id of initiator:
            iSCSI name and session id: iqn.1993-08.org.debian:01:node1
        Key=0x2
          All target ports bit clear
          Relative port address: 0x5
          << Reservation holder >>
          scope: LU_SCOPE,  type: Exclusive Access, all registrants
          Transport Id of initiator:
            iSCSI name and session id: iqn.1993-08.org.debian:01:node2

As you can see both registrants are reported as reservations holders,
which is the right thing to do.

Now let's try to get a persistent reservation with the same type from
node2. SPC4r17 (par. 5.7.9 Reserving) states that:

    If the device server receives a PERSISTENT RESERVE OUT command with
    RESERVE service action where the TYPE field and the SCOPE field
    contain the same values as the existing type and scope from a
    persistent reservation holder, it shall not make any change to the
    existing persistent reservation and shall complete the command with
    GOOD status.

Node2 *is* a persistent reservation holder based on the wording of
SPC4r17 (par. 5.7.10 Persistent reservation holder).
But instead:

    root@node2:~# sg_persist --out --reserve -T 8 --param-rk 0x2 /dev/sdc
      LIO-ORG   FILEIO            4.0
      Peripheral device type: disk
    persistent reserve out: scsi status: Reservation Conflict
    PR out: command failed

and on the target machine I get:

    [95713.681066] SPC-3 PR: Attempted RESERVE from [iSCSI]:
    iqn.1993-08.org.debian:01:node2 while reservation already held by
    [iSCSI]: iqn.1993-08.org.debian:01:node1, returning
    RESERVATION_CONFLICT

If I try the same from node1, the target completes the command with GOOD
status.


It is clear that the target code still considers node1 as the (only)
reservation holder and only *reports* node2 as being a reservation
holder.

I believe we should fix the above errors by changing the
'pr_res_holder' inside the 't10_reservation' struct to be a list of
holders rather than trying to handle this implicitly. Having a single
holder in the code seems prone to more errors similar to this one.

Thanks,
Ilias

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/2] target: Fixes for AllRegistrants reservation handling
  2014-12-18 14:54 ` [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Ilias Tsitsimpis
@ 2014-12-18 16:53   ` Douglas Gilbert
  2014-12-19  8:21     ` Nicholas A. Bellinger
  2014-12-19  1:06   ` Nicholas A. Bellinger
  1 sibling, 1 reply; 9+ messages in thread
From: Douglas Gilbert @ 2014-12-18 16:53 UTC (permalink / raw)
  To: Ilias Tsitsimpis, Nicholas A. Bellinger
  Cc: target-devel, linux-scsi, James Bottomley, Nicholas Bellinger,
	Alexander Motin

On 14-12-18 09:54 AM, Ilias Tsitsimpis wrote:
> On Tue, Dec 16, 2014 at 12:09AM, Nicholas A. Bellinger wrote:
>> From: Nicholas Bellinger <nab@linux-iscsi.org>
>>
>> Hi all,
>>
>> This series addresses two issues raised recently by Ilias wrt
>> AllRegistrants reservation handling in target code that does not
>> adhere to SPC-4 specification requirements.
>>
>> This first is a informational change to PR-IN READ_FULL_STATUS,
>> that when an AllRegistrants reservation is in place, all active
>> registrations should be setting R_HOLDER=1 within their respective
>> descriptors.
>>
>> The second is a functional change to PR-OUT REGISTER w/ SARK=0
>> operation, to avoid dropping the AllRegistrants reservation until
>> the last registered I_T nexus has been released.  It also ensures
>> that the correct reservation type + scope is retained when the
>> new reservation is set within __core_scsi3_complete_pro_release()
>> for this AllRegistrants special case.
>>
>> Also, thanks to James for the extra SPC-4 clarifications.
>>
>> Please review.
>
> Hi Nicholas,
>
> Thanks for the quick fix. These patches address the two issues that I
> raised in my previous email but they don't seem to fix all the problems
> with AllRegistrants reservation handling in target code. Please see my
> example below.
>
> I have set up an iSCSI target, using the Linux SCSI Target
> implementation with your patches applied, and I am connecting to it from
> two different nodes using the open-iscsi project.
>
>      root@node1:~# sg_inq /dev/sdc
>      standard INQUIRY:
>        PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3]
>        [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
>        SCCS=1  ACC=0  TPGS=3  3PC=1  Protect=0  BQue=0
>        EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0
>        [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1
>          length=36 (0x24)   Peripheral device type: disk
>       Vendor identification: LIO-ORG
>       Product identification: FILEIO
>       Product revision level: 4.0
>       Unit serial number: 853ea439-7fcf-4aaa-9de2-1399e06b45be

Here is an alternate open source implementation of an
iSCSI target/server:

root@node1:~# sg_inq /dev/sdc
standard INQUIRY:
   PQual=0  Device_type=0  RMB=0  LU_CONG=0  version=0x06  [SPC-4]
   [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=1  Resp_data_format=2
   SCCS=0  ACC=0  TPGS=1  3PC=1  Protect=0  [BQue=0]
   EncServ=0  MultiP=1 (VS=0)  [MChngr=0]  [ACKREQQ=0]  Addr16=0
   [RelAdr=0]  WBus16=0  Sync=0  [Linked=0]  [TranDis=0]  CmdQue=1
   [SPI: Clocking=0x0  QAS=0  IUS=0]
     length=96 (0x60)   Peripheral device type: disk
  Vendor identification: FreeBSD
  Product identification: iSCSI Disk
  Product revision level: 0123
  Unit serial number: 0015f2d0d8b600

>      root@node2:~# sg_inq /dev/sdc
>      standard INQUIRY:
>        PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3]
>        [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
>        SCCS=1  ACC=0  TPGS=3  3PC=1  Protect=0  BQue=0
>        EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0
>        [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1
>          length=36 (0x24)   Peripheral device type: disk
>       Vendor identification: LIO-ORG
>       Product identification: FILEIO
>       Product revision level: 4.0
>       Unit serial number: 853ea439-7fcf-4aaa-9de2-1399e06b45be

root@node2:~# sg_inq /dev/sdb
standard INQUIRY:
   PQual=0  Device_type=0  RMB=0  LU_CONG=0  version=0x06  [SPC-4]
   [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=1  Resp_data_format=2
   SCCS=0  ACC=0  TPGS=1  3PC=1  Protect=0  [BQue=0]
   EncServ=0  MultiP=1 (VS=0)  [MChngr=0]  [ACKREQQ=0]  Addr16=0
   [RelAdr=0]  WBus16=0  Sync=0  [Linked=0]  [TranDis=0]  CmdQue=1
   [SPI: Clocking=0x0  QAS=0  IUS=0]
     length=96 (0x60)   Peripheral device type: disk
  Vendor identification: FreeBSD
  Product identification: iSCSI Disk
  Product revision level: 0123
  Unit serial number: 0015f2d0d8b600


Now playing along with the same test sequence and noting when
there are significant differences.

> I register both of the I_T nexuses with the target.
>
>      root@node1:~# sg_persist --out --register --param-sark 0x1 /dev/sdc
>
>      root@node2:~# sg_persist --out --register --param-sark 0x2 /dev/sdc
>
>      root@node1:~# sg_persist --in --read-full-status /dev/sdc
>        LIO-ORG   FILEIO            4.0
>        Peripheral device type: disk
>        PR generation=0x17
>          Key=0x1
>            All target ports bit clear
>            Relative port address: 0x5
>            not reservation holder
>            Transport Id of initiator:
>              iSCSI name and session id: iqn.1993-08.org.debian:01:node1
>          Key=0x2
>            All target ports bit clear
>            Relative port address: 0x5
>            not reservation holder
>            Transport Id of initiator:
>              iSCSI name and session id: iqn.1993-08.org.debian:01:node2
>
> Then I get a persistent reservation with type 'Exclusive Access - All
> Registrants' from node1.
>
>      root@node1:~# sg_persist --out --reserve -T 8 --param-rk 0x1 /dev/sdc
>      root@node1:~# sg_persist --in --read-full-status /dev/sdc
>        LIO-ORG   FILEIO            4.0
>        Peripheral device type: disk
>        PR generation=0x17
>          Key=0x1
>            All target ports bit clear
>            Relative port address: 0x5
>            << Reservation holder >>
>            scope: LU_SCOPE,  type: Exclusive Access, all registrants
>            Transport Id of initiator:
>              iSCSI name and session id: iqn.1993-08.org.debian:01:node1
>          Key=0x2
>            All target ports bit clear
>            Relative port address: 0x5
>            << Reservation holder >>
>            scope: LU_SCOPE,  type: Exclusive Access, all registrants
>            Transport Id of initiator:
>              iSCSI name and session id: iqn.1993-08.org.debian:01:node2
>
> As you can see both registrants are reported as reservations holders,
> which is the right thing to do.
>
> Now let's try to get a persistent reservation with the same type from
> node2. SPC4r17 (par. 5.7.9 Reserving) states that:
>
>      If the device server receives a PERSISTENT RESERVE OUT command with
>      RESERVE service action where the TYPE field and the SCOPE field
>      contain the same values as the existing type and scope from a
>      persistent reservation holder, it shall not make any change to the
>      existing persistent reservation and shall complete the command with
>      GOOD status.
>
> Node2 *is* a persistent reservation holder based on the wording of
> SPC4r17 (par. 5.7.10 Persistent reservation holder).
> But instead:
>
>      root@node2:~# sg_persist --out --reserve -T 8 --param-rk 0x2 /dev/sdc
>        LIO-ORG   FILEIO            4.0
>        Peripheral device type: disk
>      persistent reserve out: scsi status: Reservation Conflict
>      PR out: command failed
>
> and on the target machine I get:
>
>      [95713.681066] SPC-3 PR: Attempted RESERVE from [iSCSI]:
>      iqn.1993-08.org.debian:01:node2 while reservation already held by
>      [iSCSI]: iqn.1993-08.org.debian:01:node1, returning
>      RESERVATION_CONFLICT

With FreeNAS as the iSCSI target (server), the above command on
node2 succeeds.

> If I try the same from node1, the target completes the command with GOOD
> status.

And back on node1 I see:

root@node1:~# sg_persist --out --reserve -T 8 --param-rk 0x2 /dev/sdc
   FreeBSD   iSCSI Disk        0123
   Peripheral device type: disk
PR out (Reserve): Reservation conflict

which I am guessing is what was expected.

> It is clear that the target code still considers node1 as the (only)
> reservation holder and only *reports* node2 as being a reservation
> holder.
>
> I believe we should fix the above errors by changing the
> 'pr_res_holder' inside the 't10_reservation' struct to be a list of
> holders rather than trying to handle this implicitly. Having a single
> holder in the code seems prone to more errors similar to this one.


I think Alexander Motin has done a pretty impressive
job over at FreeBSD in the SCSI target area. FreeNAS
(9.3 recently released) is a convenient packaging for
turning a box (or just an old disk in my case) into an
iSCSI target.


FreeNAS's iSCSI target also implements ODX which is one
reason why I have been looking at it (hint to NAB). With
ODX it does cut one significant corner in only supporting
"access upon reference" RODs. Its ODX implementation found
several bugs and holes in my ddpt ODX client code. Perhaps
NAB might check how FreeBSD's code handles the AllRegistrants
reservation handling case.

Doug Gilbert

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/2] target: Fixes for AllRegistrants reservation handling
  2014-12-18 14:54 ` [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Ilias Tsitsimpis
  2014-12-18 16:53   ` Douglas Gilbert
@ 2014-12-19  1:06   ` Nicholas A. Bellinger
  1 sibling, 0 replies; 9+ messages in thread
From: Nicholas A. Bellinger @ 2014-12-19  1:06 UTC (permalink / raw)
  To: Ilias Tsitsimpis
  Cc: Nicholas A. Bellinger, target-devel, linux-scsi, James Bottomley

On Thu, 2014-12-18 at 16:54 +0200, Ilias Tsitsimpis wrote:
> On Tue, Dec 16, 2014 at 12:09AM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> > 
> > Hi all,
> > 
> > This series addresses two issues raised recently by Ilias wrt
> > AllRegistrants reservation handling in target code that does not
> > adhere to SPC-4 specification requirements.
> > 
> > This first is a informational change to PR-IN READ_FULL_STATUS,
> > that when an AllRegistrants reservation is in place, all active
> > registrations should be setting R_HOLDER=1 within their respective
> > descriptors.
> > 
> > The second is a functional change to PR-OUT REGISTER w/ SARK=0
> > operation, to avoid dropping the AllRegistrants reservation until
> > the last registered I_T nexus has been released.  It also ensures
> > that the correct reservation type + scope is retained when the
> > new reservation is set within __core_scsi3_complete_pro_release()
> > for this AllRegistrants special case.
> > 
> > Also, thanks to James for the extra SPC-4 clarifications.
> > 
> > Please review.
> 
> Hi Nicholas,
> 
> Thanks for the quick fix. These patches address the two issues that I
> raised in my previous email but they don't seem to fix all the problems
> with AllRegistrants reservation handling in target code. Please see my
> example below.
> 

<SNIP>

> Now let's try to get a persistent reservation with the same type from
> node2. SPC4r17 (par. 5.7.9 Reserving) states that:
> 
>     If the device server receives a PERSISTENT RESERVE OUT command with
>     RESERVE service action where the TYPE field and the SCOPE field
>     contain the same values as the existing type and scope from a
>     persistent reservation holder, it shall not make any change to the
>     existing persistent reservation and shall complete the command with
>     GOOD status.
> 
> Node2 *is* a persistent reservation holder based on the wording of
> SPC4r17 (par. 5.7.10 Persistent reservation holder).
> But instead:
> 
>     root@node2:~# sg_persist --out --reserve -T 8 --param-rk 0x2 /dev/sdc
>       LIO-ORG   FILEIO            4.0
>       Peripheral device type: disk
>     persistent reserve out: scsi status: Reservation Conflict
>     PR out: command failed
> 
> and on the target machine I get:
> 
>     [95713.681066] SPC-3 PR: Attempted RESERVE from [iSCSI]:
>     iqn.1993-08.org.debian:01:node2 while reservation already held by
>     [iSCSI]: iqn.1993-08.org.debian:01:node1, returning
>     RESERVATION_CONFLICT
> 
> If I try the same from node1, the target completes the command with GOOD
> status.
> 
> 
> It is clear that the target code still considers node1 as the (only)
> reservation holder and only *reports* node2 as being a reservation
> holder.

That is a very small change.  Sending out a patch for this now.

> 
> I believe we should fix the above errors by changing the
> 'pr_res_holder' inside the 't10_reservation' struct to be a list of
> holders rather than trying to handle this implicitly. Having a single
> holder in the code seems prone to more errors similar to this one.
> 

Not exactly, changing all existing code for ALLREG related special cases
really isn't worth the extra pain here.  I'd much rather identify any
remaining ALLREG specific issues, and address them individually.

Thanks Ilias!

--nab

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/2] target: Fixes for AllRegistrants reservation handling
  2014-12-18 16:53   ` Douglas Gilbert
@ 2014-12-19  8:21     ` Nicholas A. Bellinger
  0 siblings, 0 replies; 9+ messages in thread
From: Nicholas A. Bellinger @ 2014-12-19  8:21 UTC (permalink / raw)
  To: dgilbert
  Cc: Ilias Tsitsimpis, Nicholas A. Bellinger, target-devel,
	linux-scsi, James Bottomley, Alexander Motin

Hi Doug,

On Thu, 2014-12-18 at 11:53 -0500, Douglas Gilbert wrote:

<SNIP>

> 
> FreeNAS's iSCSI target also implements ODX which is one
> reason why I have been looking at it (hint to NAB). With
> ODX it does cut one significant corner in only supporting
> "access upon reference" RODs. Its ODX implementation found
> several bugs and holes in my ddpt ODX client code. 

So ODX support is still low on my current TODO list, but I'm happy to
assist anyone in the short-term who is willing to submit patches for
implementing the first steps to get the ball rolling.  IIRC, the CDB
emulation additions are really quite straight-forward, especially given
you've already got a working ddpt client.  ;)

Of course, the more interesting question is once EXTENDED_COPY(LID4)
emulation is in place, how is the interface for supporting tokenized
READ/WRITE through to struct block_device (and FILEIO too) going to
look..?

I haven't seen much discussion on this topic, and would be interested to
hear if anyone has thoughts on how that piece might work.

--nab

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-12-19  8:21 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-16  0:09 [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Nicholas A. Bellinger
2014-12-16  0:09 ` [PATCH 1/2] target: Fix R_HOLDER bit usage for AllRegistrants Nicholas A. Bellinger
2014-12-18  7:01   ` Lee Duncan
2014-12-16  0:09 ` [PATCH 2/2] target: Avoid dropping AllRegistrants reservation during unregister Nicholas A. Bellinger
2014-12-18  7:02   ` Lee Duncan
2014-12-18 14:54 ` [PATCH 0/2] target: Fixes for AllRegistrants reservation handling Ilias Tsitsimpis
2014-12-18 16:53   ` Douglas Gilbert
2014-12-19  8:21     ` Nicholas A. Bellinger
2014-12-19  1:06   ` Nicholas A. Bellinger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.