1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-30 01:47:56 +03:00

vgck --updatemetadata is a new command

uses vg_write to correct more common or less severe issues,
and also adds the ability to repair some metadata corruption
that couldn't be handled previously.
This commit is contained in:
David Teigland 2019-02-06 13:39:41 -06:00
parent de3d3b11f4
commit 47effdc025
8 changed files with 152 additions and 1 deletions

View File

@ -341,6 +341,9 @@ static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
goto fail;
}
if (mda)
mda->header_start = mdah->start;
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
if (mda_is_ignored(mda)) {

View File

@ -1381,4 +1381,6 @@ int lv_on_pmem(struct logical_volume *lv);
int vg_is_foreign(struct volume_group *vg);
void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
#endif

View File

@ -5597,3 +5597,86 @@ int vg_is_foreign(struct volume_group *vg)
return _is_foreign_vg(vg);
}
void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg)
{
struct dm_list bad_mda_list;
struct mda_list *mdal;
struct metadata_area *mda;
struct device *dev;
dm_list_init(&bad_mda_list);
lvmcache_get_bad_mdas(cmd, vg->name, (const char *)&vg->id, &bad_mda_list);
dm_list_iterate_items(mdal, &bad_mda_list) {
mda = mdal->mda;
dev = mda_get_device(mda);
/*
* bad_fields:
*
* 0: shouldn't happen
*
* READ|INTERNAL: there's probably nothing wrong on disk
*
* MAGIC|START: there's a good chance that we were
* reading the mda_header from the wrong location; maybe
* the pv_header location was wrong. We don't want to
* write new metadata to the wrong location. To handle
* this we would want to do some further verification that
* we have the mda location correct.
*
* VERSION|CHECKSUM: when the others are correct these
* look safe to repair.
*
* HEADER: general error related to header, covered by fields
* above.
*
* TEXT: general error related to text metadata, we can repair.
*/
if (!mda->bad_fields ||
(mda->bad_fields & BAD_MDA_READ) ||
(mda->bad_fields & BAD_MDA_INTERNAL) ||
(mda->bad_fields & BAD_MDA_MAGIC) ||
(mda->bad_fields & BAD_MDA_START)) {
log_warn("WARNING: not repairing bad metadata (0x%x) for mda%d on %s",
mda->bad_fields, mda->mda_num, dev_name(dev));
continue;
}
/*
* vg_write/vg_commit reread the mda_header which checks the
* mda header fields and fails if any are bad, which stops
* vg_write/vg_commit from continuing. Suppress these header
* field checks when we know the field is bad and we are going
* to replace it. FIXME: do vg_write/vg_commit really need to
* reread and recheck the mda_header again (probably not)?
*/
if (mda->bad_fields & BAD_MDA_CHECKSUM)
mda->ignore_bad_fields |= BAD_MDA_CHECKSUM;
if (mda->bad_fields & BAD_MDA_VERSION)
mda->ignore_bad_fields |= BAD_MDA_VERSION;
log_warn("WARNING: repairing bad metadata (0x%x) in mda%d at %llu on %s.",
mda->bad_fields, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
if (!mda->ops->vg_write(vg->fid, vg, mda)) {
log_warn("WARNING: failed to write VG %s metadata to bad mda%d at %llu on %s.",
vg->name, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
continue;
}
if (!mda->ops->vg_precommit(vg->fid, vg, mda)) {
log_warn("WARNING: failed to precommit VG %s metadata to bad mda%d at %llu on %s.",
vg->name, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
continue;
}
if (!mda->ops->vg_commit(vg->fid, vg, mda)) {
log_warn("WARNING: failed to commit VG %s metadata to bad mda%d at %llu on %s.",
vg->name, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
continue;
}
}
}

View File

@ -185,6 +185,7 @@ struct metadata_area {
struct metadata_area_ops *ops;
void *metadata_locn;
uint32_t status;
uint64_t header_start; /* mda_header.start */
int mda_num;
uint32_t bad_fields; /* BAD_MDA_ flags are set to indicate errors found when reading */
uint32_t ignore_bad_fields; /* BAD_MDA_ flags are set to indicate errors to ignore */

View File

@ -1393,6 +1393,9 @@ arg(thin_ARG, 'T', "thin", 0, 0, 0,
"See --type thin, --type thin-pool, and --virtualsize.\n"
"See \\fBlvmthin\\fP(7) for more information about LVM thin provisioning.\n")
arg(updatemetadata_ARG, '\0', "updatemetadata", 0, 0, 0,
"Update VG metadata to correct problems.\n")
arg(uuid_ARG, 'u', "uuid", 0, 0, 0,
"#pvchange\n"
"Generate new random UUID for specified PVs.\n"

View File

@ -1624,6 +1624,11 @@ vgck
OO: --reportformat ReportFmt
OP: VG|Tag ...
ID: vgck_general
DESC: Read and display information about a VG.
vgck --updatemetadata VG
ID: vgck_update_metadata
DESC: Rewrite VG metadata to correct problems.
---

View File

@ -177,7 +177,7 @@ xx(vgchange,
xx(vgck,
"Check the consistency of volume group(s)",
ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS)
ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
xx(vgconvert,
"Change volume group metadata format",

View File

@ -15,6 +15,57 @@
#include "tools.h"
/*
* TODO: we cannot yet repair corruption in label_header, pv_header/locations,
* or corruption of some mda_header fields.
*/
static int _update_metadata_single(struct cmd_context *cmd __attribute__((unused)),
const char *vg_name,
struct volume_group *vg,
struct processing_handle *handle __attribute__((unused)))
{
/*
* Simply calling vg_write can correct or clean up various things:
* . some mda's have old versions of metdadata
* . wipe outdated PVs
* . fix pv_header used flag and version
* . strip historical lvs
* . clear missing pv flag on unused PV
*/
if (!vg_write(vg)) {
log_error("Failed to write VG.");
return 0;
}
if (!vg_commit(vg)) {
log_error("Failed to commit VG.");
return 0;
}
/*
* vg_write does not write to "bad" mdas (where "bad" is corrupt, can't
* be processed when reading). bad mdas are not kept in
* fid->metadata_areas_in_use so vg_read and vg_write ignore them, but
* they are saved in lvmcache. this gets them from lvmcache and tries
* to write this metadata to them.
*/
vg_write_commit_bad_mdas(cmd, vg);
return 1;
}
static int _update_metadata(struct cmd_context *cmd, int argc, char **argv)
{
cmd->handles_missing_pvs = 1;
cmd->wipe_outdated_pvs = 1;
cmd->handles_unknown_segments = 1;
return process_each_vg(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, 0, NULL,
&_update_metadata_single);
}
static int vgck_single(struct cmd_context *cmd __attribute__((unused)),
const char *vg_name,
struct volume_group *vg,
@ -37,6 +88,9 @@ static int vgck_single(struct cmd_context *cmd __attribute__((unused)),
int vgck(struct cmd_context *cmd, int argc, char **argv)
{
if (arg_is_set(cmd, updatemetadata_ARG))
return _update_metadata(cmd, argc, argv);
return process_each_vg(cmd, argc, argv, NULL, NULL, 0, 0, NULL,
&vgck_single);
}