diff --git a/scst/include/scst.h b/scst/include/scst.h index d99e30266..e861bf8c1 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1522,6 +1522,11 @@ struct scst_ext_latency_stat { #endif /* CONFIG_SCST_MEASURE_LATENCY */ +struct scst_io_stat_entry { + uint64_t cmd_count; + uint64_t io_byte_count; +}; + /* * SCST session, analog of SCSI I_T nexus */ @@ -1568,6 +1573,9 @@ struct scst_session { */ atomic_t sess_cmd_count; + /* Some statistics. Protected by sess_list_lock. */ + struct scst_io_stat_entry io_stats[SCST_DATA_DIR_MAX]; + /* Access control for this session and list entry there */ struct scst_acg *acg; diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index 1ddde00aa..4a2a77f86 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -186,7 +186,7 @@ enum scst_cdb_flags { /************************************************************* ** Data direction aliases. Changing it don't forget to change - ** scst_to_tgt_dma_dir as well!! + ** scst_to_tgt_dma_dir and SCST_DATA_DIR_MAX as well!! *************************************************************/ #define SCST_DATA_UNKNOWN 0 #define SCST_DATA_WRITE 1 @@ -194,6 +194,8 @@ enum scst_cdb_flags { #define SCST_DATA_BIDI (SCST_DATA_WRITE | SCST_DATA_READ) #define SCST_DATA_NONE 4 +#define SCST_DATA_DIR_MAX (SCST_DATA_NONE+1) + #ifdef CONFIG_SCST_PROC /************************************************************* diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 3052ef790..e82609dd8 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -3400,10 +3400,69 @@ static struct kobj_attribute session_initiator_name_attr = __ATTR(initiator_name, S_IRUGO, scst_sess_sysfs_initiator_name_show, NULL); +#define SCST_SESS_SYSFS_STAT_ATTR(name, exported_name, dir, kb) \ +static ssize_t scst_sess_sysfs_##exported_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ +{ \ + struct scst_session *sess; \ + int res; \ + uint64_t v; \ + \ + BUILD_BUG_ON(SCST_DATA_UNKNOWN != 0); \ + BUILD_BUG_ON(SCST_DATA_WRITE != 1); \ + BUILD_BUG_ON(SCST_DATA_READ != 2); \ + BUILD_BUG_ON(SCST_DATA_BIDI != 3); \ + BUILD_BUG_ON(SCST_DATA_NONE != 4); \ + \ + BUILD_BUG_ON(dir >= SCST_DATA_DIR_MAX); \ + \ + sess = container_of(kobj, struct scst_session, sess_kobj); \ + v = sess->io_stats[dir].name; \ + if (kb) \ + v >>= 10; \ + res = sprintf(buf, "%llu\n", (unsigned long long)v); \ + return res; \ +} \ + \ +static ssize_t scst_sess_sysfs_##exported_name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, const char *buf, size_t count) \ +{ \ + struct scst_session *sess; \ + sess = container_of(kobj, struct scst_session, sess_kobj); \ + spin_lock_irq(&sess->sess_list_lock); \ + BUILD_BUG_ON(dir >= SCST_DATA_DIR_MAX); \ + sess->io_stats[dir].cmd_count = 0; \ + sess->io_stats[dir].io_byte_count = 0; \ + spin_unlock_irq(&sess->sess_list_lock); \ + return count; \ +} \ + \ +static struct kobj_attribute session_##exported_name##_attr = \ + __ATTR(exported_name, S_IRUGO | S_IWUSR, \ + scst_sess_sysfs_##exported_name##_show, \ + scst_sess_sysfs_##exported_name##_store); + +SCST_SESS_SYSFS_STAT_ATTR(cmd_count, unknown_cmd_count, SCST_DATA_UNKNOWN, 0); +SCST_SESS_SYSFS_STAT_ATTR(cmd_count, write_cmd_count, SCST_DATA_WRITE, 0); +SCST_SESS_SYSFS_STAT_ATTR(io_byte_count, write_io_count_kb, SCST_DATA_WRITE, 1); +SCST_SESS_SYSFS_STAT_ATTR(cmd_count, read_cmd_count, SCST_DATA_READ, 0); +SCST_SESS_SYSFS_STAT_ATTR(io_byte_count, read_io_count_kb, SCST_DATA_READ, 1); +SCST_SESS_SYSFS_STAT_ATTR(cmd_count, bidi_cmd_count, SCST_DATA_BIDI, 0); +SCST_SESS_SYSFS_STAT_ATTR(io_byte_count, bidi_io_count_kb, SCST_DATA_BIDI, 1); +SCST_SESS_SYSFS_STAT_ATTR(cmd_count, none_cmd_count, SCST_DATA_NONE, 0); + static struct attribute *scst_session_attrs[] = { &session_commands_attr.attr, &session_active_commands_attr.attr, &session_initiator_name_attr.attr, + &session_unknown_cmd_count_attr.attr, + &session_write_cmd_count_attr.attr, + &session_write_io_count_kb_attr.attr, + &session_read_cmd_count_attr.attr, + &session_read_io_count_kb_attr.attr, + &session_bidi_cmd_count_attr.attr, + &session_bidi_io_count_kb_attr.attr, + &session_none_cmd_count_attr.attr, #ifdef CONFIG_SCST_MEASURE_LATENCY &session_latency_attr.attr, #endif /* CONFIG_SCST_MEASURE_LATENCY */ diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 72535142b..104159676 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -3565,6 +3565,7 @@ static int scst_finish_cmd(struct scst_cmd *cmd) { int res; struct scst_session *sess = cmd->sess; + struct scst_io_stat_entry *stat; TRACE_ENTRY(); @@ -3588,7 +3589,13 @@ static int scst_finish_cmd(struct scst_cmd *cmd) atomic_dec(&sess->sess_cmd_count); spin_lock_irq(&sess->sess_list_lock); + + stat = &sess->io_stats[cmd->data_direction]; + stat->cmd_count++; + stat->io_byte_count += cmd->bufflen + cmd->out_bufflen; + list_del(&cmd->sess_cmd_list_entry); + spin_unlock_irq(&sess->sess_list_lock); cmd->finished = 1;