Record I/O timing statistics

The start time is added to struct dm_io, an existing structure 
allocated privately internally within dm and attached to each 
incoming bio.

We export disk_round_stats() from block/ll_rw_blk.c instead of
creating a private clone.

From: "Jun'ichi \"Nick\" Nomura" <jnomura@redhat.com>

Index: current-quilt-publish/drivers/md/dm.c
===================================================================
--- current-quilt-publish.orig/drivers/md/dm.c	2006-01-03 21:08:09.000000000 +0000
+++ current-quilt-publish/drivers/md/dm.c	2006-01-03 21:08:23.000000000 +0000
@@ -31,6 +31,7 @@ struct dm_io {
 	int error;
 	struct bio *bio;
 	atomic_t io_count;
+	unsigned long start_time;
 };
 
 /*
@@ -244,6 +245,42 @@ static inline void free_tio(struct mappe
 	mempool_free(tio, md->tio_pool);
 }
 
+static void start_io_acct(struct dm_io *io)
+{
+	struct mapped_device *md = io->md;
+
+	io->start_time = jiffies;
+
+	preempt_disable();
+	disk_round_stats(dm_disk(md));
+	preempt_enable();
+	dm_disk(md)->in_flight = atomic_inc_return(&md->pending);
+}
+
+static int end_io_acct(struct dm_io *io)
+{
+	struct mapped_device *md = io->md;
+	struct bio *bio = io->bio;
+	unsigned long duration = jiffies - io->start_time;
+	int pending;
+
+	preempt_disable();
+	disk_round_stats(dm_disk(md));
+	preempt_enable();
+	dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending);
+
+	switch (bio_data_dir(bio)) {
+	case WRITE:
+		disk_stat_add(dm_disk(md), write_ticks, duration);
+		break;
+	case READ:
+		disk_stat_add(dm_disk(md), read_ticks, duration);
+		break;
+	}
+
+	return !pending;
+}
+
 /*
  * Add the bio to the list of deferred io.
  */
@@ -299,7 +336,7 @@ static inline void dec_pending(struct dm
 		io->error = error;
 
 	if (atomic_dec_and_test(&io->io_count)) {
-		if (atomic_dec_and_test(&io->md->pending))
+		if (end_io_acct(io))
 			/* nudge anyone waiting on suspend queue */
 			wake_up(&io->md->wait);
 
@@ -554,7 +591,7 @@ static void __split_bio(struct mapped_de
 	ci.sector_count = bio_sectors(bio);
 	ci.idx = bio->bi_idx;
 
-	atomic_inc(&md->pending);
+	start_io_acct(ci.io);
 	while (ci.sector_count)
 		__clone_and_map(&ci);
 
Index: current-quilt-publish/drivers/block/ll_rw_blk.c
===================================================================
--- current-quilt-publish.orig/drivers/block/ll_rw_blk.c	2006-01-03 21:08:09.000000000 +0000
+++ current-quilt-publish/drivers/block/ll_rw_blk.c	2006-01-03 21:08:23.000000000 +0000
@@ -2442,6 +2442,8 @@ void disk_round_stats(struct gendisk *di
 	disk->stamp_idle = now;
 }
 
+EXPORT_SYMBOL_GPL(disk_round_stats);
+
 /*
  * queue lock must be held
  */
