mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
Change pvresize code to work with new metadata handling interface and allow
resizing a PV with two metadata areas.
This commit is contained in:
parent
17ad2b1115
commit
cb2396730a
@ -2093,6 +2093,55 @@ static int _text_pv_remove_metadata_area(const struct format_type *fmt,
|
||||
return remove_metadata_area_from_pv(pv, mda_index);
|
||||
}
|
||||
|
||||
static int _text_pv_resize(const struct format_type *fmt,
|
||||
struct physical_volume *pv,
|
||||
struct volume_group *vg,
|
||||
uint64_t size)
|
||||
{
|
||||
struct format_instance *fid = pv->fid;
|
||||
const char *pvid = (const char *) &pv->id;
|
||||
struct metadata_area *mda;
|
||||
struct mda_context *mdac;
|
||||
uint64_t size_reduction;
|
||||
uint64_t mda_size;
|
||||
unsigned mda_ignored;
|
||||
|
||||
/*
|
||||
* First, set the new size and update the cache and reset pe_count.
|
||||
* (pe_count must be reset otherwise it would be considered as
|
||||
* a limiting factor while moving the mda!)
|
||||
*/
|
||||
pv->size = size;
|
||||
pv->pe_count = 0;
|
||||
|
||||
/* If there's an mda at the end, move it to a new position. */
|
||||
if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
|
||||
(mdac = mda->metadata_locn)) {
|
||||
/* FIXME: Maybe MDA0 size would be better? */
|
||||
mda_size = mdac->area.size >> SECTOR_SHIFT;
|
||||
mda_ignored = mda_is_ignored(mda);
|
||||
|
||||
if (!_text_pv_remove_metadata_area(fmt, pv, 1) ||
|
||||
!_text_pv_add_metadata_area(fmt, pv, 1, 1, mda_size,
|
||||
mda_ignored)) {
|
||||
log_error("Failed to move metadata area with index 1 "
|
||||
"while resizing PV %s.", pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there's a VG, reduce size by counting in pe_start and metadata areas. */
|
||||
if (vg) {
|
||||
size_reduction = pv_pe_start(pv);
|
||||
if ((mda = fid_get_mda_indexed(fid, pvid, ID_LEN, 1)) &&
|
||||
(mdac = mda->metadata_locn))
|
||||
size_reduction += mdac->area.size >> SECTOR_SHIFT;
|
||||
pv->size -= size_reduction;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* NULL vgname means use only the supplied context e.g. an archive file */
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type *fmt,
|
||||
const struct format_instance_ctx *fic)
|
||||
@ -2170,6 +2219,7 @@ static struct format_handler _text_handler = {
|
||||
.pv_setup = _text_pv_setup,
|
||||
.pv_add_metadata_area = _text_pv_add_metadata_area,
|
||||
.pv_remove_metadata_area = _text_pv_remove_metadata_area,
|
||||
.pv_resize = _text_pv_resize,
|
||||
.pv_write = _text_pv_write,
|
||||
.vg_setup = _text_vg_setup,
|
||||
.lv_setup = _text_lv_setup,
|
||||
|
@ -428,7 +428,7 @@ struct physical_volume *pv_create(const struct cmd_context *cmd,
|
||||
uint64_t pvmetadatasize,
|
||||
unsigned metadataignore);
|
||||
int pv_resize(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t new_pe_count);
|
||||
uint64_t size);
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
uint64_t label_sector);
|
||||
|
||||
|
@ -292,6 +292,14 @@ struct format_handler {
|
||||
struct physical_volume *pv,
|
||||
unsigned metadata_index);
|
||||
|
||||
/*
|
||||
* Recalculate the PV size taking into account any existing metadata areas.
|
||||
*/
|
||||
int (*pv_resize) (const struct format_type *fmt,
|
||||
struct physical_volume *pv,
|
||||
struct volume_group *vg,
|
||||
uint64_t size);
|
||||
|
||||
/*
|
||||
* Write a PV structure to disk. Fails if the PV is in a VG ie
|
||||
* pv->vg_name must be a valid orphan VG name
|
||||
|
@ -357,10 +357,10 @@ int check_pv_segments(struct volume_group *vg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t new_pe_count)
|
||||
static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t old_pe_count, uint32_t new_pe_count)
|
||||
{
|
||||
struct pv_segment *peg, *pegt;
|
||||
uint32_t old_pe_count = pv->pe_count;
|
||||
|
||||
if (new_pe_count < pv->pe_alloc_count) {
|
||||
log_error("%s: cannot resize to %" PRIu32 " extents "
|
||||
@ -400,10 +400,9 @@ static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint3
|
||||
}
|
||||
|
||||
static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t new_pe_count)
|
||||
uint32_t old_pe_count, uint32_t new_pe_count)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
uint32_t old_pe_count = pv->pe_count;
|
||||
|
||||
if ((uint64_t) new_pe_count * pv->pe_size > pv->size ) {
|
||||
log_error("%s: cannot resize to %" PRIu32 " extents as there "
|
||||
@ -432,20 +431,59 @@ static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
|
||||
*/
|
||||
int pv_resize(struct physical_volume *pv,
|
||||
struct volume_group *vg,
|
||||
uint32_t new_pe_count)
|
||||
uint64_t size)
|
||||
{
|
||||
if ((new_pe_count == pv->pe_count)) {
|
||||
log_verbose("No change to size of physical volume %s.",
|
||||
pv_dev_name(pv));
|
||||
return 1;
|
||||
uint32_t old_pe_count, new_pe_count = 0;
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_error("Size must exceed minimum of %ld sectors on PV %s.",
|
||||
pv_min_size(), pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Resizing physical volume %s from %" PRIu32
|
||||
" to %" PRIu32 " extents.",
|
||||
pv_dev_name(pv), pv->pe_count, new_pe_count);
|
||||
if (size < pv_pe_start(pv)) {
|
||||
log_error("Size must exceed physical extent start "
|
||||
"of %" PRIu64 " sectors on PV %s.",
|
||||
pv_pe_start(pv), pv_dev_name(pv));
|
||||
}
|
||||
|
||||
if (new_pe_count > pv->pe_count)
|
||||
return _extend_pv(pv, vg, new_pe_count);
|
||||
else
|
||||
return _reduce_pv(pv, vg, new_pe_count);
|
||||
old_pe_count = pv->pe_count;
|
||||
|
||||
if (!pv->fmt->ops->pv_resize(pv->fmt, pv, vg, size)) {
|
||||
log_error("Format specific resize of PV %s failed.",
|
||||
pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* pv->pe_count is 0 now! We need to recalculate! */
|
||||
|
||||
/* If there's a VG, calculate new PE count value. */
|
||||
if (vg) {
|
||||
/* FIXME: Maybe PE calculation should go into pv->fmt->resize?
|
||||
(like it is for pv->fmt->setup) */
|
||||
if (!(new_pe_count = pv_size(pv) / vg->extent_size)) {
|
||||
log_error("Size must leave space for at least one physical "
|
||||
"extent of %" PRIu32 " sectors on PV %s.",
|
||||
pv_pe_size(pv), pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((new_pe_count == old_pe_count)) {
|
||||
pv->pe_count = old_pe_count;
|
||||
log_verbose("No change to size of physical volume %s.",
|
||||
pv_dev_name(pv));
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_verbose("Resizing physical volume %s from %" PRIu32
|
||||
" to %" PRIu32 " extents.",
|
||||
pv_dev_name(pv), pv->pe_count, new_pe_count);
|
||||
|
||||
if (new_pe_count > old_pe_count)
|
||||
return _extend_pv(pv, vg, old_pe_count, new_pe_count);
|
||||
else
|
||||
return _reduce_pv(pv, vg, old_pe_count, new_pe_count);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -30,12 +30,9 @@ static int _pv_resize_single(struct cmd_context *cmd,
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
uint64_t size = 0;
|
||||
uint32_t new_pe_count = 0;
|
||||
int r = 0;
|
||||
const char *pv_name = pv_dev_name(pv);
|
||||
const char *vg_name = pv_vg_name(pv);
|
||||
struct lvmcache_info *info;
|
||||
int mda_count = 0;
|
||||
struct volume_group *old_vg = vg;
|
||||
|
||||
if (is_orphan_vg(vg_name)) {
|
||||
@ -49,9 +46,6 @@ static int _pv_resize_single(struct cmd_context *cmd,
|
||||
log_error("Unable to read PV \"%s\"", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mda_count = dm_list_size(&pv->fid->metadata_areas_in_use) +
|
||||
dm_list_size(&pv->fid->metadata_areas_ignored);
|
||||
} else {
|
||||
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
|
||||
|
||||
@ -70,24 +64,10 @@ static int _pv_resize_single(struct cmd_context *cmd,
|
||||
|
||||
pv = pvl->pv;
|
||||
|
||||
if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
|
||||
log_error("Can't get info for PV %s in volume group %s",
|
||||
pv_name, vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mda_count = dm_list_size(&info->mdas);
|
||||
|
||||
if (!archive(vg))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME Create function to test compatibility properly */
|
||||
if (mda_count > 1) {
|
||||
log_error("%s: too many metadata areas for pvresize", pv_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(pv->fmt->features & FMT_RESIZE_PV)) {
|
||||
log_error("Physical volume %s format does not support resizing.",
|
||||
pv_name);
|
||||
@ -109,39 +89,12 @@ static int _pv_resize_single(struct cmd_context *cmd,
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
if (size < pv_min_size()) {
|
||||
log_error("%s: Size must exceed minimum of %" PRIu64 " sectors.",
|
||||
pv_name, pv_min_size());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < pv_pe_start(pv)) {
|
||||
log_error("%s: Size must exceed physical extent start of "
|
||||
"%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
pv->size = size;
|
||||
|
||||
if (vg) {
|
||||
pv->size -= pv_pe_start(pv);
|
||||
new_pe_count = pv_size(pv) / vg->extent_size;
|
||||
|
||||
if (!new_pe_count) {
|
||||
log_error("%s: Size must leave space for at "
|
||||
"least one physical extent of "
|
||||
"%" PRIu32 " sectors.", pv_name,
|
||||
pv_pe_size(pv));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pv_resize(pv, vg, new_pe_count))
|
||||
goto_out;
|
||||
}
|
||||
|
||||
log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
|
||||
pv_name, pv_size(pv));
|
||||
|
||||
if (!pv_resize(pv, vg, size))
|
||||
goto_out;
|
||||
|
||||
log_verbose("Updating physical volume \"%s\"", pv_name);
|
||||
if (!is_orphan_vg(vg_name)) {
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user