dm era: support non power-of-2 blocksize
authorMike Snitzer <snitzer@redhat.com>
Thu, 6 Mar 2014 15:50:54 +0000 (10:50 -0500)
committerMike Snitzer <snitzer@redhat.com>
Fri, 7 Mar 2014 17:02:49 +0000 (12:02 -0500)
The dm-era target is expected to be paired with the dm-cache target
which has support for non power-of-2 data blocksize.  So dm-era should
also support an origin data device blocksize that is non power-of-2.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-era-target.c

index f7723512275ec7876dc853ad25ddeaa0368b30df..3a72206fb7660d569957648c310f771cc2461db3 100644 (file)
@@ -1080,9 +1080,9 @@ struct era {
        struct dm_dev *metadata_dev;
        struct dm_dev *origin_dev;
 
-       uint32_t block_size;
        dm_block_t nr_blocks;
-       unsigned sectors_per_block_shift;
+       uint32_t sectors_per_block;
+       int sectors_per_block_shift;
        struct era_metadata *md;
 
        struct workqueue_struct *wq;
@@ -1113,9 +1113,21 @@ struct rpc {
 /*----------------------------------------------------------------
  * Remapping.
  *---------------------------------------------------------------*/
+static bool block_size_is_power_of_two(struct era *era)
+{
+       return era->sectors_per_block_shift >= 0;
+}
+
 static dm_block_t get_block(struct era *era, struct bio *bio)
 {
-       return bio->bi_iter.bi_sector >> era->sectors_per_block_shift;
+       sector_t block_nr = bio->bi_iter.bi_sector;
+
+       if (!block_size_is_power_of_two(era))
+               (void) sector_div(block_nr, era->sectors_per_block);
+       else
+               block_nr >>= era->sectors_per_block_shift;
+
+       return block_nr;
 }
 
 static void remap_to_origin(struct era *era, struct bio *bio)
@@ -1336,7 +1348,7 @@ static void era_destroy(struct era *era)
 
 static dm_block_t calc_nr_blocks(struct era *era)
 {
-       return dm_sector_div_up(era->ti->len, era->block_size);
+       return dm_sector_div_up(era->ti->len, era->sectors_per_block);
 }
 
 /*
@@ -1376,22 +1388,26 @@ static int era_ctr(struct dm_target *ti, unsigned argc, char **argv)
                return -EINVAL;
        }
 
-       r = sscanf(argv[2], "%u%c", &era->block_size, &dummy);
+       r = sscanf(argv[2], "%u%c", &era->sectors_per_block, &dummy);
        if (r != 1) {
                ti->error = "Error parsing block size";
                era_destroy(era);
                return -EINVAL;
        }
-       era->sectors_per_block_shift = __ffs(era->block_size);
 
-       r = dm_set_target_max_io_len(ti, era->block_size);
+       r = dm_set_target_max_io_len(ti, era->sectors_per_block);
        if (r) {
                ti->error = "could not set max io len";
                era_destroy(era);
                return -EINVAL;
        }
 
-       md = metadata_open(era->metadata_dev->bdev, era->block_size, true);
+       if (era->sectors_per_block & (era->sectors_per_block - 1))
+               era->sectors_per_block_shift = -1;
+       else
+               era->sectors_per_block_shift = __ffs(era->sectors_per_block);
+
+       md = metadata_open(era->metadata_dev->bdev, era->sectors_per_block, true);
        if (IS_ERR(md)) {
                ti->error = "Error reading metadata";
                era_destroy(era);
@@ -1549,7 +1565,7 @@ static void era_status(struct dm_target *ti, status_type_t type,
                format_dev_t(buf, era->metadata_dev->bdev->bd_dev);
                DMEMIT("%s ", buf);
                format_dev_t(buf, era->origin_dev->bdev->bd_dev);
-               DMEMIT("%s %u", buf, era->block_size);
+               DMEMIT("%s %u", buf, era->sectors_per_block);
                break;
        }
 
@@ -1614,12 +1630,12 @@ static void era_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
        /*
         * If the system-determined stacked limits are compatible with the
-        * cache's blocksize (io_opt is a factor) do not override them.
+        * era device's blocksize (io_opt is a factor) do not override them.
         */
-       if (io_opt_sectors < era->block_size ||
-           do_div(io_opt_sectors, era->block_size)) {
+       if (io_opt_sectors < era->sectors_per_block ||
+           do_div(io_opt_sectors, era->sectors_per_block)) {
                blk_limits_io_min(limits, 0);
-               blk_limits_io_opt(limits, era->block_size << SECTOR_SHIFT);
+               blk_limits_io_opt(limits, era->sectors_per_block << SECTOR_SHIFT);
        }
 }