dm: introduce merge_bvec_fn
authorMilan Broz <mbroz@redhat.com>
Mon, 21 Jul 2008 11:00:37 +0000 (12:00 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Mon, 21 Jul 2008 11:00:37 +0000 (12:00 +0100)
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 <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm.c
include/linux/device-mapper.h
include/linux/dm-ioctl.h

index efe9690..bca448e 100644 (file)
@@ -829,6 +829,49 @@ static int __split_bio(struct mapped_device *md, struct bio *bio)
  * 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(int minor)
        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 0d8d419..a90222e 100644 (file)
@@ -9,11 +9,13 @@
 #define _LINUX_DEVICE_MAPPER_H
 
 #include <linux/bio.h>
+#include <linux/blkdev.h>
 
 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 +74,9 @@ typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode,
                            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);
 
 /*
@@ -107,6 +112,7 @@ struct target_type {
        dm_status_fn status;
        dm_message_fn message;
        dm_ioctl_fn ioctl;
+       dm_merge_fn merge;
 };
 
 struct io_restrictions {
index b03c41b..28c2940 100644 (file)
@@ -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 */