aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-stripe.c
diff options
context:
space:
mode:
authorMustafa Mesanovic <mume@linux.vnet.ibm.com>2011-03-24 09:54:35 -0400
committerAlasdair G Kergon <agk@redhat.com>2011-03-24 09:54:35 -0400
commit29915202006c2e7bafe81348eb498ff9a724ac61 (patch)
tree0fc9b1fb5c58ed148316d7a5718de1b290dcde18 /drivers/md/dm-stripe.c
parenta490a07a67b7a37f588021410e06b721a752fc34 (diff)
dm stripe: implement merge method
Implement a merge function in the striped target. When the striped target's underlying devices provide a merge_bvec_fn (like all DM devices do via dm_merge_bvec) it is important to call down to them when building a biovec that doesn't span a stripe boundary. Without the merge method, a striped DM device stacked on DM devices causes bios with a single page to be submitted which results in unnecessary overhead that hurts performance. This change really helps filesystems (e.g. XFS and now ext4) which take care to assemble larger bios. By implementing stripe_merge(), DM and the stripe target no longer undermine the filesystem's work by only allowing a single page per bio. Buffered IO sees the biggest improvement (particularly uncached reads, buffered writes to a lesser degree). This is especially so for more capable "enterprise" storage LUNs. The performance improvement has been measured to be ~12-35% -- when a reasonable chunk_size is used (e.g. 64K) in conjunction with a stripe count that is a power of 2. In contrast, the performance penalty is ~5-7% for the pathological worst case stripe configuration (small chunk_size with a stripe count that is not a power of 2). The reason for this is that stripe_map_sector() is now called once for every call to dm_merge_bvec(). stripe_map_sector() will use slower division if stripe count isn't a power of 2. Signed-off-by: Mustafa Mesanovic <mume@linux.vnet.ibm.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r--drivers/md/dm-stripe.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index dddfa14f2982..3d80cf0c152d 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -396,9 +396,29 @@ static void stripe_io_hints(struct dm_target *ti,
396 blk_limits_io_opt(limits, chunk_size * sc->stripes); 396 blk_limits_io_opt(limits, chunk_size * sc->stripes);
397} 397}
398 398
399static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
400 struct bio_vec *biovec, int max_size)
401{
402 struct stripe_c *sc = ti->private;
403 sector_t bvm_sector = bvm->bi_sector;
404 uint32_t stripe;
405 struct request_queue *q;
406
407 stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector);
408
409 q = bdev_get_queue(sc->stripe[stripe].dev->bdev);
410 if (!q->merge_bvec_fn)
411 return max_size;
412
413 bvm->bi_bdev = sc->stripe[stripe].dev->bdev;
414 bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector;
415
416 return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
417}
418
399static struct target_type stripe_target = { 419static struct target_type stripe_target = {
400 .name = "striped", 420 .name = "striped",
401 .version = {1, 3, 1}, 421 .version = {1, 4, 0},
402 .module = THIS_MODULE, 422 .module = THIS_MODULE,
403 .ctr = stripe_ctr, 423 .ctr = stripe_ctr,
404 .dtr = stripe_dtr, 424 .dtr = stripe_dtr,
@@ -407,6 +427,7 @@ static struct target_type stripe_target = {
407 .status = stripe_status, 427 .status = stripe_status,
408 .iterate_devices = stripe_iterate_devices, 428 .iterate_devices = stripe_iterate_devices,
409 .io_hints = stripe_io_hints, 429 .io_hints = stripe_io_hints,
430 .merge = stripe_merge,
410}; 431};
411 432
412int __init dm_stripe_init(void) 433int __init dm_stripe_init(void)