diff options
| author | Joe Thornber <ejt@redhat.com> | 2013-05-10 14:37:19 +0100 | 
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2013-05-10 14:37:19 +0100 | 
| commit | 24347e9595704464f62a4ed8f46abf62b4c79cdd (patch) | |
| tree | d522f4239193edda8bb204d2c0b4251f2e982bbb | |
| parent | 1921c56d95c4ac92b359ad44ffbc1e9a36060b29 (diff) | |
| download | olio-linux-3.10-24347e9595704464f62a4ed8f46abf62b4c79cdd.tar.xz olio-linux-3.10-24347e9595704464f62a4ed8f46abf62b4c79cdd.zip  | |
dm thin: detect metadata device resizing
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>
| -rw-r--r-- | drivers/md/dm-thin-metadata.c | 12 | ||||
| -rw-r--r-- | drivers/md/dm-thin-metadata.h | 1 | ||||
| -rw-r--r-- | drivers/md/dm-thin.c | 54 | 
3 files changed, 64 insertions, 3 deletions
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 9452a489ed9..f553ed66603 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -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); diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 0cecc370288..ef8dd709e34 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -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 diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index ef021b0c810..f4632f97bd7 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -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,  |