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 | 44 ++++++++++++++++++++++++++++++++++++++++++ include/linux/device-mapper.h | 6 +++++ include/linux/dm-ioctl.h | 4 +-- 3 files changed, 52 insertions(+), 2 deletions(-) Index: linux-2.6.25/drivers/md/dm.c =================================================================== --- linux-2.6.25.orig/drivers/md/dm.c 2008-04-23 12:29:02.000000000 +0100 +++ linux-2.6.25/drivers/md/dm.c 2008-04-23 12:29:18.000000000 +0100 @@ -829,6 +829,49 @@ static int __split_bio(struct mapped_dev * CRUD END *---------------------------------------------------------------*/ +static int dm_merge_bvec(struct request_queue *q, + struct bvec_merge_data *bvm, + 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, bvm->bi_sector); + + /* + * Find maximum amount of I/O that won't need splitting + */ + max_sectors = min(max_io_len(md, bvm->bi_sector, ti), + (sector_t) BIO_MAX_SECTORS); + max_size = (max_sectors << SECTOR_SHIFT) - bvm->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, bvm, biovec, max_size); + + /* + * Always allow an entire first page + */ + if (max_size <= biovec->bv_len && !(bvm->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 +1075,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-23 12:29:02.000000000 +0100 +++ linux-2.6.25/include/linux/device-mapper.h 2008-04-23 12:29:47.000000000 +0100 @@ -11,11 +11,13 @@ #ifdef __KERNEL__ #include +#include 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 +76,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 bvec_merge_data *bvm, + 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-23 12:29:02.000000000 +0100 +++ linux-2.6.25/include/linux/dm-ioctl.h 2008-04-23 12:54:38.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-04-23)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */