[stgt] [PATCH 1/3] Add infrastructure for statistics on SCSI device level

nezhinsky at gmail.com nezhinsky at gmail.com
Wed Jul 18 00:31:08 CEST 2012


From: Alexander Nezhinsky <alexandern at mellanox.com>

To introduce statistics on SCSI device level we need to accumulate them
for each ITL (initiator-target-lun) nexus.

For example in case of iscsi, this is a granularity which is finer than
a session (IT nexus), as it represents access to a specific lun within
the session.

Statistics counters are added to the ITL object, "struct it_nexus_lu_info".
They need to be shown later in various scopes (connection, device, target etc.)
requiring two-way access, both from a device (lun to all its ITLs) and
from an IT nexus (IT nexus to all its ITLs).

Thus linked list heads called "itn_itl_info_list" and "lu_itl_info_list" are
added to struct it_nexus and struct scsi_lu, while struct it_nexus_lu_info
becomes a memeber in these two lists, thru the list entries called:
"itn_itl_info_siblings" and "lu_itl_info_siblings".

Signed-off-by: Alexander Nezhinsky <alexandern at mellanox.com>
---
 usr/scsi.c   |   16 +++++++++--
 usr/target.c |   89 ++++++++++++++++++++++++++++++++++++----------------------
 usr/tgtd.h   |   27 +++++++++++++++++-
 3 files changed, 96 insertions(+), 36 deletions(-)

diff --git a/usr/scsi.c b/usr/scsi.c
index 83479ed..6f41b0b 100644
--- a/usr/scsi.c
+++ b/usr/scsi.c
@@ -207,6 +207,18 @@ int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd)
 	unsigned char op = cmd->scb[0];
 	struct it_nexus_lu_info *itn_lu;
 
+	if (scsi_get_data_dir(cmd) == DATA_WRITE) {
+		cmd->itn_lu_info->stat.wr_subm_bytes += scsi_get_out_length(cmd);
+		cmd->itn_lu_info->stat.wr_subm_cmds++;
+	} else if (scsi_get_data_dir(cmd) == DATA_READ) {
+		cmd->itn_lu_info->stat.rd_subm_bytes += scsi_get_in_length(cmd);
+		cmd->itn_lu_info->stat.rd_subm_cmds++;
+	} else if (scsi_get_data_dir(cmd) == DATA_BIDIRECTIONAL) {
+		cmd->itn_lu_info->stat.wr_subm_bytes += scsi_get_out_length(cmd);
+		cmd->itn_lu_info->stat.rd_subm_bytes += scsi_get_in_length(cmd);
+		cmd->itn_lu_info->stat.bidir_subm_cmds++;
+	}
+
 	if (CDB_CONTROL(cmd) & ((1U << 0) | (1U << 2))) {
 		/*
 		 * We don't support a linked command. SAM-3 say that
@@ -241,8 +253,8 @@ int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd)
 		break;
 	case REPORT_LUNS:
 		list_for_each_entry(itn_lu,
-				    &cmd->it_nexus->it_nexus_lu_info_list,
-				    lu_info_siblings)
+				    &cmd->it_nexus->itn_itl_info_list,
+				    itn_itl_info_siblings)
 			ua_sense_clear(itn_lu,
 				       ASC_REPORTED_LUNS_DATA_HAS_CHANGED);
 		break;
diff --git a/usr/target.c b/usr/target.c
index 68222a0..c19421a 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -81,7 +81,7 @@ static int target_name_lookup(char *name)
 	return 0;
 }
 
-static struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id)
+struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id)
 {
 	struct target *target;
 	struct it_nexus *itn;
@@ -196,14 +196,15 @@ static void it_nexus_del_lu_info(struct it_nexus *itn)
 {
 	struct it_nexus_lu_info *itn_lu;
 
-	while(!list_empty(&itn->it_nexus_lu_info_list)) {
-		itn_lu = list_first_entry(&itn->it_nexus_lu_info_list,
+	while (!list_empty(&itn->itn_itl_info_list)) {
+		itn_lu = list_first_entry(&itn->itn_itl_info_list,
 					  struct it_nexus_lu_info,
-					  lu_info_siblings);
+					  itn_itl_info_siblings);
 
 		ua_sense_pending_del(itn_lu);
 
-		list_del(&itn_lu->lu_info_siblings);
+		list_del(&itn_lu->itn_itl_info_siblings);
+		list_del(&itn_lu->lu_itl_info_siblings);
 		free(itn_lu);
 	}
 }
@@ -220,8 +221,8 @@ void ua_sense_add_other_it_nexus(uint64_t itn_id, struct scsi_lu *lu,
 		if (itn->itn_id == itn_id)
 			continue;
 
-		list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-				    lu_info_siblings) {
+		list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+				    itn_itl_info_siblings) {
 
 			if (itn_lu->lu != lu)
 				continue;
@@ -244,8 +245,8 @@ void ua_sense_add_it_nexus(uint64_t itn_id, struct scsi_lu *lu,
 	list_for_each_entry(itn, &lu->tgt->it_nexus_list, nexus_siblings) {
 
 		if (itn->itn_id == itn_id) {
-			list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-					    lu_info_siblings) {
+			list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+					    itn_itl_info_siblings) {
 
 				if (itn_lu->lu == lu) {
 					ret = ua_sense_add(itn_lu, asc);
@@ -267,8 +268,8 @@ int lu_prevent_removal(struct scsi_lu *lu)
 	struct it_nexus_lu_info *itn_lu;
 
 	list_for_each_entry(itn, &lu->tgt->it_nexus_list, nexus_siblings) {
-		list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-				    lu_info_siblings) {
+		list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+				    itn_itl_info_siblings) {
 			if (itn_lu->lu == lu) {
 				if (itn_lu->prevent & PREVENT_REMOVAL)
 					return 1;
@@ -306,7 +307,7 @@ int it_nexus_create(int tid, uint64_t itn_id, int host_no, char *info)
 	itn->host_no = host_no;
 	itn->nexus_target = target;
 	itn->info = info;
-	INIT_LIST_HEAD(&itn->it_nexus_lu_info_list);
+	INIT_LIST_HEAD(&itn->itn_itl_info_list);
 	gettimeofday(&tv, NULL);
 	itn->ctime = tv.tv_sec;
 
@@ -315,14 +316,18 @@ int it_nexus_create(int tid, uint64_t itn_id, int host_no, char *info)
 		if (!itn_lu)
 			goto out;
 		itn_lu->lu = lu;
+		itn_lu->itn_id = itn_id;
 		INIT_LIST_HEAD(&itn_lu->pending_ua_sense_list);
 
 		ret = ua_sense_add(itn_lu, ASC_POWERON_RESET);
 		if (ret)
 			goto out;
 
-		list_add(&itn_lu->lu_info_siblings,
-			 &itn->it_nexus_lu_info_list);
+		list_add_tail(&itn_lu->lu_itl_info_siblings,
+			      &lu->lu_itl_info_list);
+
+		list_add(&itn_lu->itn_itl_info_siblings,
+			 &itn->itn_itl_info_list);
 	}
 
 	INIT_LIST_HEAD(&itn->cmd_list);
@@ -472,7 +477,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
 	struct scsi_lu *lu, *pos;
 	struct device_type_template *t;
 	struct backingstore_template *bst;
-	struct it_nexus_lu_info *itn_lu;
+	struct it_nexus_lu_info *itn_lu, *itn_lu_pos;
 	struct it_nexus *itn;
 	char strflags[128];
 
@@ -573,6 +578,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
 
 	tgt_cmd_queue_init(&lu->cmd_queue);
 	INIT_LIST_HEAD(&lu->registration_list);
+	INIT_LIST_HEAD(&lu->lu_itl_info_list);
 	lu->prgeneration = 0;
 	lu->pr_holder = NULL;
 
@@ -635,21 +641,24 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params,
 		if (!itn_lu)
 			break;
 		itn_lu->lu = lu;
+		itn_lu->itn_id = itn->itn_id;
 		INIT_LIST_HEAD(&itn_lu->pending_ua_sense_list);
 
-		list_add(&itn_lu->lu_info_siblings,
-			 &itn->it_nexus_lu_info_list);
-	}
-
-	list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
-		list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-				    lu_info_siblings) {
+		/* signal LUNs info change thru all existing LUNs in the nexus */
+		list_for_each_entry(itn_lu_pos, &itn->itn_itl_info_list,
+				    itn_itl_info_siblings) {
 
-			if (ua_sense_add(itn_lu, ASC_REPORTED_LUNS_DATA_HAS_CHANGED)) {
+			if (ua_sense_add(itn_lu_pos, ASC_REPORTED_LUNS_DATA_HAS_CHANGED)) {
 				adm_err = TGTADM_NOMEM;
 				goto fail_bs_init;
 			}
 		}
+
+		list_add_tail(&itn_lu->lu_itl_info_siblings,
+			      &lu->lu_itl_info_list);
+
+		list_add(&itn_lu->itn_itl_info_siblings,
+			 &itn->itn_itl_info_list);
 	}
 
 	if (backing && !path)
@@ -711,8 +720,8 @@ tgtadm_err tgt_device_destroy(int tid, uint64_t lun, int force)
 		lu->bst->bs_exit(lu);
 
 	list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
-		list_for_each_entry_safe(itn_lu, next, &itn->it_nexus_lu_info_list,
-					 lu_info_siblings) {
+		list_for_each_entry_safe(itn_lu, next, &itn->itn_itl_info_list,
+					 itn_itl_info_siblings) {
 			if (itn_lu->lu == lu) {
 				ua_sense_pending_del(itn_lu);
 				break;
@@ -730,8 +739,8 @@ tgtadm_err tgt_device_destroy(int tid, uint64_t lun, int force)
 	free(lu);
 
 	list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
-		list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-				    lu_info_siblings) {
+		list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+				    itn_itl_info_siblings) {
 
 			ret = ua_sense_add(itn_lu,
 					   ASC_REPORTED_LUNS_DATA_HAS_CHANGED);
@@ -951,8 +960,8 @@ static struct it_nexus_lu_info *it_nexus_lu_info_lookup(struct it_nexus *itn,
 {
 	struct it_nexus_lu_info *itn_lu;
 
-	list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-			    lu_info_siblings) {
+	list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+			    itn_itl_info_siblings) {
 		if (itn_lu->lu->lun == lun)
 			return itn_lu;
 	}
@@ -1061,6 +1070,20 @@ int target_cmd_perform_passthrough(int tid, struct scsi_cmd *cmd)
 void target_cmd_io_done(struct scsi_cmd *cmd, int result)
 {
 	scsi_set_result(cmd, result);
+	if (scsi_get_data_dir(cmd) == DATA_WRITE) {
+		cmd->itn_lu_info->stat.wr_done_bytes += scsi_get_out_length(cmd);
+		cmd->itn_lu_info->stat.wr_done_cmds++;
+	} else if (scsi_get_data_dir(cmd) == DATA_READ) {
+		cmd->itn_lu_info->stat.rd_done_bytes += scsi_get_in_length(cmd);
+		cmd->itn_lu_info->stat.rd_done_cmds++;
+	} else if (scsi_get_data_dir(cmd) == DATA_BIDIRECTIONAL) {
+		cmd->itn_lu_info->stat.wr_done_bytes += scsi_get_out_length(cmd);
+		cmd->itn_lu_info->stat.rd_done_bytes += scsi_get_in_length(cmd);
+		cmd->itn_lu_info->stat.bidir_done_cmds++;
+	}
+	if (result != SAM_STAT_GOOD)
+		cmd->itn_lu_info->stat.err_num++;
+
 	tgt_drivers[cmd->c_target->lid]->cmd_end_notify(cmd->cmd_itn_id,
 							result, cmd);
 	return;
@@ -1241,8 +1264,8 @@ enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id,
 			send = 0;
 
 		list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
-			list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-					    lu_info_siblings) {
+			list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+					    itn_itl_info_siblings) {
 				if (itn_lu->lu->lun == lun) {
 					if (itn->itn_id == itn_id)
 						asc = ASC_POWERON_RESET;
@@ -1263,8 +1286,8 @@ enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id,
 			send = 0;
 
 		list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) {
-			list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list,
-					    lu_info_siblings) {
+			list_for_each_entry(itn_lu, &itn->itn_itl_info_list,
+					    itn_itl_info_siblings) {
 				if (itn_lu->lu->lun == lun) {
 					ua_sense_add(itn_lu, ASC_POWERON_RESET);
 					break;
diff --git a/usr/tgtd.h b/usr/tgtd.h
index aa9b9d5..9fac774 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -92,9 +92,31 @@ struct ua_sense {
 	int ua_sense_len;
 };
 
+struct lu_stat {
+	uint64_t rd_subm_bytes;
+	uint64_t rd_done_bytes;
+
+	uint64_t wr_subm_bytes;
+	uint64_t wr_done_bytes;
+
+	uint32_t rd_subm_cmds;
+	uint32_t rd_done_cmds;
+
+	uint32_t wr_subm_cmds;
+	uint32_t wr_done_cmds;
+
+	uint32_t bidir_subm_cmds;
+	uint32_t bidir_done_cmds;
+
+	uint32_t err_num;
+};
+
 struct it_nexus_lu_info {
 	struct scsi_lu *lu;
-	struct list_head lu_info_siblings;
+	uint64_t itn_id;
+	struct lu_stat stat;
+	struct list_head itn_itl_info_siblings;
+	struct list_head lu_itl_info_siblings;
 	struct list_head pending_ua_sense_list;
 	int prevent; /* prevent removal on this itl nexus ? */
 };
@@ -174,6 +196,8 @@ struct scsi_lu {
 	/* the list of devices belonging to a target */
 	struct list_head device_siblings;
 
+	struct list_head lu_itl_info_list;
+
 	struct tgt_cmd_queue cmd_queue;
 
 	uint64_t reserve_id;
@@ -280,6 +304,7 @@ extern enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id,
 						uint8_t *lun, uint64_t tag,
 						int host_no);
 
+extern struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id);
 extern void target_cmd_io_done(struct scsi_cmd *cmd, int result);
 extern int ua_sense_del(struct scsi_cmd *cmd, int del);
 extern void ua_sense_clear(struct it_nexus_lu_info *itn_lu, uint16_t asc);
-- 
1.7.9.5

--
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