NVMe: Disk IO statistics
authorKeith Busch <keith.busch@intel.com>
Wed, 29 May 2013 21:59:39 +0000 (15:59 -0600)
committerMatthew Wilcox <matthew.r.wilcox@intel.com>
Thu, 20 Jun 2013 16:06:35 +0000 (12:06 -0400)
Add io stats accounting for bio requests so nvme block devices show
useful disk stats.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
drivers/block/nvme-core.c
include/linux/nvme.h

index de3a759..4e71b07 100644 (file)
@@ -285,6 +285,7 @@ nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp)
                iod->npages = -1;
                iod->length = nbytes;
                iod->nents = 0;
+               iod->start_time = jiffies;
        }
 
        return iod;
@@ -308,6 +309,30 @@ void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
        kfree(iod);
 }
 
+static void nvme_start_io_acct(struct bio *bio)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+       const int rw = bio_data_dir(bio);
+       int cpu = part_stat_lock();
+       part_round_stats(cpu, &disk->part0);
+       part_stat_inc(cpu, &disk->part0, ios[rw]);
+       part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
+       part_inc_in_flight(&disk->part0, rw);
+       part_stat_unlock();
+}
+
+static void nvme_end_io_acct(struct bio *bio, unsigned long start_time)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+       const int rw = bio_data_dir(bio);
+       unsigned long duration = jiffies - start_time;
+       int cpu = part_stat_lock();
+       part_stat_add(cpu, &disk->part0, ticks[rw], duration);
+       part_round_stats(cpu, &disk->part0);
+       part_dec_in_flight(&disk->part0, rw);
+       part_stat_unlock();
+}
+
 static void bio_completion(struct nvme_dev *dev, void *ctx,
                                                struct nvme_completion *cqe)
 {
@@ -318,6 +343,8 @@ static void bio_completion(struct nvme_dev *dev, void *ctx,
        if (iod->nents)
                dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents,
                        bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+       nvme_end_io_acct(bio, iod->start_time);
        nvme_free_iod(dev, iod);
        if (status)
                bio_endio(bio, -EIO);
@@ -695,6 +722,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        cmnd->rw.control = cpu_to_le16(control);
        cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
 
+       nvme_start_io_acct(bio);
        if (++nvmeq->sq_tail == nvmeq->q_depth)
                nvmeq->sq_tail = 0;
        writel(nvmeq->sq_tail, nvmeq->q_db);
index f451c8d..5d7c079 100644 (file)
@@ -572,6 +572,7 @@ struct nvme_iod {
        int offset;             /* Of PRP list */
        int nents;              /* Used in scatterlist */
        int length;             /* Of data, in bytes */
+       unsigned long start_time;
        dma_addr_t first_dma;
        struct scatterlist sg[0];
 };