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:
parent
de3d3b11f4
commit
47effdc025
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
@ -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",
|
||||
|
54
tools/vgck.c
54
tools/vgck.c
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user