I/O request can be splitted for two or more requests, if it's size is greater than queue/max_sectors_kb setting. Knowledge of splits frequency helps to understand workload profile better and to make decision to tune queue/max_sectors_kb. This patch adds three counters to /sys/class/block/$dev/stat and /proc/diskstats: number of reads, writes and discards splitted. There's also counter for flush requests, but it is ignored, because flush cannot be splitted. --- Documentation/ABI/testing/procfs-diskstats | 3 +++ Documentation/ABI/testing/sysfs-block | 5 ++++- Documentation/admin-guide/iostats.rst | 10 ++++++++++ block/bio.c | 2 ++ block/blk-core.c | 2 ++ block/genhd.c | 8 ++++++-- block/partition-generic.c | 8 ++++++-- include/linux/genhd.h | 1 + 8 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Documentation/ABI/testing/procfs-diskstats b/Documentation/ABI/testing/procfs-diskstats index 70dcaf2481f4..e1473e93d901 100644 --- a/Documentation/ABI/testing/procfs-diskstats +++ b/Documentation/ABI/testing/procfs-diskstats @@ -33,5 +33,8 @@ Description: 19 - flush requests completed successfully 20 - time spent flushing + 21 - reads splitted + 22 - writes splitted + 23 - discards splitted For more details refer to Documentation/admin-guide/iostats.rst diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index ed8c14f161ee..ffbac0e72508 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -3,7 +3,7 @@ Date: February 2008 Contact: Jerome Marchand <jmarchan@xxxxxxxxxx> Description: The /sys/block/<disk>/stat files displays the I/O - statistics of disk <disk>. They contain 11 fields: + statistics of disk <disk>. They contain 20 fields: 1 - reads completed successfully 2 - reads merged 3 - sectors read @@ -21,6 +21,9 @@ Description: 15 - time spent discarding (ms) 16 - flush requests completed 17 - time spent flushing (ms) + 18 - reads splitted + 19 - writes splitted + 20 - discrads splitted For more details refer Documentation/admin-guide/iostats.rst diff --git a/Documentation/admin-guide/iostats.rst b/Documentation/admin-guide/iostats.rst index 4f0462af3ca7..7f3f374b82b7 100644 --- a/Documentation/admin-guide/iostats.rst +++ b/Documentation/admin-guide/iostats.rst @@ -130,6 +130,16 @@ Field 16 -- # of flush requests completed Field 17 -- # of milliseconds spent flushing This is the total number of milliseconds spent by all flush requests. +Field 18 -- # of reads splitted, field 19 -- # of writes splitted + This is the total number of requests splitted before queue. + + The maximum size of I/O is limited by queue/max_sectors_kb. + If size of I/O is greater than this limit, it will be splitted + as many times as needed to keep I/O size withing the limit. + +Field 20 -- # of discrads Splitted + See description of fileds 18 and 19. + To avoid introducing performance bottlenecks, no locks are held while modifying these counters. This implies that minor inaccuracies may be introduced when changes collide, so (for instance) adding up all the diff --git a/block/bio.c b/block/bio.c index 8f0ed6228fc5..c8a051e128f8 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1855,6 +1855,8 @@ struct bio *bio_split(struct bio *bio, int sectors, if (bio_flagged(bio, BIO_TRACE_COMPLETION)) bio_set_flag(split, BIO_TRACE_COMPLETION); + bio_set_flag(split, BIO_SPLITTED); + return split; } EXPORT_SYMBOL(bio_split); diff --git a/block/blk-core.c b/block/blk-core.c index f0d82227a2fc..776d28b9a5bf 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1379,6 +1379,8 @@ void blk_account_io_start(struct request *rq, bool new_io) } part_inc_in_flight(rq->q, part, rw); rq->part = part; + if (bio_flagged(rq->bio, BIO_SPLITTED)) + part_stat_inc(part, splits[rw]); } update_io_ticks(part, jiffies); diff --git a/block/genhd.c b/block/genhd.c index ff6268970ddc..adb38baa24dc 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1386,7 +1386,8 @@ static int diskstats_show(struct seq_file *seqf, void *v) "%lu %lu %lu %u " "%u %u %u " "%lu %lu %lu %u " - "%lu %u" + "%lu %u " + "%lu %lu %lu" "\n", MAJOR(part_devt(hd)), MINOR(part_devt(hd)), disk_name(gp, hd->partno, buf), @@ -1406,7 +1407,10 @@ static int diskstats_show(struct seq_file *seqf, void *v) part_stat_read(hd, sectors[STAT_DISCARD]), (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD), part_stat_read(hd, ios[STAT_FLUSH]), - (unsigned int)part_stat_read_msecs(hd, STAT_FLUSH) + (unsigned int)part_stat_read_msecs(hd, STAT_FLUSH), + part_stat_read(hd, splits[STAT_READ]), + part_stat_read(hd, splits[STAT_WRITE]), + part_stat_read(hd, splits[STAT_DISCARD]) ); } disk_part_iter_exit(&piter); diff --git a/block/partition-generic.c b/block/partition-generic.c index 3db8b73a96b1..61e26ec21256 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -128,7 +128,8 @@ ssize_t part_stat_show(struct device *dev, "%8lu %8lu %8llu %8u " "%8u %8u %8u " "%8lu %8lu %8llu %8u " - "%8lu %8u" + "%8lu %8u " + "%8lu %8lu %8lu" "\n", part_stat_read(p, ios[STAT_READ]), part_stat_read(p, merges[STAT_READ]), @@ -146,7 +147,10 @@ ssize_t part_stat_show(struct device *dev, (unsigned long long)part_stat_read(p, sectors[STAT_DISCARD]), (unsigned int)part_stat_read_msecs(p, STAT_DISCARD), part_stat_read(p, ios[STAT_FLUSH]), - (unsigned int)part_stat_read_msecs(p, STAT_FLUSH)); + (unsigned int)part_stat_read_msecs(p, STAT_FLUSH), + part_stat_read(p, splits[STAT_READ]), + part_stat_read(p, splits[STAT_WRITE]), + part_stat_read(p, splits[STAT_DISCARD])); } ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 8b5330dd5ac0..ea502e7b12b6 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -88,6 +88,7 @@ struct disk_stats { unsigned long sectors[NR_STAT_GROUPS]; unsigned long ios[NR_STAT_GROUPS]; unsigned long merges[NR_STAT_GROUPS]; + unsigned long splits[NR_STAT_GROUPS]; unsigned long io_ticks; unsigned long time_in_queue; local_t in_flight[2]; -- 2.17.1