dm thin: optimize power of two block size
authorMikulas Patocka <mpatocka@redhat.com>
Fri, 27 Jul 2012 14:08:03 +0000 (15:08 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 27 Jul 2012 14:08:03 +0000 (15:08 +0100)
dm-thin will be most likely used with a block size that is a power of
two. So it should be optimized for this case.

This patch changes division and modulo operations to shifts and bit
masks if block size is a power of two.

A test that bi_sector is divisible by a block size is removed from
io_overlaps_block. Device mapper never sends bios that span a block
boundary. Consequently, if we tested that bi_size is equivalent to block
size, bi_sector must already be on a block boundary.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-thin.c

index 828649256902f5745718b542f55761648bf190ac..93e3e542cff9c66ad7045310fc93b1deda654cd6 100644 (file)
@@ -512,6 +512,7 @@ struct pool {
 
        dm_block_t low_water_blocks;
        uint32_t sectors_per_block;
+       int sectors_per_block_shift;
 
        struct pool_features pf;
        unsigned low_water_triggered:1; /* A dm event has been sent */
@@ -679,7 +680,10 @@ static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 {
        sector_t block_nr = bio->bi_sector;
 
-       (void) sector_div(block_nr, tc->pool->sectors_per_block);
+       if (tc->pool->sectors_per_block_shift < 0)
+               (void) sector_div(block_nr, tc->pool->sectors_per_block);
+       else
+               block_nr >>= tc->pool->sectors_per_block_shift;
 
        return block_nr;
 }
@@ -690,8 +694,12 @@ static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
        sector_t bi_sector = bio->bi_sector;
 
        bio->bi_bdev = tc->pool_dev->bdev;
-       bio->bi_sector = (block * pool->sectors_per_block) +
-                        sector_div(bi_sector, pool->sectors_per_block);
+       if (tc->pool->sectors_per_block_shift < 0)
+               bio->bi_sector = (block * pool->sectors_per_block) +
+                                sector_div(bi_sector, pool->sectors_per_block);
+       else
+               bio->bi_sector = (block << pool->sectors_per_block_shift) |
+                               (bi_sector & (pool->sectors_per_block - 1));
 }
 
 static void remap_to_origin(struct thin_c *tc, struct bio *bio)
@@ -936,10 +944,7 @@ static void process_prepared(struct pool *pool, struct list_head *head,
  */
 static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-       sector_t bi_sector = bio->bi_sector;
-
-       return !sector_div(bi_sector, pool->sectors_per_block) &&
-               (bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT));
+       return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT);
 }
 
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
@@ -1721,6 +1726,10 @@ static struct pool *pool_create(struct mapped_device *pool_md,
 
        pool->pmd = pmd;
        pool->sectors_per_block = block_size;
+       if (block_size & (block_size - 1))
+               pool->sectors_per_block_shift = -1;
+       else
+               pool->sectors_per_block_shift = __ffs(block_size);
        pool->low_water_blocks = 0;
        pool_features_init(&pool->pf);
        pool->prison = prison_create(PRISON_CELLS);