diff options
| author | Mike Snitzer <snitzer@redhat.com> | 2014-02-12 23:58:15 -0500 | 
|---|---|---|
| committer | Mike Snitzer <snitzer@redhat.com> | 2014-02-27 11:49:08 -0500 | 
| commit | 7d48935eff401bb7970e73e822871a10e3643df1 (patch) | |
| tree | cc7523512553a162b66e37d022da2c2e8acfee22 | |
| parent | a1989b330093578ea5470bea0a00f940c444c466 (diff) | |
dm thin: allow metadata space larger than supported to go unused
It was always intended that a user could provide a thin metadata device
that is larger than the max supported by the on-disk format.  The extra
space would just go unused.
Unfortunately that never worked.  If the user attempted to use a larger
metadata device on creation they would get an error like the following:
 device-mapper: space map common: space map too large
 device-mapper: transaction manager: couldn't create metadata space map
 device-mapper: thin metadata: tm_create_with_sm failed
 device-mapper: table: 252:17: thin-pool: Error creating metadata object
 device-mapper: ioctl: error adding target to table
Fix this by allowing the initial metadata space map creation to cap its
size at the max number of blocks supported (DM_SM_METADATA_MAX_BLOCKS).
get_metadata_dev_size() must also impose DM_SM_METADATA_MAX_BLOCKS (via
THIN_METADATA_MAX_SECTORS), otherwise extending metadata would cap at
THIN_METADATA_MAX_SECTORS_WARNING (which is larger than supported).
Also, the calculation for THIN_METADATA_MAX_SECTORS didn't account for
the sizeof the disk_bitmap_header.  So the supported maximum metadata
size is a bit smaller (reduced from 33423360 to 33292800 sectors).
Lastly, remove the "excess space will not be used" warning message from
get_metadata_dev_size(); it resulted in printing the warning multiple
times.  Factor out warn_if_metadata_device_too_big(), call it from
pool_ctr() and maybe_resize_metadata_dev().
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Joe Thornber <ejt@redhat.com>
| -rw-r--r-- | drivers/md/dm-thin-metadata.c | 4 | ||||
| -rw-r--r-- | drivers/md/dm-thin-metadata.h | 8 | ||||
| -rw-r--r-- | drivers/md/dm-thin.c | 31 | ||||
| -rw-r--r-- | drivers/md/persistent-data/dm-space-map-metadata.c | 2 | ||||
| -rw-r--r-- | drivers/md/persistent-data/dm-space-map-metadata.h | 11 | 
5 files changed, 37 insertions, 19 deletions
| diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 3bb4506582a9..baa87ff12816 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)  	disk_super->data_mapping_root = cpu_to_le64(pmd->root);  	disk_super->device_details_root = cpu_to_le64(pmd->details_root); -	disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); +	disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);  	disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);  	disk_super->data_block_size = cpu_to_le32(pmd->data_block_size); @@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f  {  	int r; -	pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE, +	pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,  					  THIN_METADATA_CACHE_SIZE,  					  THIN_MAX_CONCURRENT_LOCKS);  	if (IS_ERR(pmd->bm)) { diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index dd6088a17a65..82ea384d36ff 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -9,16 +9,14 @@  #include "persistent-data/dm-block-manager.h"  #include "persistent-data/dm-space-map.h" +#include "persistent-data/dm-space-map-metadata.h" -#define THIN_METADATA_BLOCK_SIZE 4096 +#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE  /*   * The metadata device is currently limited in size. - * - * We have one block of index, which can hold 255 index entries.  Each - * index entry contains allocation info about 16k metadata blocks.   */ -#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT))) +#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS  /*   * A metadata device larger than 16GB triggers a warning. diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 4cf4b198cb60..7e84baccf0ad 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2000,16 +2000,27 @@ static void metadata_low_callback(void *context)  	dm_table_event(pool->ti->table);  } -static sector_t get_metadata_dev_size(struct block_device *bdev) +static sector_t get_dev_size(struct block_device *bdev) +{ +	return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; +} + +static void warn_if_metadata_device_too_big(struct block_device *bdev)  { -	sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; +	sector_t metadata_dev_size = get_dev_size(bdev);  	char buffer[BDEVNAME_SIZE]; -	if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) { +	if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)  		DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",  		       bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS); -		metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING; -	} +} + +static sector_t get_metadata_dev_size(struct block_device *bdev) +{ +	sector_t metadata_dev_size = get_dev_size(bdev); + +	if (metadata_dev_size > THIN_METADATA_MAX_SECTORS) +		metadata_dev_size = THIN_METADATA_MAX_SECTORS;  	return metadata_dev_size;  } @@ -2018,7 +2029,7 @@ 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); +	sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE);  	return metadata_dev_size;  } @@ -2096,12 +2107,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)  		ti->error = "Error opening metadata block device";  		goto out_unlock;  	} - -	/* -	 * Run for the side-effect of possibly issuing a warning if the -	 * device is too big. -	 */ -	(void) get_metadata_dev_size(metadata_dev->bdev); +	warn_if_metadata_device_too_big(metadata_dev->bdev);  	r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);  	if (r) { @@ -2288,6 +2294,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)  		return -EINVAL;  	} else if (metadata_dev_size > sb_metadata_dev_size) { +		warn_if_metadata_device_too_big(pool->md_dev);  		DMINFO("%s: growing the metadata device from %llu to %llu blocks",  		       dm_device_name(pool->pool_md),  		       sb_metadata_dev_size, metadata_dev_size); diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 536782e3bcb7..e9bdd462f4f5 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -680,6 +680,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,  	if (r)  		return r; +	if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) +		nr_blocks = DM_SM_METADATA_MAX_BLOCKS;  	r = sm_ll_extend(&smm->ll, nr_blocks);  	if (r)  		return r; diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h index 39bba0801cf2..64df923974d8 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.h +++ b/drivers/md/persistent-data/dm-space-map-metadata.h @@ -9,6 +9,17 @@  #include "dm-transaction-manager.h" +#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT) + +/* + * The metadata device is currently limited in size. + * + * We have one block of index, which can hold 255 index entries.  Each + * index entry contains allocation info about ~16k metadata blocks. + */ +#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64)) +#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE) +  /*   * Unfortunately we have to use two-phase construction due to the cycle   * between the tm and sm. | 
