block: add disk/bio-based accounting helpers
authorChristoph Hellwig <hch@lst.de>
Wed, 27 May 2020 05:24:04 +0000 (07:24 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 27 May 2020 11:21:23 +0000 (05:21 -0600)
Add two new helpers to simplify I/O accounting for bio based drivers.
Currently these drivers use the generic_start_io_acct and
generic_end_io_acct helpers which have very cumbersome calling
conventions, don't actually return the time they started accounting,
and try to deal with accounting for partitions, which can't happen
for bio based drivers.  The new helpers will be used to subsequently
replace uses of the old helpers.

The main API is the bio based wrappes in blkdev.h, but for zram
which wants to account rw_page based I/O lower level routines are
provided as well.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-core.c
include/linux/blkdev.h

index 77e57c2e8d6023ece25d5ceb3e6e6f4f0d647fac..8973104f88d907a494d5a53b857e0566e59c451a 100644 (file)
@@ -1432,6 +1432,40 @@ void blk_account_io_start(struct request *rq, bool new_io)
        part_stat_unlock();
 }
 
+unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
+               unsigned int op)
+{
+       struct hd_struct *part = &disk->part0;
+       const int sgrp = op_stat_group(op);
+       unsigned long now = READ_ONCE(jiffies);
+
+       part_stat_lock();
+       update_io_ticks(part, now, false);
+       part_stat_inc(part, ios[sgrp]);
+       part_stat_add(part, sectors[sgrp], sectors);
+       part_stat_local_inc(part, in_flight[op_is_write(op)]);
+       part_stat_unlock();
+
+       return now;
+}
+EXPORT_SYMBOL(disk_start_io_acct);
+
+void disk_end_io_acct(struct gendisk *disk, unsigned int op,
+               unsigned long start_time)
+{
+       struct hd_struct *part = &disk->part0;
+       const int sgrp = op_stat_group(op);
+       unsigned long now = READ_ONCE(jiffies);
+       unsigned long duration = now - start_time;
+
+       part_stat_lock();
+       update_io_ticks(part, now, true);
+       part_stat_add(part, nsecs[sgrp], jiffies_to_nsecs(duration));
+       part_stat_local_dec(part, in_flight[op_is_write(op)]);
+       part_stat_unlock();
+}
+EXPORT_SYMBOL(disk_end_io_acct);
+
 /*
  * Steal bios from a request and add them to a bio list.
  * The request must not have been partially completed before.
index 7d10f4e632325d9aa2318543e13fe63fb899830f..6f7ff0fa8fcf81a3c2df14c04cdba4d60bdd997f 100644 (file)
@@ -1892,4 +1892,32 @@ static inline void blk_wake_io_task(struct task_struct *waiter)
                wake_up_process(waiter);
 }
 
+unsigned long disk_start_io_acct(struct gendisk *disk, unsigned int sectors,
+               unsigned int op);
+void disk_end_io_acct(struct gendisk *disk, unsigned int op,
+               unsigned long start_time);
+
+#ifdef CONFIG_BLOCK
+/**
+ * bio_start_io_acct - start I/O accounting for bio based drivers
+ * @bio:       bio to start account for
+ *
+ * Returns the start time that should be passed back to bio_end_io_acct().
+ */
+static inline unsigned long bio_start_io_acct(struct bio *bio)
+{
+       return disk_start_io_acct(bio->bi_disk, bio_sectors(bio), bio_op(bio));
+}
+
+/**
+ * bio_end_io_acct - end I/O accounting for bio based drivers
+ * @bio:       bio to end account for
+ * @start:     start time returned by bio_start_io_acct()
+ */
+static inline void bio_end_io_acct(struct bio *bio, unsigned long start_time)
+{
+       return disk_end_io_acct(bio->bi_disk, bio_op(bio), start_time);
+}
+#endif /* CONFIG_BLOCK */
+
 #endif