From: Milan Broz Introduce a bvec merge function for device mapper devices for dynamic size restrictions. This code ensures the requested biovec lies within a single target and then calls a target-specific function to check against any constraints imposed by underlying devices. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm.c | 45 ++++++++++++++++++++++++++++++++++++++++++ include/linux/device-mapper.h | 6 +++++ include/linux/dm-ioctl.h | 4 +-- 3 files changed, 53 insertions(+), 2 deletions(-) Index: linux-2.6.25/drivers/md/dm.c =================================================================== --- linux-2.6.25.orig/drivers/md/dm.c 2008-04-22 20:08:23.000000000 +0100 +++ linux-2.6.25/drivers/md/dm.c 2008-04-22 20:09:15.000000000 +0100 @@ -829,6 +829,50 @@ static int __split_bio(struct mapped_dev * CRUD END *---------------------------------------------------------------*/ +static int dm_merge_bvec(struct request_queue *q, struct block_device *bi_bdev, + sector_t bi_sector, unsigned bi_size, + unsigned long bi_rw, struct bio_vec *biovec) +{ + struct mapped_device *md = q->queuedata; + struct dm_table *map = dm_get_table(md); + struct dm_target *ti; + sector_t max_sectors; + int max_size; + + if (unlikely(!map)) + return 0; + + ti = dm_table_find_target(map, bi_sector); + + /* + * Find maximum amount of I/O that won't need splitting + */ + max_sectors = min(max_io_len(md, bi_sector, ti), + (sector_t) BIO_MAX_SECTORS); + max_size = (max_sectors << SECTOR_SHIFT) - bi_size; + if (max_size < 0) + max_size = 0; + + /* + * merge_bvec_fn() returns number of bytes + * it can accept at this offset + * max is precomputed maximal io size + */ + if (max_size && ti->type->merge) + max_size = ti->type->merge(ti, bi_sector, bi_size, bi_rw, + biovec, max_size); + + /* + * Always allow an entire first page + */ + if (max_size <= biovec->bv_len && !(bi_size >> SECTOR_SHIFT)) + max_size = biovec->bv_len; + + dm_table_put(map); + + return max_size; +} + /* * The request function that just remaps the bio built up by * dm_merge_bvec. @@ -1032,6 +1076,7 @@ static struct mapped_device *alloc_dev(i blk_queue_make_request(md->queue, dm_request); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; + blk_queue_merge_bvec(md->queue, dm_merge_bvec); md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache); if (!md->io_pool) Index: linux-2.6.25/include/linux/device-mapper.h =================================================================== --- linux-2.6.25.orig/include/linux/device-mapper.h 2008-04-18 12:40:15.000000000 +0100 +++ linux-2.6.25/include/linux/device-mapper.h 2008-04-22 20:09:15.000000000 +0100 @@ -16,6 +16,7 @@ struct dm_target; struct dm_table; struct dm_dev; struct mapped_device; +struct bio_vec; typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; @@ -74,6 +75,10 @@ typedef int (*dm_ioctl_fn) (struct dm_ta struct file *filp, unsigned int cmd, unsigned long arg); +typedef int (*dm_merge_fn) (struct dm_target *ti, sector_t bi_sector, + unsigned int bi_size, unsigned long bi_rw, + struct bio_vec *biovec, int max_size); + void dm_error(const char *message); /* @@ -109,6 +114,7 @@ struct target_type { dm_status_fn status; dm_message_fn message; dm_ioctl_fn ioctl; + dm_merge_fn merge; }; struct io_restrictions { Index: linux-2.6.25/include/linux/dm-ioctl.h =================================================================== --- linux-2.6.25.orig/include/linux/dm-ioctl.h 2008-04-17 16:21:28.000000000 +0100 +++ linux-2.6.25/include/linux/dm-ioctl.h 2008-04-22 20:09:15.000000000 +0100 @@ -256,9 +256,9 @@ enum { #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 13 +#define DM_VERSION_MINOR 14 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2007-10-18)" +#define DM_VERSION_EXTRA "-ioctl (2008-01-01)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */