[stgt] [PATCH 3/4] tgt: Fix hang issue in spc_pr_preempt
Mike Anderson
andmike at linux.vnet.ibm.com
Fri Oct 8 05:58:06 CEST 2010
Address issue in spc_pr_preempt where the goto was leading to
endless loop. The unit attentions where not being set for
reservation released and reservation preempted cases.
Signed-off-by: Mike Anderson <andmike at linux.vnet.ibm.com>
---
usr/spc.c | 99 +++++++++++++++++++++++++++++++++++-------------------------
1 files changed, 58 insertions(+), 41 deletions(-)
diff --git a/usr/spc.c b/usr/spc.c
index e19a743..22f0277 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -926,6 +926,19 @@ static struct registration *lookup_registration_by_nexus(struct scsi_lu *lu,
return NULL;
}
+static int check_registration_key_exists(struct scsi_lu *lu, uint64_t key)
+{
+ struct registration *reg;
+
+ list_for_each_entry(reg, &lu->registration_list,
+ registration_siblings) {
+ if (reg->key == key)
+ return 0;
+ }
+
+ return 1;
+}
+
static void __unregister(struct scsi_lu *lu, struct registration *reg)
{
list_del(®->registration_siblings);
@@ -1211,10 +1224,11 @@ static int spc_pr_preempt(int host_no, struct scsi_cmd *cmd)
uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
uint8_t key = ILLEGAL_REQUEST;
int ret, abort;
+ int res_released = 0, remove_all_reg = 0;
uint64_t res_key, sa_res_key;
uint8_t pr_scope, pr_type;
uint8_t *buf;
- struct registration *reg, *sibling, *n;
+ struct registration *holder, *reg, *sibling, *n;
ret = check_pr_out_basic_parameter(cmd);
if (ret)
@@ -1237,56 +1251,59 @@ static int spc_pr_preempt(int host_no, struct scsi_cmd *cmd)
if (reg->key != res_key)
return SAM_STAT_RESERVATION_CONFLICT;
-remove_registration:
- if (!cmd->dev->pr_holder) {
- list_for_each_entry_safe(sibling, n, &cmd->dev->registration_list,
- registration_siblings) {
+ if (sa_res_key) {
+ ret = check_registration_key_exists(cmd->dev, sa_res_key);
+ if (ret)
+ return SAM_STAT_RESERVATION_CONFLICT;
+ }
+
+ holder = cmd->dev->pr_holder;
- if (sibling->key == sa_res_key) {
- __unregister(cmd->dev, sibling);
- break;
+ if (holder) {
+ if (holder->pr_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
+ holder->pr_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) {
+
+ if (!sa_res_key) {
+ if (pr_type != holder->pr_type ||
+ pr_scope != holder->pr_scope)
+ res_released = 1;
+ reg->pr_type = pr_type;
+ reg->pr_scope = pr_scope;
+ cmd->dev->pr_holder = reg;
+ remove_all_reg = 1;
+ }
+ } else {
+ if (holder->key == sa_res_key) {
+ if ((pr_type != holder->pr_type) ||
+ (pr_scope != holder->pr_scope))
+ res_released = 1;
+ reg->pr_type = pr_type;
+ reg->pr_scope = pr_scope;
+ cmd->dev->pr_holder = reg;
+ } else {
+ if (!sa_res_key)
+ goto sense;
}
}
-
- return SAM_STAT_GOOD;
}
- if (cmd->dev->pr_holder->pr_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
- cmd->dev->pr_holder->pr_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) {
-
- if (sa_res_key)
- goto remove_registration;
-
- list_for_each_entry_safe(sibling, n, &cmd->dev->registration_list,
- registration_siblings) {
-
- if (sibling == reg)
- continue;
+ list_for_each_entry_safe(sibling, n, &cmd->dev->registration_list,
+ registration_siblings) {
+ if (sibling == reg)
+ continue;
+ if (sibling->key == sa_res_key || remove_all_reg) {
+ ua_sense_add_it_nexus(sibling->nexus_id,
+ cmd->dev, ASC_RESERVATIONS_PREEMPTED);
__unregister(cmd->dev, sibling);
+ } else {
+ if (res_released)
+ ua_sense_add_it_nexus(sibling->nexus_id,
+ cmd->dev, ASC_RESERVATIONS_RELEASED);
}
-
- cmd->dev->pr_holder = reg;
- reg->pr_type = pr_type;
- reg->pr_scope = pr_scope;
-
- return SAM_STAT_GOOD;
}
- if (cmd->dev->pr_holder->key == sa_res_key) {
- cmd->dev->pr_holder = reg;
- reg->pr_type = pr_type;
- reg->pr_scope = pr_scope;
-
- goto remove_registration;
- }
-
- if (sa_res_key)
- goto remove_registration;
-
- else
- goto sense;
-
+ cmd->dev->prgeneration++;
return SAM_STAT_GOOD;
sense:
scsi_set_in_resid_by_actual(cmd, 0);
--
1.7.2.3
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list