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 | 37 +++++++++++++++++++++++++++++++++++++ include/linux/device-mapper.h | 5 +++++ include/linux/dm-ioctl.h | 4 ++-- 3 files changed, 44 insertions(+), 2 deletions(-) Index: current-quilt/drivers/md/dm.c =================================================================== --- current-quilt.orig/drivers/md/dm.c 2007-05-01 18:01:32.000000000 +0100 +++ current-quilt/drivers/md/dm.c 2007-05-01 18:28:30.000000000 +0100 @@ -792,6 +792,42 @@ static void __split_bio(struct mapped_de * CRUD END *---------------------------------------------------------------*/ +static int dm_merge_bvec(request_queue_t *q, struct bio *bio, + 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 len; + + if (unlikely(!map)) + return 0; + + ti = dm_table_find_target(map, bio->bi_sector); + + /* + * Find maximum bytes of I/O that won't need splitting + */ + max_sectors = min(max_io_len(md, bio->bi_sector, ti), (sector_t) BIO_MAX_SECTORS); + len = (max_sectors << SECTOR_SHIFT) - bio->bi_size; + if (len < 0) + len = 0; + + if (len > 0 && ti->type->merge) + len = ti->type->merge(ti, bio, biovec, len); + + /* + * Always allow an entire first page + */ + if (len <= biovec->bv_len && bio_sectors(bio) == 0) + len = biovec->bv_len; + + dm_table_put(map); + + return len; +} + /* * The request function that just remaps the bio built up by * dm_merge_bvec. @@ -1003,6 +1039,7 @@ static struct mapped_device *alloc_dev(i blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; md->queue->issue_flush_fn = dm_flush_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: current-quilt/include/linux/device-mapper.h =================================================================== --- current-quilt.orig/include/linux/device-mapper.h 2007-05-01 18:01:31.000000000 +0100 +++ current-quilt/include/linux/device-mapper.h 2007-05-01 18:28:30.000000000 +0100 @@ -14,6 +14,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; @@ -72,6 +73,9 @@ 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, struct bio *bio, + struct bio_vec *biovec, int len); + void dm_error(const char *message); /* @@ -107,6 +111,7 @@ struct target_type { dm_status_fn status; dm_message_fn message; dm_ioctl_fn ioctl; + dm_merge_fn merge; }; struct io_restrictions { Index: current-quilt/include/linux/dm-ioctl.h =================================================================== --- current-quilt.orig/include/linux/dm-ioctl.h 2007-05-01 17:41:14.000000000 +0100 +++ current-quilt/include/linux/dm-ioctl.h 2007-05-01 18:28:30.000000000 +0100 @@ -285,9 +285,9 @@ typedef char ioctl_struct[308]; #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 11 +#define DM_VERSION_MINOR 12 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2006-10-12)" +#define DM_VERSION_EXTRA "-ioctl (2007-04-02)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */