From: Konstantin Khlebnikov khlebnikov@yandex-team.ru
mainline inclusion from mainline-v5.7-rc1 commit 2b8bd423614c595540eaadcfbc702afe8e155e50 category: bugfix bugzilla: 187044, https://gitee.com/openeuler/kernel/issues/I5F2BY CVE: NA
--------------------------------
Currently io_ticks is approximated by adding one at each start and end of requests if jiffies counter has changed. This works perfectly for requests shorter than a jiffy or if one of requests starts/ends at each jiffy.
If disk executes just one request at a time and they are longer than two jiffies then only first and last jiffies will be accounted.
Fix is simple: at the end of request add up into io_ticks jiffies passed since last update rather than just one jiffy.
Example: common HDD executes random read 4k requests around 12ms.
fio --name=test --filename=/dev/sdb --rw=randread --direct=1 --runtime=30 & iostat -x 10 sdb
Note changes of iostat's "%util" 8,43% -> 99,99% before/after patch:
Before:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0,00 0,00 82,60 0,00 330,40 0,00 8,00 0,96 12,09 12,09 0,00 1,02 8,43
After:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util sdb 0,00 0,00 82,50 0,00 330,00 0,00 8,00 1,00 12,10 12,10 0,00 12,12 99,99
Now io_ticks does not loose time between start and end of requests, but for queue-depth > 1 some I/O time between adjacent starts might be lost.
For load estimation "%util" is not as useful as average queue length, but it clearly shows how often disk queue is completely empty.
Fixes: 5b18b5a73760 ("block: delete part_round_stats and switch to less precise counting") Signed-off-by: Konstantin Khlebnikov khlebnikov@yandex-team.ru Reviewed-by: Ming Lei ming.lei@redhat.com Signed-off-by: Jens Axboe axboe@kernel.dk
Conflict: block/bio.c block/blk-core.c include/linux/genhd.h Signed-off-by: Zhang Wensheng zhangwensheng5@huawei.com Reviewed-by: Yu Kuai yukuai3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- block/bio.c | 6 +++--- block/blk-core.c | 2 +- include/linux/genhd.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/block/bio.c b/block/bio.c index 6457cbfa70cc..b5bbc023d64d 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1668,14 +1668,14 @@ void bio_check_pages_dirty(struct bio *bio) } EXPORT_SYMBOL_GPL(bio_check_pages_dirty);
-void update_io_ticks(int cpu, struct hd_struct *part, unsigned long now) +void update_io_ticks(int cpu, struct hd_struct *part, unsigned long now, bool end) { unsigned long stamp; again: stamp = READ_ONCE(part->stamp); if (unlikely(stamp != now)) { if (likely(cmpxchg(&part->stamp, stamp, now) == stamp)) - __part_stat_add(cpu, part, io_ticks, now - stamp); + __part_stat_add(cpu, part, io_ticks, end ? now - stamp : 1); } if (part->partno) { part = &part_to_disk(part)->part0; @@ -1709,7 +1709,7 @@ void generic_end_io_acct(struct request_queue *q, int req_op, if (precise_iostat) { part_round_stats(q, cpu, part); } else { - update_io_ticks(cpu, part, now); + update_io_ticks(cpu, part, now, true); part_stat_add(cpu, part, time_in_queue, duration); } part_stat_add(cpu, part, nsecs[sgrp], jiffies_to_nsecs(duration)); diff --git a/block/blk-core.c b/block/blk-core.c index a5d80ab91170..5892c532ae5b 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2809,7 +2809,7 @@ void blk_account_io_done(struct request *req, u64 now) part = req->part;
if (!precise_iostat) { - update_io_ticks(cpu, part, jiffies); + update_io_ticks(cpu, part, jiffies, true); part_stat_add(cpu, part, time_in_queue, nsecs_to_jiffies64(now - req->start_time_ns)); } else { diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 264326ae5a90..58a819484fb4 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -427,7 +427,7 @@ static inline void free_part_info(struct hd_struct *part)
/* block/blk-core.c */ extern void part_round_stats(struct request_queue *q, int cpu, struct hd_struct *part); -void update_io_ticks(int cpu, struct hd_struct *part, unsigned long now); +void update_io_ticks(int cpu, struct hd_struct *part, unsigned long now, bool end);
/* block/genhd.c */ extern void device_add_disk(struct device *parent, struct gendisk *disk);