New version of statistics patch: - Removed sysfs file containing hint for number of tape drives - Removed disk like stat file - there is now one file per statistic as per feedback from James - Like all other kernel stats these start at zero and keep incrementing (cannot zero them any more) - Implemented a method where the statistics files can be frozen at a point in time to allow consistent statistics to be read from the group of statistics files (permissions on the sync file limit mean you need an euid of 0 to freeze the statistics) - Example output of statistics directory: # ll /sys/class/scsi_tape/st0/device/statistics total 0 -r--r--r--. 1 root root 4096 May 3 06:32 in_flight -r--r--r--. 1 root root 4096 May 3 06:32 io_ms -r--r--r--. 1 root root 4096 May 3 06:32 other_cnt -r--r--r--. 1 root root 4096 May 3 06:32 read_block_cnt -r--r--r--. 1 root root 4096 May 3 06:32 read_byte_cnt -r--r--r--. 1 root root 4096 May 3 06:32 read_cnt -r--r--r--. 1 root root 4096 May 3 06:32 read_ms -rw-rw-r--. 1 root root 4096 May 3 06:41 sync -r--r--r--. 1 root root 4096 May 3 06:32 write_block_cnt -r--r--r--. 1 root root 4096 May 3 06:32 write_byte_cnt -r--r--r--. 1 root root 4096 May 3 06:32 write_cnt -r--r--r--. 1 root root 4096 May 3 06:32 write_ms Needs the previous patch I sent this week titled "st: clear driver data from struct device when released" to be applied before this one (the diff below is not against a vanilla 3.9 kernel it is against 3.9 with that patch applied to it to get this patch). Signed-off-by: Shane Seymour <shane.seymour@xxxxxx> Tested-by: Shane Seymour <shane.seymour@xxxxxx> --- diff -uprN -X linux-3.9-vanilla/Documentation/dontdiff linux-3.9-vanilla/drivers/scsi/st.c linux-3.9/drivers/scsi/st.c --- linux-3.9-vanilla/drivers/scsi/st.c 2013-05-03 05:46:32.000000000 +0100 +++ linux-3.9/drivers/scsi/st.c 2013-05-03 06:46:55.000000000 +0100 @@ -218,6 +218,15 @@ static DEFINE_SPINLOCK(st_index_lock); static DEFINE_SPINLOCK(st_use_lock); static DEFINE_IDR(st_index_idr); +static inline void st_stats_remove_files(struct scsi_tape *); +static inline void st_stats_create_files(struct scsi_tape *); +static ssize_t st_tape_attr_show(struct kobject *, struct attribute *, char *); +static ssize_t st_tape_attr_store(struct kobject *, struct attribute *, + const char *, size_t); +static const struct sysfs_ops st_stats_sysfs_ops = { + .show = st_tape_attr_show, + .store = st_tape_attr_store, +}; #include "osst_detect.h" @@ -458,10 +467,19 @@ static void st_scsi_execute_end(struct r struct st_request *SRpnt = req->end_io_data; struct scsi_tape *STp = SRpnt->stp; struct bio *tmp; + u64 ticks = get_jiffies_64(); STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; STp->buffer->cmdstat.residual = req->resid_len; + STp->in_flight--; + ticks -= STp->stamp; + STp->io_ticks += ticks; + if (req->cmd[0] == WRITE_6) + STp->write_ticks += ticks; + else if (req->cmd[0] == READ_6) + STp->read_ticks += ticks; + tmp = SRpnt->bio; if (SRpnt->waiting) complete(SRpnt->waiting); @@ -478,6 +496,7 @@ static int st_scsi_execute(struct st_req struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; int err = 0; int write = (data_direction == DMA_TO_DEVICE); + struct scsi_tape *STp = SRpnt->stp; req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); @@ -498,6 +517,18 @@ static int st_scsi_execute(struct st_req } } + if (cmd[0] == WRITE_6) { + STp->write_cnt++; + STp->write_byte_cnt += bufflen; + } else if (cmd[0] == READ_6) { + STp->read_cnt++; + STp->read_byte_cnt += bufflen; + } else { + STp->other_cnt++; + } + STp->stamp = get_jiffies_64(); + STp->in_flight++; + SRpnt->bio = req->bio; req->cmd_len = COMMAND_SIZE(cmd[0]); memset(req->cmd, 0, BLK_MAX_CDB); @@ -4048,6 +4079,14 @@ static int create_cdevs(struct scsi_tape if (error) return error; } +/* Create statistics directory under device, if it fails we dont + have statistics. */ + tape->statistics = kobject_create_and_add("statistics", + &tape->device->sdev_gendev.kobj); + if (tape->statistics != 0) { + st_stats_create_files(tape); + tape->statistics->ktype->sysfs_ops = &st_stats_sysfs_ops; + } return sysfs_create_link(&tape->device->sdev_gendev.kobj, &tape->modes[0].devs[0]->kobj, "tape"); @@ -4057,6 +4096,10 @@ static void remove_cdevs(struct scsi_tap { int mode, rew; sysfs_remove_link(&tape->device->sdev_gendev.kobj, "tape"); + if (tape->statistics != 0) { + st_stats_remove_files(tape); + kobject_put(tape->statistics); + } for (mode = 0; mode < ST_NBR_MODES; mode++) { struct st_modedef *STm = &(tape->modes[mode]); for (rew = 0; rew < 2; rew++) { @@ -4127,6 +4170,28 @@ static int st_probe(struct device *dev) tpnt->buffer = buffer; tpnt->buffer->last_SRpnt = NULL; + tpnt->statistics = 0; + tpnt->read_byte_cnt = 0; + tpnt->write_byte_cnt = 0; + tpnt->read_cnt = 0; + tpnt->write_cnt = 0; + tpnt->other_cnt = 0; + tpnt->in_flight = 0; + tpnt->read_ticks = 0; + tpnt->write_ticks = 0; + tpnt->io_ticks = 0; + tpnt->stamp = 0; + tpnt->sync = 0; + tpnt->sync_read_byte_cnt = 0; + tpnt->sync_write_byte_cnt = 0; + tpnt->sync_in_flight = 0; + tpnt->sync_read_cnt = 0; + tpnt->sync_write_cnt = 0; + tpnt->sync_other_cnt = 0; + tpnt->sync_read_ticks = 0; + tpnt->sync_write_ticks = 0; + tpnt->sync_io_ticks = 0; + tpnt->inited = 0; tpnt->dirty = 0; tpnt->in_use = 0; @@ -4484,6 +4549,439 @@ static struct device_attribute st_dev_at __ATTR_NULL, }; +/* Support for tape stats */ + +struct tape_stats_attr { + struct attribute attr; + ssize_t (*show)(struct scsi_tape *, char *); + ssize_t (*store)(struct scsi_tape *, const char *, size_t); +}; + +#define TAPE_STATS_ATTR(_name, _mode, _show, _store) \ +struct tape_stats_attr tape_stats_attr_##_name = { \ + .attr = {.name = __stringify(_name) , .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +/** + * st_stats_create_file - create sysfs tape stats attribute file + * @st: scsi_tape structure. + * @attr: device attribute descriptor. + */ +static inline int st_stats_create_file(struct scsi_tape *st, + const struct tape_stats_attr *attr) +{ + int error = 0; + if (st) + error = sysfs_create_file(st->statistics, &attr->attr); + return error; +} + +/** + * st_stats_remove_file - remove sysfs atape stats attribute file. + * @st: scsi_tape structure. + * @attr: device attribute descriptor. + */ +static inline void st_stats_remove_file(struct scsi_tape *st, + const struct tape_stats_attr *attr) +{ + if (st) + sysfs_remove_file(st->statistics, &attr->attr); +} + +/** + * st_stats_attr_show_read_cnt - return read count - count of reads made + * from tape drive + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_read_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->read_cnt); + return snprintf(buf, 4096, "%llu", st->sync_read_cnt); +} + +/** + * st_stats_attr_show_read_byte_cnt - return read byte count - tape drives + * may use blocks less than 512 bytes this gives the raw byte count of + * of data read from the tape drive. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_read_byte_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->read_byte_cnt); + return snprintf(buf, 4096, "%llu", st->sync_read_byte_cnt); +} + +/** + * st_stats_attr_show_read_block_cnt - return read block count - + * provides disk like data for someone expecting that instead of wanting + * byte counts. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_read_block_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->read_byte_cnt >> 9); + return snprintf(buf, 4096, "%llu", st->sync_read_byte_cnt >> 9); +} + +/** + * st_stats_attr_show_read_ms - return read ms - overall time spent waiting + * on reads in ms. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_read_ms(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%u", + jiffies_to_msecs(st->read_ticks)); + return snprintf(buf, 4096, "%u", jiffies_to_msecs(st->sync_read_ticks)); +} + +/** + * st_stats_attr_show_write_cnt - write count - number of user calls + * to write(2) that have written data to tape. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_write_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->write_cnt); + return snprintf(buf, 4096, "%llu", st->sync_write_cnt); +} + +/** + * st_stats_attr_show_write_byte_cnt - write byte count - raw count of + * bytes written to tape. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_write_byte_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->write_byte_cnt); + return snprintf(buf, 4096, "%llu", st->sync_write_byte_cnt); +} + +/** + * st_stats_attr_show_write_block_cnt - write block total - raw count of + * 512 byte blocks written to tape. This is for compatability + * with disk type information although it doesn't mean much for tapes since + * they can have a block size of less than 512 bytes. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_write_block_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->write_byte_cnt >> 9); + return snprintf(buf, 4096, "%llu", st->sync_write_byte_cnt >> 9); +} + +/** + * st_stats_attr_show_write_ms - write ms - number of milliseconds since + * last open waiting on write requests to complete. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_write_ms(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%u", + jiffies_to_msecs(st->write_ticks)); + return snprintf(buf, 4096, "%u", + jiffies_to_msecs(st->sync_write_ticks)); +} + +/** + * st_stats_attr_show_in_flight - number of I/Os currently in flight - + * in most cases this will be either 0 or 1. It may be higher if someone + * has also issued other SCSI commands such as via an ioctl. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_in_flight(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->in_flight); + return snprintf(buf, 4096, "%llu", st->sync_in_flight); +} + +/** + * st_stats_attr_show_io_ms - io wait ms - this is the number of ms spent + * waiting on other I/O to complete. This includes tape movement commands + * such as rewinding, seeking to end of file or tape, etc. Except in + * complex tape management programs these will be indirect commands issued + * by the driver - e.g. rewind on close. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_io_ms(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%u", + jiffies_to_msecs(st->io_ticks)); + return snprintf(buf, 4096, "%u", jiffies_to_msecs(st->sync_io_ticks)); +} + +/** + * st_stats_attr_show_other_cnt - other io count - this is the number of + * I/O requests that make up the time returned from st_stats_attr_show_io_ms. + * Typically these are tape movement requests but will include driver + * tape movement. This includes on requests seen by the st driver. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_other_cnt(struct scsi_tape *st, char *buf) +{ + if (st->sync == 0) + return snprintf(buf, 4096, "%llu", st->other_cnt); + return snprintf(buf, 4096, "%llu", st->sync_other_cnt); +} +/** + * st_stats_attr_show_sync - if 0 is returned the stats are being read + * directly and are not in sync. Anyone using the sync interface should + * chose a random value that nobody else will use. Every time you want the + * stats updated you write the same value into the sync file to cause + * them to be copied. You can read this back when done to see if someone + * else has changed the sync value (i.e. someone else has caused an update + * to happen. You can either read them again after writing your sync + * value back or take the stats as they are forewarned that they may not + * be completely in sync. + * If you do not care about them being in sync you need to take some + * action if the sync value is non-zero as someone could have left it + * non-zero which means the values never change. You should write a "0" + * to the sync file before you read the read the other stats files. + * @st: scsi_tape structure. + * @buf: buffer to return formatted data in + */ +ssize_t st_stats_attr_show_sync(struct scsi_tape *st, char *buf) +{ + return snprintf(buf, 4096, "%llu", st->sync); +} + +ssize_t st_stats_attr_store_sync(struct scsi_tape *st, const char *buf, + size_t len) +{ + if (sscanf(buf, "%llu", &st->sync) != 1) + st->sync = 0; + if (st->sync == 0) + return len; + st->sync_read_byte_cnt = st->read_byte_cnt; + st->sync_write_byte_cnt = st->write_byte_cnt; + st->sync_in_flight = st->in_flight; + st->sync_read_cnt = st->read_cnt; + st->sync_write_cnt = st->write_cnt; + st->sync_other_cnt = st->other_cnt; + st->sync_read_ticks = st->read_ticks; + st->sync_write_ticks = st->write_ticks; + st->sync_io_ticks = st->io_ticks; + return len; +} + +TAPE_STATS_ATTR(read_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_read_cnt, NULL); +TAPE_STATS_ATTR(read_byte_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_read_byte_cnt, NULL); +TAPE_STATS_ATTR(read_block_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_read_block_cnt, NULL); +TAPE_STATS_ATTR(read_ms, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_read_ms, NULL); +TAPE_STATS_ATTR(write_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_write_cnt, NULL); +TAPE_STATS_ATTR(write_byte_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_write_byte_cnt, NULL); +TAPE_STATS_ATTR(write_block_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_write_block_cnt, NULL); +TAPE_STATS_ATTR(write_ms, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_write_ms, NULL); +TAPE_STATS_ATTR(in_flight, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_in_flight, NULL); +TAPE_STATS_ATTR(io_ms, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_io_ms, NULL); +TAPE_STATS_ATTR(other_cnt, S_IRUSR | S_IRGRP | S_IROTH, + st_stats_attr_show_other_cnt, NULL); +TAPE_STATS_ATTR(sync, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + st_stats_attr_show_sync, st_stats_attr_store_sync); + +/** + * st_stats_create_files - register files in the device + * statistics directory. + * @st: scsi_tape structure. + */ +static inline void st_stats_create_files(struct scsi_tape *st) +{ + if (st_stats_create_file(st, &tape_stats_attr_read_cnt)) + goto error_read_cnt; + if (st_stats_create_file(st, &tape_stats_attr_read_byte_cnt)) + goto error_read_byte_cnt; + if (st_stats_create_file(st, &tape_stats_attr_read_block_cnt)) + goto error_read_block_cnt; + if (st_stats_create_file(st, &tape_stats_attr_read_ms)) + goto error_read_ms; + if (st_stats_create_file(st, &tape_stats_attr_write_cnt)) + goto error_write_cnt; + if (st_stats_create_file(st, &tape_stats_attr_write_byte_cnt)) + goto error_write_byte_cnt; + if (st_stats_create_file(st, &tape_stats_attr_write_block_cnt)) + goto error_write_block_cnt; + if (st_stats_create_file(st, &tape_stats_attr_write_ms)) + goto error_write_ms; + if (st_stats_create_file(st, &tape_stats_attr_in_flight)) + goto error_in_flight; + if (st_stats_create_file(st, &tape_stats_attr_io_ms)) + goto error_io_ms; + if (st_stats_create_file(st, &tape_stats_attr_other_cnt)) + goto error_other_cnt; + if (st_stats_create_file(st, &tape_stats_attr_sync)) + goto error_sync; + return; +error_sync: + st_stats_remove_file(st, &tape_stats_attr_sync); +error_other_cnt: + st_stats_remove_file(st, &tape_stats_attr_other_cnt); +error_io_ms: + st_stats_remove_file(st, &tape_stats_attr_io_ms); +error_in_flight: + st_stats_remove_file(st, &tape_stats_attr_in_flight); +error_write_ms: + st_stats_remove_file(st, &tape_stats_attr_write_ms); +error_write_block_cnt: + st_stats_remove_file(st, &tape_stats_attr_write_block_cnt); +error_write_byte_cnt: + st_stats_remove_file(st, &tape_stats_attr_write_byte_cnt); +error_write_cnt: + st_stats_remove_file(st, &tape_stats_attr_write_cnt); +error_read_ms: + st_stats_remove_file(st, &tape_stats_attr_read_ms); +error_read_block_cnt: + st_stats_remove_file(st, &tape_stats_attr_read_block_cnt); +error_read_byte_cnt: + st_stats_remove_file(st, &tape_stats_attr_read_byte_cnt); +error_read_cnt: + st_stats_remove_file(st, &tape_stats_attr_read_cnt); +} + +#define to_tape_stats_attr(ptr) container_of(ptr, struct tape_stats_attr, attr) + +/** + * st_tape_attr_store - call functions required to implement the store + * functionality. Works similar to show function. + * @kobj: struct kobject + * @attr: struct attribute + * @buf: data provided by caller + * @len: length of data provided + */ +static ssize_t st_tape_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) +{ + struct kobject *ktemp = kobj->parent; + struct device *dev; + struct scsi_tape *st; + struct tape_stats_attr *st_attr = to_tape_stats_attr(attr); + ssize_t ret = -EIO; + + if ((!st_attr->store) || (ktemp == 0)) + return ret; + dev = kobj_to_dev(ktemp); + if (dev == 0) + return ret; + + mutex_lock(&st_ref_mutex); + st = dev_get_drvdata(dev); + if (st == 0) { + mutex_unlock(&st_ref_mutex); + return ret; + } + kref_get(&st->kref); + mutex_unlock(&st_ref_mutex); + + if (st_attr->store) + ret = st_attr->store(st, buf, len); + + mutex_lock(&st_ref_mutex); + kref_put(&st->kref, scsi_tape_release); + mutex_unlock(&st_ref_mutex); + + return ret; +} + +/** + * st_tape_attr_show - call the functions that provide the statistics. + * This function makes sure that the struct scsi_tape being refered to is + * current and has not been deleted (e.g. during an unload of the st + * driver or the tape drive disappearing). + * @kobj: struct kobject + * @attr: struct attribute + * @buf: data being returned to caller + */ +static ssize_t st_tape_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct kobject *ktemp = kobj->parent; + struct device *dev; + struct scsi_tape *st; + struct tape_stats_attr *st_attr = to_tape_stats_attr(attr); + ssize_t ret = -EIO; + +/* kobject passed in is for the statistics directory. We need to look at the + parent kobject (part of a struct device) and from there get the struct + scsi_tape. If no show function return error as well. */ + if ((!st_attr->show) || (ktemp == 0)) + return ret; + dev = kobj_to_dev(ktemp); + if (dev == 0) + return ret; +/* dev_get_drvdata must return 0 if the struct scsi_tape has been freed. + Holding st_ref_mutex means it cannot be freed while we check and we + grab a reference to the struct scsi_tape before unlocking. */ + mutex_lock(&st_ref_mutex); + st = dev_get_drvdata(dev); + if (st == 0) { + mutex_unlock(&st_ref_mutex); + return ret; + } + kref_get(&st->kref); + mutex_unlock(&st_ref_mutex); + + if (st_attr->show) + ret = st_attr->show(st, buf); + + mutex_lock(&st_ref_mutex); + kref_put(&st->kref, scsi_tape_release); + mutex_unlock(&st_ref_mutex); + + return ret; +} + +/** + * st_stats_remove_files - remove the files from the statistics directory. + * @st: struct scsi_tape + */ +static inline void st_stats_remove_files(struct scsi_tape *st) +{ + st_stats_remove_file(st, &tape_stats_attr_other_cnt); + st_stats_remove_file(st, &tape_stats_attr_io_ms); + st_stats_remove_file(st, &tape_stats_attr_in_flight); + st_stats_remove_file(st, &tape_stats_attr_write_ms); + st_stats_remove_file(st, &tape_stats_attr_write_block_cnt); + st_stats_remove_file(st, &tape_stats_attr_write_byte_cnt); + st_stats_remove_file(st, &tape_stats_attr_write_cnt); + st_stats_remove_file(st, &tape_stats_attr_read_ms); + st_stats_remove_file(st, &tape_stats_attr_read_block_cnt); + st_stats_remove_file(st, &tape_stats_attr_read_byte_cnt); + st_stats_remove_file(st, &tape_stats_attr_read_cnt); + st_stats_remove_file(st, &tape_stats_attr_sync); +} + /* The following functions may be useful for a larger audience. */ static int sgl_map_user_pages(struct st_buffer *STbp, const unsigned int max_pages, unsigned long uaddr, diff -uprN -X linux-3.9-vanilla/Documentation/dontdiff linux-3.9-vanilla/drivers/scsi/st.h linux-3.9/drivers/scsi/st.h --- linux-3.9-vanilla/drivers/scsi/st.h 2013-04-29 01:36:01.000000000 +0100 +++ linux-3.9/drivers/scsi/st.h 2013-05-03 03:25:40.000000000 +0100 @@ -158,6 +158,29 @@ struct scsi_tape { int max_block; int recover_count; /* From tape opening */ int recover_reg; /* From last status call */ +/* Statistics variables */ + struct kobject *statistics; /* Object for statistics directory */ + u64 read_byte_cnt; /* bytes read */ + u64 write_byte_cnt; /* bytes written */ + u64 in_flight; /* Number of I/Os in flight */ + u64 read_cnt; /* Count of read requests */ + u64 write_cnt; /* Count of write requests */ + u64 other_cnt; /* Count of other requests either implicit + or from user space via ioctl. */ + u64 read_ticks; /* Ticks spent completing read requests */ + u64 write_ticks; /* Ticks spent completing write requests */ + u64 io_ticks; /* Ticks spent doing any I/O */ + u64 stamp; /* holds time request was queued */ + u64 sync; /* Are stats read in sync */ + u64 sync_read_byte_cnt; + u64 sync_write_byte_cnt; + u64 sync_in_flight; + u64 sync_read_cnt; + u64 sync_write_cnt; + u64 sync_other_cnt; + u64 sync_read_ticks; + u64 sync_write_ticks; + u64 sync_io_ticks; #if DEBUG unsigned char write_pending; -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html