mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-02 01:18:26 +03:00
vgmerge: Fix intermediate metadata corruption
vgmerge suffers from a similar problem to the one fixed in commit
8146548d25
("vgsplit: Fix intermediate
metadata corruption.")
When merging, splitting or renaming VGs, use a new PV status flag
PV_MOVED_VG to mark the PVs that hold metadata with the old VG name and
use this to provide PV-level granularity instead of incorrectly assuming
all PVs in the VG are the same.
This commit is contained in:
parent
a781b1c178
commit
486ed10848
@ -1,7 +1,8 @@
|
|||||||
Version 2.02.175 -
|
Version 2.02.175 -
|
||||||
======================================
|
======================================
|
||||||
Use --help with blockdev when checking for --getsize64 support in fsadm.
|
Use --help with blockdev when checking for --getsize64 support in fsadm.
|
||||||
Fix metadata corruption in vgsplit intermediate state.
|
Fix metadata corruption in vgsplit and vgmerge intermediate states.
|
||||||
|
Add PV_MOVED_VG PV status flag to mark PVs moving between VGs.
|
||||||
Require LV name with pvmove in a shared VG.
|
Require LV name with pvmove in a shared VG.
|
||||||
Allow shared active mirror LVs with lvmlockd, dlm, and cmirrord.
|
Allow shared active mirror LVs with lvmlockd, dlm, and cmirrord.
|
||||||
Support lvconvert --repair with cache and cachepool volumes.
|
Support lvconvert --repair with cache and cachepool volumes.
|
||||||
|
@ -48,6 +48,7 @@ static const struct flag _pv_flags[] = {
|
|||||||
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
||||||
{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
|
{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
|
||||||
{MISSING_PV, "MISSING", STATUS_FLAG},
|
{MISSING_PV, "MISSING", STATUS_FLAG},
|
||||||
|
{PV_MOVED_VG, NULL, 0},
|
||||||
{UNLABELLED_PV, NULL, 0},
|
{UNLABELLED_PV, NULL, 0},
|
||||||
{0, NULL, 0}
|
{0, NULL, 0}
|
||||||
};
|
};
|
||||||
|
@ -612,11 +612,14 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
uint64_t new_wrap = 0, old_wrap = 0, new_end;
|
uint64_t new_wrap = 0, old_wrap = 0, new_end;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
int noprecommit = 0;
|
int noprecommit = 0;
|
||||||
|
const char *old_vg_name = NULL;
|
||||||
|
|
||||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||||
if (pvl->pv->dev == mdac->area.dev) {
|
if (pvl->pv->dev == mdac->area.dev) {
|
||||||
found = 1;
|
found = 1;
|
||||||
|
if (pvl->pv->status & PV_MOVED_VG)
|
||||||
|
old_vg_name = vg->old_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,8 +633,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
|||||||
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area)))
|
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
rlocn = _find_vg_rlocn(&mdac->area, mdah,
|
rlocn = _find_vg_rlocn(&mdac->area, mdah, old_vg_name ? : vg->name, &noprecommit);
|
||||||
vg->old_name ? vg->old_name : vg->name, &noprecommit);
|
|
||||||
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
||||||
|
|
||||||
if (!fidtc->raw_metadata_buf &&
|
if (!fidtc->raw_metadata_buf &&
|
||||||
@ -719,11 +721,14 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
int noprecommit = 0;
|
int noprecommit = 0;
|
||||||
|
const char *old_vg_name = NULL;
|
||||||
|
|
||||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||||
if (pvl->pv->dev == mdac->area.dev) {
|
if (pvl->pv->dev == mdac->area.dev) {
|
||||||
found = 1;
|
found = 1;
|
||||||
|
if (pvl->pv->status & PV_MOVED_VG)
|
||||||
|
old_vg_name = vg->old_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,9 +739,7 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
|||||||
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area)))
|
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah,
|
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, old_vg_name ? : vg->name, &noprecommit))) {
|
||||||
vg->old_name ? vg->old_name : vg->name,
|
|
||||||
&noprecommit))) {
|
|
||||||
mdah->raw_locns[0].offset = 0;
|
mdah->raw_locns[0].offset = 0;
|
||||||
mdah->raw_locns[0].size = 0;
|
mdah->raw_locns[0].size = 0;
|
||||||
mdah->raw_locns[0].checksum = 0;
|
mdah->raw_locns[0].checksum = 0;
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
#define CONVERTING UINT64_C(0x0000000000400000) /* LV */
|
#define CONVERTING UINT64_C(0x0000000000400000) /* LV */
|
||||||
|
|
||||||
#define MISSING_PV UINT64_C(0x0000000000800000) /* PV */
|
#define MISSING_PV UINT64_C(0x0000000000800000) /* PV */
|
||||||
|
#define PV_MOVED_VG UINT64_C(0x4000000000000000) /* PV - Moved to a new VG */
|
||||||
#define PARTIAL_LV UINT64_C(0x0000000001000000) /* LV - derived flag, not
|
#define PARTIAL_LV UINT64_C(0x0000000001000000) /* LV - derived flag, not
|
||||||
written out in metadata*/
|
written out in metadata*/
|
||||||
|
|
||||||
@ -146,7 +147,7 @@
|
|||||||
#define LV_RESHAPE UINT64_C(0x1000000000000000) /* Ongoing reshape (number of stripes, stripesize or raid algorithm change):
|
#define LV_RESHAPE UINT64_C(0x1000000000000000) /* Ongoing reshape (number of stripes, stripesize or raid algorithm change):
|
||||||
used as SEGTYPE_FLAG to prevent activation on old runtime */
|
used as SEGTYPE_FLAG to prevent activation on old runtime */
|
||||||
#define LV_RESHAPE_DATA_OFFSET UINT64_C(0x2000000000000000) /* LV reshape flag data offset (out of place reshaping) */
|
#define LV_RESHAPE_DATA_OFFSET UINT64_C(0x2000000000000000) /* LV reshape flag data offset (out of place reshaping) */
|
||||||
/* Next unused flag: UINT64_C(0x4000000000000000) */
|
/* Next unused flag: UINT64_C(0x8000000000000000) */
|
||||||
|
|
||||||
/* Format features flags */
|
/* Format features flags */
|
||||||
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
|
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
|
||||||
|
@ -520,6 +520,8 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
pv_dev_name(pvl->pv));
|
pv_dev_name(pvl->pv));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Mark the PVs that still hold metadata with the old VG name */
|
||||||
|
pvl->pv->status |= PV_MOVED_VG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -3616,6 +3618,7 @@ static int _vg_commit_mdas(struct volume_group *vg)
|
|||||||
int vg_commit(struct volume_group *vg)
|
int vg_commit(struct volume_group *vg)
|
||||||
{
|
{
|
||||||
int cache_updated = 0;
|
int cache_updated = 0;
|
||||||
|
struct pv_list *pvl;
|
||||||
|
|
||||||
if (!lvmcache_vgname_is_locked(vg->name)) {
|
if (!lvmcache_vgname_is_locked(vg->name)) {
|
||||||
log_error(INTERNAL_ERROR "Attempt to write new VG metadata "
|
log_error(INTERNAL_ERROR "Attempt to write new VG metadata "
|
||||||
@ -3631,11 +3634,14 @@ int vg_commit(struct volume_group *vg)
|
|||||||
/* Instruct remote nodes to upgrade cached metadata. */
|
/* Instruct remote nodes to upgrade cached metadata. */
|
||||||
if (!remote_commit_cached_metadata(vg))
|
if (!remote_commit_cached_metadata(vg))
|
||||||
stack; // FIXME: What should we do?
|
stack; // FIXME: What should we do?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to clear old_name after a successful commit.
|
* We need to clear old_name after a successful commit.
|
||||||
* The volume_group structure could be reused later.
|
* The volume_group structure could be reused later.
|
||||||
*/
|
*/
|
||||||
vg->old_name = NULL;
|
vg->old_name = NULL;
|
||||||
|
dm_list_iterate_items(pvl, &vg->pvs)
|
||||||
|
pvl->pv->status &= ~PV_MOVED_VG;
|
||||||
|
|
||||||
/* This *is* the original now that it's commited. */
|
/* This *is* the original now that it's commited. */
|
||||||
release_vg(vg->vg_committed);
|
release_vg(vg->vg_committed);
|
||||||
|
@ -111,6 +111,8 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
|||||||
del_pvl_from_vgs(vg_from, pvl);
|
del_pvl_from_vgs(vg_from, pvl);
|
||||||
add_pvl_to_vgs(vg_to, pvl);
|
add_pvl_to_vgs(vg_to, pvl);
|
||||||
pvl->pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
|
pvl->pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
|
||||||
|
/* Mark the VGs that still hold metadata for the old VG */
|
||||||
|
pvl->pv->status |= PV_MOVED_VG;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix up LVIDs */
|
/* Fix up LVIDs */
|
||||||
@ -168,6 +170,9 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
|||||||
vg_to->extent_count += vg_from->extent_count;
|
vg_to->extent_count += vg_from->extent_count;
|
||||||
vg_to->free_count += vg_from->free_count;
|
vg_to->free_count += vg_from->free_count;
|
||||||
|
|
||||||
|
/* Flag up that some PVs have moved from another VG */
|
||||||
|
vg_to->old_name = vg_from->name;
|
||||||
|
|
||||||
/* store it on disks */
|
/* store it on disks */
|
||||||
log_verbose("Writing out updated volume group");
|
log_verbose("Writing out updated volume group");
|
||||||
if (!vg_write(vg_to) || !vg_commit(vg_to))
|
if (!vg_write(vg_to) || !vg_commit(vg_to))
|
||||||
|
Loading…
Reference in New Issue
Block a user