> +{
> + struct gendisk *disk = dev_to_disk(dev);
> +
> + spin_lock(&disk->flush_time_lock);
> + disk->avg_flush_time_ns = 0;
> + disk->flush_samples = 0;
> + spin_unlock(&disk->flush_time_lock);
> +
> + return count;
> +}
> +
> +
> static ssize_t disk_ext_range_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -876,6 +910,9 @@ static ssize_t disk_discard_alignment_show(struct device *dev,
> }
>
> static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
> +static DEVICE_ATTR(avg_flush_time_ns, S_IRUGO | S_IWUSR,
> + disk_avg_flush_time_ns_show, disk_avg_flush_time_ns_store);
> +static DEVICE_ATTR(flush_samples, S_IRUGO, disk_flush_samples_show, NULL);
> static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
> static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
> static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
> @@ -898,6 +935,8 @@ static struct device_attribute dev_attr_fail_timeout =
>
> static struct attribute *disk_attrs[] = {
> &dev_attr_range.attr,
> + &dev_attr_avg_flush_time_ns.attr,
> + &dev_attr_flush_samples.attr,
> &dev_attr_ext_range.attr,
> &dev_attr_removable.attr,
> &dev_attr_ro.attr,
> diff --git a/fs/bio.c b/fs/bio.c
> index 4bd454f..aab5f27 100644
> --- a/fs/bio.c
> +++ b/fs/bio.c
> @@ -1442,11 +1442,22 @@ EXPORT_SYMBOL(bio_flush_dcache_pages);
> **/
> void bio_endio(struct bio *bio, int error)
> {
> + struct request_queue *q = NULL;
> +
> if (error)
> clear_bit(BIO_UPTODATE, &bio->bi_flags);
> else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
> error = -EIO;
>
> + if (bio->bi_bdev)
> + q = bdev_get_queue(bio->bi_bdev);
> + if (!(q && q->prep_rq_fn) && !error && bio->bi_rw & REQ_FLUSH) {
> + u64 delta;
> +
> + delta = ktime_to_ns(ktime_get()) - bio->flush_start_time_ns;
> + update_flush_times(bio->bi_bdev->bd_disk, delta);
> + }
> +
> if (bio->bi_end_io)
> bio->bi_end_io(bio, error);
> }
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 46ad519..e8c29b9 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
> @@ -74,6 +74,8 @@ struct bio {
>
> bio_destructor_t *bi_destructor; /* destructor */
>
> + u64 flush_start_time_ns;
> +
> /*
> * We can inline a number of vecs at the end of the bio, to avoid
> * double allocations for a small number of bio_vecs. This member
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index aae86fd..357d669 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -163,6 +163,8 @@ struct request {
>
> /* for bidi */
> struct request *next_rq;
> +
> + u64 flush_start_time_ns;
> };
>
> static inline unsigned short req_get_ioprio(struct request *req)
> diff --git a/include/linux/genhd.h b/include/linux/genhd.h
> index 7a7b9c1..7097396 100644
> --- a/include/linux/genhd.h
> +++ b/include/linux/genhd.h
> @@ -178,8 +178,31 @@ struct gendisk {
> struct blk_integrity *integrity;
> #endif
> int node_id;
> +
> + spinlock_t flush_time_lock;
> + u64 avg_flush_time_ns;
> + u64 flush_samples;
> };
>
> +static inline void update_flush_times(struct gendisk *disk, u64 delta)
> +{
> + u64 data;
> +
> + spin_lock(&disk->flush_time_lock);
> + if (disk->flush_samples < 256)
> + disk->flush_samples++;
> + if (!disk->avg_flush_time_ns)
> + disk->avg_flush_time_ns = delta;
> + else {
> + data = disk->avg_flush_time_ns;
> + data *= 255;
> + data += delta;
> + data /= 256;
> + disk->avg_flush_time_ns = data;
> + }
> + spin_unlock(&disk->flush_time_lock);
> +}
> +
> static inline struct gendisk *part_to_disk(struct hd_struct *part)
> {
> if (likely(part)) {
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to
majordomo@vger.kernel.org
> More majordomo info at
http://vger.kernel.org/majordomo-info.html
>