dm thin: detect metadata device resizing
authorJoe Thornber <ejt@redhat.com>
Fri, 10 May 2013 13:37:19 +0000 (14:37 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 10 May 2013 13:37:19 +0000 (14:37 +0100)
Allow the dm thin pool metadata device to be extended.

Whenever a pool is resumed, detect whether the size of the metadata
device has increased, and if so, extend the metadata to use the new
space.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c

index 9452a489ed999d765211579c3d93fc4f4f8f8c91..f553ed66603c57efc1135c658ace9e149804ff1a 100644 (file)
@@ -1677,6 +1677,18 @@ int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
        return r;
 }
 
+int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_count)
+{
+       int r = -EINVAL;
+
+       down_write(&pmd->root_lock);
+       if (!pmd->fail_io)
+               r = __resize_space_map(pmd->metadata_sm, new_count);
+       up_write(&pmd->root_lock);
+
+       return r;
+}
+
 void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd)
 {
        down_write(&pmd->root_lock);
index 0cecc3702885fb57452c013f83679fc437a393ca..ef8dd709e34e2371c721be5c6a9b497f28a342b4 100644 (file)
@@ -185,6 +185,7 @@ int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result);
  * blocks would be lost.
  */
 int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_size);
+int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_size);
 
 /*
  * Flicks the underlying block manager into read only mode, so you know
index ef021b0c810625c2532eb37d96b0af96d5d994cf..f4632f97bd7b5b6ca988937b11dbd62694eaab34 100644 (file)
@@ -1923,6 +1923,15 @@ static sector_t get_metadata_dev_size(struct block_device *bdev)
        return metadata_dev_size;
 }
 
+static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
+{
+       sector_t metadata_dev_size = get_metadata_dev_size(bdev);
+
+       sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+
+       return metadata_dev_size;
+}
+
 /*
  * thin-pool <metadata dev> <data dev>
  *          <data block size (sectors)>
@@ -2132,6 +2141,41 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
        return 0;
 }
 
+static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
+{
+       int r;
+       struct pool_c *pt = ti->private;
+       struct pool *pool = pt->pool;
+       dm_block_t metadata_dev_size, sb_metadata_dev_size;
+
+       *need_commit = false;
+
+       metadata_dev_size = get_metadata_dev_size(pool->md_dev);
+
+       r = dm_pool_get_metadata_dev_size(pool->pmd, &sb_metadata_dev_size);
+       if (r) {
+               DMERR("failed to retrieve data device size");
+               return r;
+       }
+
+       if (metadata_dev_size < sb_metadata_dev_size) {
+               DMERR("metadata device (%llu sectors) too small: expected %llu",
+                     metadata_dev_size, sb_metadata_dev_size);
+               return -EINVAL;
+
+       } else if (metadata_dev_size > sb_metadata_dev_size) {
+               r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size);
+               if (r) {
+                       DMERR("failed to resize metadata device");
+                       return r;
+               }
+
+               *need_commit = true;
+       }
+
+       return 0;
+}
+
 /*
  * Retrieves the number of blocks of the data device from
  * the superblock and compares it to the actual device size,
@@ -2146,7 +2190,7 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
 static int pool_preresume(struct dm_target *ti)
 {
        int r;
-       bool need_commit1;
+       bool need_commit1, need_commit2;
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
 
@@ -2161,7 +2205,11 @@ static int pool_preresume(struct dm_target *ti)
        if (r)
                return r;
 
-       if (need_commit1)
+       r = maybe_resize_metadata_dev(ti, &need_commit2);
+       if (r)
+               return r;
+
+       if (need_commit1 || need_commit2)
                (void) commit_or_fallback(pool);
 
        return 0;
@@ -2583,7 +2631,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 7, 0},
+       .version = {1, 8, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,