forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									1921c56d95
								
							
						
					
					
						commit
						24347e9595
					
				
					 3 changed files with 64 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue