Commit 7d48935e authored by Mike Snitzer's avatar Mike Snitzer

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: default avatarMike Snitzer <snitzer@redhat.com>
Acked-by: default avatarJoe Thornber <ejt@redhat.com>
parent a1989b33
...@@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd) ...@@ -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->data_mapping_root = cpu_to_le64(pmd->root);
disk_super->device_details_root = cpu_to_le64(pmd->details_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->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
disk_super->data_block_size = cpu_to_le32(pmd->data_block_size); 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 ...@@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
{ {
int r; 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_METADATA_CACHE_SIZE,
THIN_MAX_CONCURRENT_LOCKS); THIN_MAX_CONCURRENT_LOCKS);
if (IS_ERR(pmd->bm)) { if (IS_ERR(pmd->bm)) {
......
...@@ -9,16 +9,14 @@ ...@@ -9,16 +9,14 @@
#include "persistent-data/dm-block-manager.h" #include "persistent-data/dm-block-manager.h"
#include "persistent-data/dm-space-map.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. * 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. * A metadata device larger than 16GB triggers a warning.
......
...@@ -2000,16 +2000,27 @@ static void metadata_low_callback(void *context) ...@@ -2000,16 +2000,27 @@ static void metadata_low_callback(void *context)
dm_table_event(pool->ti->table); 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]; 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.", DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS); 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; return metadata_dev_size;
} }
...@@ -2018,7 +2029,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev) ...@@ -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_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; return metadata_dev_size;
} }
...@@ -2096,12 +2107,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -2096,12 +2107,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->error = "Error opening metadata block device"; ti->error = "Error opening metadata block device";
goto out_unlock; goto out_unlock;
} }
warn_if_metadata_device_too_big(metadata_dev->bdev);
/*
* Run for the side-effect of possibly issuing a warning if the
* device is too big.
*/
(void) get_metadata_dev_size(metadata_dev->bdev);
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev); r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
if (r) { if (r) {
...@@ -2288,6 +2294,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) ...@@ -2288,6 +2294,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
return -EINVAL; return -EINVAL;
} else if (metadata_dev_size > sb_metadata_dev_size) { } 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", DMINFO("%s: growing the metadata device from %llu to %llu blocks",
dm_device_name(pool->pool_md), dm_device_name(pool->pool_md),
sb_metadata_dev_size, metadata_dev_size); sb_metadata_dev_size, metadata_dev_size);
......
...@@ -680,6 +680,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm, ...@@ -680,6 +680,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
if (r) if (r)
return 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); r = sm_ll_extend(&smm->ll, nr_blocks);
if (r) if (r)
return r; return r;
......
...@@ -9,6 +9,17 @@ ...@@ -9,6 +9,17 @@
#include "dm-transaction-manager.h" #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 * Unfortunately we have to use two-phase construction due to the cycle
* between the tm and sm. * between the tm and sm.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment