We can't have 2 target types in the same module without breaking the automatic loading of target modules. eg, if 'iostat_avg' is requested and not registered the kernel will try and load a module called 'dm-iostat_avg'. So this changes the code back to a single target, with an extra parameter which states whether we want latency info or not. --- diff/drivers/md/dm-iostats.c 2002-12-16 13:22:12.000000000 +0000 +++ source/drivers/md/dm-iostats.c 2002-12-16 13:22:03.000000000 +0000 @@ -11,6 +11,7 @@ #include #include #include +#include static kmem_cache_t *_iostats_cache; mempool_t *_iostats_pool; @@ -28,23 +29,24 @@ }; /* - * Linear: io status for a linear range of a device. + * io status for a linear range of a device. */ -struct iostats_c { - struct dm_dev *dev; - uint32_t reads; - uint32_t writes; -}; - typedef uint16_t count_t; #define MAX_COUNT ((count_t) -1) +#define MIN_IOSTATS 128 +#define IOF_LATENCY 1 -struct iostats_avg_c { - spinlock_t lock; - +struct iostats_c { + unsigned long flags; struct dm_dev *dev; uint32_t reads; uint32_t writes; + + /* + * These fields are only present if we are recording the + * average completion times. + */ + spinlock_t lock; jiffies_t total_r; jiffies_t total_w; count_t count_r; @@ -62,106 +64,70 @@ mempool_free(io, _iostats_pool); } - /* - * Construct a linear io status mapping: + * Construct a io status mapping: */ -static int _iostats_ctr(struct dm_target *ti, int argc, char **argv, int size) +static int iostats_ctr(struct dm_target *ti, int argc, char **argv) { + size_t size; + int averaging; struct iostats_c *ic; - if (argc != 1) { - ti->error = "dm-iostats: Wrong argument count"; + if (argc != 2) { + ti->error = "incorrect number of arguments"; return -EINVAL; } - ic = kmalloc(size, GFP_KERNEL); - if (ic == NULL) { - ti->error = "dm-iostats: Cannot allocate io status context"; - return -ENOMEM; - } - - if (dm_get_device(ti, argv[0], ti->begin, ti->len, - dm_table_get_mode(ti->table), &ic->dev)) { - ti->error = "dm-iostats: Device lookup failed"; - goto bad; + if (strlen(argv[1]) != 1) { + ti->error = "invalid 'should average' flag"; + return -EINVAL; } - ti->private = ic; - return 0; - - bad: - kfree(ic); - return -EINVAL; -} - -/* read/write statistics constructor */ -static int iostats_ctr(struct dm_target *ti, int argc, char **argv) -{ - int r = _iostats_ctr(ti, argc, argv, sizeof(struct iostats_c)); + averaging = (toupper(argv[1][0]) == 'Y'); - if (!r) { - struct iostats_c *ic = ti->private; + if (averaging) + size = sizeof(*ic); + else + size = (size_t) &((struct iostats_c *) NULL)->lock; - ic->reads = 0; - ic->writes = 0; + ic = kmalloc(size, GFP_KERNEL); + if (!ic) { + ti->error = "out of memory"; + kfree(ic); + return -ENOMEM; } - return r; -} - -/* average io latency statistics constuctor */ -static int iostats_avg_ctr(struct dm_target *ti, int argc, char **argv) -{ - int r = _iostats_ctr(ti, argc, argv, sizeof(struct iostats_avg_c)); - - if (!r) { - struct iostats_avg_c *ic = ti->private; - + memset(ic, 0, size); + if (averaging) { + set_bit(IOF_LATENCY, &ic->flags); ic->lock = SPIN_LOCK_UNLOCKED; - ic->reads = 0; - ic->writes = 0; - ic->total_r = 0; - ic->total_w = 0; - ic->count_r = 0; - ic->count_w = 0; } - return r; + if (dm_get_device(ti, argv[0], ti->begin, ti->len, + dm_table_get_mode(ti->table), &ic->dev)) { + ti->error = "device lookup failed"; + kfree(ic); + return -ENXIO; + } + + return 0; } -/* common destructor */ static void iostats_dtr(struct dm_target *ti) { struct iostats_c *ic = (struct iostats_c *) ti->private; - dm_put_device(ti, ic->dev); kfree(ic); } -/* read/write statistics mapping */ -static int iostats_map(struct dm_target *ti, struct buffer_head *bh, int rw) -{ - struct iostats_c *ic = (struct iostats_c *) ti->private; - - if (rw == WRITE) - ic->writes++; - else - ic->reads++; - - /* map */ - bh->b_rdev = ic->dev->dev; - - return 1; -} - -/* average latency stats end_io function */ +/* + * average latency stats end_io function */ static void iostats_avg_end_io(struct buffer_head *bh, int uptodate) { int flags; jiffies_t j; struct dm_iostats *io = bh->b_private; - struct iostats_avg_c *ic = io->ti->private; + struct iostats_c *ic = io->ti->private; spin_lock_irqsave(&ic->lock, flags); @@ -198,12 +164,15 @@ bh->b_end_io(bh, uptodate); } -/* average io latency statistics mapping */ -static int iostats_avg_map(struct dm_target *ti, struct buffer_head *bh, int rw) +/* + * Hook the io so we can work get the io completion time. + */ +static int _hook_io(struct iostats_c *stats, struct dm_target *ti, + struct buffer_head *bh, int rw) { - struct iostats_avg_c *ic = (struct iostats_avg_c *) ti->private; - struct dm_iostats *io = alloc_io(); + struct dm_iostats *io; + io = alloc_io(); if (!io) return -ENOMEM; @@ -217,31 +186,26 @@ bh->b_end_io = iostats_avg_end_io; bh->b_private = io; - /* map */ - bh->b_rdev = ic->dev->dev; - - return 1; + return 0; } /* read/write statistics mapping */ -static int iostats_status(struct dm_target *ti, status_type_t type, - char *result, int maxlen) +static int iostats_map(struct dm_target *ti, struct buffer_head *bh, int rw) { struct iostats_c *ic = (struct iostats_c *) ti->private; - switch (type) { - case STATUSTYPE_INFO: - snprintf(result, maxlen, "%s %u %u", - kdevname(to_kdev_t(ic->dev->bdev->bd_dev)), - ic->reads, ic->writes); - break; + if (rw == WRITE) + ic->writes++; + else + ic->reads++; - case STATUSTYPE_TABLE: - snprintf(result, maxlen, "%s", - kdevname(to_kdev_t(ic->dev->bdev->bd_dev))); - break; - } - return 0; + if (test_bit(IOF_LATENCY, &ic->flags)) + _hook_io(ic, ti, bh, rw); + + /* map */ + bh->b_rdev = ic->dev->dev; + + return 1; } static inline uint _calc(jiffies_t j, count_t c) @@ -251,15 +215,19 @@ return (c ? (j * m / c) : (j * m)); } -/* average io status */ -static int iostats_avg_status(struct dm_target *ti, status_type_t type, - char *result, int maxlen) +/* read/write statistics mapping */ +static int iostats_status(struct dm_target *ti, status_type_t type, + char *result, int maxlen) { - struct iostats_avg_c *ic = (struct iostats_avg_c *) ti->private; + struct iostats_c *ic = (struct iostats_c *) ti->private; switch (type) { case STATUSTYPE_INFO: - { + if (test_bit(IOF_LATENCY, &ic->flags)) { + snprintf(result, maxlen, "%s %u %u", + kdevname(to_kdev_t(ic->dev->bdev->bd_dev)), + ic->reads, ic->writes); + } else { uint avg_r, avg_w; avg_r = _calc(ic->total_r, ic->count_r); @@ -267,19 +235,19 @@ snprintf(result, maxlen, "%s %u %u %u %u", kdevname(to_kdev_t(ic->dev->bdev->bd_dev)), ic->reads, ic->writes, avg_r, avg_w); - - break; } break; case STATUSTYPE_TABLE: - snprintf(result, maxlen, "%s", - kdevname(to_kdev_t(ic->dev->bdev->bd_dev))); + snprintf(result, maxlen, "%s %s", + kdevname(to_kdev_t(ic->dev->bdev->bd_dev)), + test_bit(IOF_LATENCY, &ic->flags) ? "y" : "n"); + break; } return 0; } -static struct target_type iostats_target = { +static struct target_type _iostats_target = { .name = "iostats", .module = THIS_MODULE, .ctr = iostats_ctr, @@ -288,50 +256,9 @@ .status = iostats_status, }; -static struct target_type iostats_avg_target = { - .name = "iostats_avg", - .module = THIS_MODULE, - .ctr = iostats_avg_ctr, - .dtr = iostats_dtr, - .map = iostats_avg_map, - .status = iostats_avg_status, -}; - -/* Keep the target pointers in an array for (de)registration */ -static struct target_type *target_type_init[] = { - &iostats_target, - &iostats_avg_target, -}; - -void __exit dm_iostats_exit(void) -{ - int i; - const int count = ARRAY_SIZE(target_type_init); - struct target_type **tti = &target_type_init[count-1]; - - for (i = count; i; i--, tti--) { - int r = dm_unregister_target(*tti); - - if (r) - DMERR("%s: unregister failed %d", (*tti)->name, r); - } - - if (_iostats_pool) { - mempool_destroy(_iostats_pool); - _iostats_pool = NULL; - } - - if (_iostats_cache) { - kmem_cache_destroy(_iostats_cache); - _iostats_cache = NULL; - } -} - int __init dm_iostats_init(void) { - int i; - const int count = ARRAY_SIZE(target_type_init); - struct target_type **tti = target_type_init; + int r; /* allocate a slab for the dm_iostats */ _iostats_cache = kmem_cache_create("dm iostats io", @@ -350,25 +277,30 @@ return -ENOMEM; } - for (i = 0; i < count; i++, tti++) { - int r = dm_register_target(*tti); + r = dm_register_target(&_iostats_target); + if (r) { + mempool_destroy(_iostats_pool); + kmem_cache_destroy(_iostats_cache); + } - if (r) { - DMERR("%s: register failed %d", (*tti)->name, r); + return 0; +} - for (tti--; i; i--, tti--) { - r = dm_unregister_target(*tti); +void __exit dm_iostats_exit(void) +{ + int r = dm_unregister_target(&_iostats_target); + if (r) + DMERR("dm-iostats unregister failed %d", r); - if (r) - DMERR("%s: unregister failed %d", - (*tti)->name, r); - } - return r; - } + if (_iostats_pool) { + mempool_destroy(_iostats_pool); + _iostats_pool = NULL; } - DMINFO("dm_iostats_init v0.0.29"); - return 0; + if (_iostats_cache) { + kmem_cache_destroy(_iostats_cache); + _iostats_cache = NULL; + } } /*